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