]> git.sur5r.net Git - openldap/blob - libraries/libldap_r/rdwr.c
Fixed typo in
[openldap] / libraries / libldap_r / rdwr.c
1 /*
2 ** This is an improved implementation of Reader/Writer locks does
3 ** not protect writers from starvation.  That is, if a writer is
4 ** currently waiting on a reader, any new reader will get
5 ** the lock before the writer.
6 **
7 ** Does not support cancellation nor does any status checking.
8 */
9
10 /********************************************************
11  * Adapted from:
12  *      "Programming with Posix Threads"
13  *              by David R Butenhof
14  *              Addison-Wesley 
15  ********************************************************
16  */
17
18 #include "portable.h"
19
20 #include <stdlib.h>
21
22 #include <ac/errno.h>
23 #include <ac/string.h>
24
25 #include "ldap_pvt_thread.h"
26
27 int 
28 ldap_pvt_thread_rdwr_init( ldap_pvt_thread_rdwr_t *rw )
29 {
30         memset( rw, 0, sizeof(ldap_pvt_thread_rdwr_t) );
31
32         /* we should check return results */
33         ldap_pvt_thread_mutex_init( &rw->ltrw_mutex );
34         ldap_pvt_thread_cond_init( &rw->ltrw_read );
35         ldap_pvt_thread_cond_init( &rw->ltrw_write );
36
37         rw->ltrw_valid = LDAP_PVT_THREAD_RDWR_VALUE;
38         return 0;
39 }
40
41 int 
42 ldap_pvt_thread_rdwr_destroy( ldap_pvt_thread_rdwr_t *rw )
43 {
44         if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALUE )
45                 return LDAP_PVT_THREAD_EINVAL;
46
47         ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
48
49         /* active threads? */
50         if( rw->ltrw_r_active > 0 || rw->ltrw_w_active > 1) {
51                 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
52                 return LDAP_PVT_THREAD_EBUSY;
53         }
54
55         /* waiting threads? */
56         if( rw->ltrw_r_wait > 0 || rw->ltrw_w_wait > 0) {
57                 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
58                 return LDAP_PVT_THREAD_EBUSY;
59         }
60
61         rw->ltrw_valid = 0;
62
63         ldap_pvt_thread_mutex_destroy( &rw->ltrw_mutex );
64         ldap_pvt_thread_cond_destroy( &rw->ltrw_read );
65         ldap_pvt_thread_cond_destroy( &rw->ltrw_write );
66
67         return 0;
68 }
69
70 int ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rw )
71 {
72         if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALUE )
73                 return LDAP_PVT_THREAD_EINVAL;
74
75         ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
76
77         if( rw->ltrw_w_active > 1 ) {
78                 /* writer is active */
79
80                 rw->ltrw_r_wait++;
81
82                 do {
83                         ldap_pvt_thread_cond_wait(
84                                 &rw->ltrw_read, &rw->ltrw_mutex );
85                 } while( rw->ltrw_w_active > 1 );
86
87                 rw->ltrw_r_wait--;
88         }
89
90         rw->ltrw_r_active++;
91
92         ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
93
94         return 0;
95 }
96
97 int ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rw )
98 {
99         if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALUE )
100                 return LDAP_PVT_THREAD_EINVAL;
101
102         ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
103
104         if( rw->ltrw_w_active > 1) {
105                 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
106                 return LDAP_PVT_THREAD_EBUSY;
107         }
108
109         rw->ltrw_r_active++;
110
111         ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
112
113         return 0;
114 }
115
116 int ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rw )
117 {
118         if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALUE )
119                 return LDAP_PVT_THREAD_EINVAL;
120
121         ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
122
123         rw->ltrw_r_active--;
124
125         if (rw->ltrw_r_active == 0 && rw->ltrw_w_wait > 0 ) {
126                 ldap_pvt_thread_cond_signal( &rw->ltrw_write );
127         }
128
129         ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
130
131         return 0;
132 }
133
134 int ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rw )
135 {
136         if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALUE )
137                 return LDAP_PVT_THREAD_EINVAL;
138
139         ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
140
141         if ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 ) {
142                 rw->ltrw_w_wait++;
143
144                 do {
145                         ldap_pvt_thread_cond_wait(
146                                 &rw->ltrw_write, &rw->ltrw_mutex );
147                 } while ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 );
148
149                 rw->ltrw_w_wait--;
150         }
151
152         rw->ltrw_w_active++;
153
154         ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
155
156         return 0;
157 }
158
159 int ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rw )
160 {
161         if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALUE )
162                 return LDAP_PVT_THREAD_EINVAL;
163
164         ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
165
166         if ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 ) {
167                 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
168                 return LDAP_PVT_THREAD_EBUSY;
169         }
170
171         rw->ltrw_w_active++;
172
173         ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
174
175         return 0;
176 }
177
178 int ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rw )
179 {
180         if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALUE )
181                 return LDAP_PVT_THREAD_EINVAL;
182
183         ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
184
185         rw->ltrw_w_active--;
186
187         if (rw->ltrw_r_wait > 0) {
188                 ldap_pvt_thread_cond_broadcast( &rw->ltrw_read );
189
190         } else if (rw->ltrw_w_wait > 0) {
191                 ldap_pvt_thread_cond_signal( &rw->ltrw_write );
192         }
193
194         ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
195
196         return 0;
197 }
198
199 #ifdef LDAP_DEBUG
200
201 /* just for testing, 
202  * return 0 if false, suitable for assert(ldap_pvt_thread_rdwr_Xchk(rdwr))
203  * 
204  * Currently they don't check if the calling thread is the one 
205  * that has the lock, just that there is a reader or writer.
206  *
207  * Basically sufficent for testing that places that should have
208  * a lock are caught.
209  */
210
211 int ldap_pvt_thread_rdwr_readers(ldap_pvt_thread_rdwr_t *rw)
212 {
213         return( rw->ltrw_r_active );
214 }
215
216 int ldap_pvt_thread_rdwr_writers(ldap_pvt_thread_rdwr_t *rw)
217 {
218         return( rw->ltrw_w_active );
219 }
220
221 int ldap_pvt_thread_rdwr_active(ldap_pvt_thread_rdwr_t *rw)
222 {
223         return(ldap_pvt_thread_rdwr_readers(rw) +
224                ldap_pvt_thread_rdwr_writers(rw));
225 }
226
227 #endif /* LDAP_DEBUG */