]> git.sur5r.net Git - openldap/blob - libraries/libldap_r/rdwr.c
Updated notices and acknowledgements
[openldap] / libraries / libldap_r / rdwr.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2003 The OpenLDAP Foundation.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted only as authorized by the OpenLDAP
9  * Public License.
10  *
11  * A copy of this license is available in file LICENSE in the
12  * top-level directory of the distribution or, alternatively, at
13  * <http://www.OpenLDAP.org/license.html>.
14  */
15
16 /*
17 ** This is an improved implementation of Reader/Writer locks does
18 ** not protect writers from starvation.  That is, if a writer is
19 ** currently waiting on a reader, any new reader will get
20 ** the lock before the writer.
21 **
22 ** Does not support cancellation nor does any status checking.
23 */
24 /* Adapted from publically available examples for:
25  *      "Programming with Posix Threads"
26  *              by David R Butenhof, Addison-Wesley 
27  *              http://cseng.aw.com/bookpage.taf?ISBN=0-201-63392-2
28  */
29
30 #include "portable.h"
31
32 #include <ac/stdlib.h>
33
34 #include <ac/errno.h>
35 #include <ac/string.h>
36 #include <ac/time.h>
37
38 #include "ldap-int.h"
39 #include "ldap_pvt_thread.h"
40
41 /*
42  * implementations that provide their own compatible 
43  * reader/writer locks define LDAP_THREAD_HAVE_RDWR
44  * in ldap_pvt_thread.h
45  */
46 #ifndef LDAP_THREAD_HAVE_RDWR
47
48 struct ldap_int_thread_rdwr_s {
49         ldap_pvt_thread_mutex_t ltrw_mutex;
50         ldap_pvt_thread_cond_t ltrw_read;       /* wait for read */
51         ldap_pvt_thread_cond_t ltrw_write;      /* wait for write */
52         int ltrw_valid;
53 #define LDAP_PVT_THREAD_RDWR_VALID 0x0bad
54         int ltrw_r_active;
55         int ltrw_w_active;
56         int ltrw_r_wait;
57         int ltrw_w_wait;
58 };
59
60 int 
61 ldap_pvt_thread_rdwr_init( ldap_pvt_thread_rdwr_t *rwlock )
62 {
63         struct ldap_int_thread_rdwr_s *rw;
64
65         assert( rwlock != NULL );
66
67         rw = (struct ldap_int_thread_rdwr_s *) LDAP_CALLOC( 1,
68                 sizeof( struct ldap_int_thread_rdwr_s ) );
69
70         /* we should check return results */
71         ldap_pvt_thread_mutex_init( &rw->ltrw_mutex );
72         ldap_pvt_thread_cond_init( &rw->ltrw_read );
73         ldap_pvt_thread_cond_init( &rw->ltrw_write );
74
75         rw->ltrw_valid = LDAP_PVT_THREAD_RDWR_VALID;
76
77         *rwlock = rw;
78         return 0;
79 }
80
81 int 
82 ldap_pvt_thread_rdwr_destroy( ldap_pvt_thread_rdwr_t *rwlock )
83 {
84         struct ldap_int_thread_rdwr_s *rw;
85
86         assert( rwlock != NULL );
87         rw = *rwlock;
88
89         assert( rw != NULL );
90         assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
91
92         if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
93                 return LDAP_PVT_THREAD_EINVAL;
94
95         ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
96
97         assert( rw->ltrw_w_active >= 0 ); 
98         assert( rw->ltrw_w_wait >= 0 ); 
99         assert( rw->ltrw_r_active >= 0 ); 
100         assert( rw->ltrw_r_wait >= 0 ); 
101
102         /* active threads? */
103         if( rw->ltrw_r_active > 0 || rw->ltrw_w_active > 0) {
104                 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
105                 return LDAP_PVT_THREAD_EBUSY;
106         }
107
108         /* waiting threads? */
109         if( rw->ltrw_r_wait > 0 || rw->ltrw_w_wait > 0) {
110                 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
111                 return LDAP_PVT_THREAD_EBUSY;
112         }
113
114         rw->ltrw_valid = 0;
115
116         ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
117
118         ldap_pvt_thread_mutex_destroy( &rw->ltrw_mutex );
119         ldap_pvt_thread_cond_destroy( &rw->ltrw_read );
120         ldap_pvt_thread_cond_destroy( &rw->ltrw_write );
121
122         LDAP_FREE(rw);
123         *rwlock = NULL;
124         return 0;
125 }
126
127 int ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rwlock )
128 {
129         struct ldap_int_thread_rdwr_s *rw;
130
131         assert( rwlock != NULL );
132         rw = *rwlock;
133
134         assert( rw != NULL );
135         assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
136
137         if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
138                 return LDAP_PVT_THREAD_EINVAL;
139
140         ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
141
142         assert( rw->ltrw_w_active >= 0 ); 
143         assert( rw->ltrw_w_wait >= 0 ); 
144         assert( rw->ltrw_r_active >= 0 ); 
145         assert( rw->ltrw_r_wait >= 0 ); 
146
147         if( rw->ltrw_w_active > 0 ) {
148                 /* writer is active */
149
150                 rw->ltrw_r_wait++;
151
152                 do {
153                         ldap_pvt_thread_cond_wait(
154                                 &rw->ltrw_read, &rw->ltrw_mutex );
155                 } while( rw->ltrw_w_active > 0 );
156
157                 rw->ltrw_r_wait--;
158                 assert( rw->ltrw_r_wait >= 0 ); 
159         }
160
161         rw->ltrw_r_active++;
162
163         ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
164
165         return 0;
166 }
167
168 int ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rwlock )
169 {
170         struct ldap_int_thread_rdwr_s *rw;
171
172         assert( rwlock != NULL );
173         rw = *rwlock;
174
175         assert( rw != NULL );
176         assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
177
178         if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
179                 return LDAP_PVT_THREAD_EINVAL;
180
181         ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
182
183         assert( rw->ltrw_w_active >= 0 ); 
184         assert( rw->ltrw_w_wait >= 0 ); 
185         assert( rw->ltrw_r_active >= 0 ); 
186         assert( rw->ltrw_r_wait >= 0 ); 
187
188         if( rw->ltrw_w_active > 0) {
189                 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
190                 return LDAP_PVT_THREAD_EBUSY;
191         }
192
193         rw->ltrw_r_active++;
194
195         ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
196
197         return 0;
198 }
199
200 int ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rwlock )
201 {
202         struct ldap_int_thread_rdwr_s *rw;
203
204         assert( rwlock != NULL );
205         rw = *rwlock;
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_r_active--;
216
217         assert( rw->ltrw_w_active >= 0 ); 
218         assert( rw->ltrw_w_wait >= 0 ); 
219         assert( rw->ltrw_r_active >= 0 ); 
220         assert( rw->ltrw_r_wait >= 0 ); 
221
222         if (rw->ltrw_r_active == 0 && rw->ltrw_w_wait > 0 ) {
223                 ldap_pvt_thread_cond_signal( &rw->ltrw_write );
224         }
225
226         ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
227
228         return 0;
229 }
230
231 int ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rwlock )
232 {
233         struct ldap_int_thread_rdwr_s *rw;
234
235         assert( rwlock != NULL );
236         rw = *rwlock;
237
238         assert( rw != NULL );
239         assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
240
241         if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
242                 return LDAP_PVT_THREAD_EINVAL;
243
244         ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
245
246         assert( rw->ltrw_w_active >= 0 ); 
247         assert( rw->ltrw_w_wait >= 0 ); 
248         assert( rw->ltrw_r_active >= 0 ); 
249         assert( rw->ltrw_r_wait >= 0 ); 
250
251         if ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 ) {
252                 rw->ltrw_w_wait++;
253
254                 do {
255                         ldap_pvt_thread_cond_wait(
256                                 &rw->ltrw_write, &rw->ltrw_mutex );
257                 } while ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 );
258
259                 rw->ltrw_w_wait--;
260                 assert( rw->ltrw_w_wait >= 0 ); 
261         }
262
263         rw->ltrw_w_active++;
264
265         ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
266
267         return 0;
268 }
269
270 int ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rwlock )
271 {
272         struct ldap_int_thread_rdwr_s *rw;
273
274         assert( rwlock != NULL );
275         rw = *rwlock;
276
277         assert( rw != NULL );
278         assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
279
280         if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
281                 return LDAP_PVT_THREAD_EINVAL;
282
283         ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
284
285         assert( rw->ltrw_w_active >= 0 ); 
286         assert( rw->ltrw_w_wait >= 0 ); 
287         assert( rw->ltrw_r_active >= 0 ); 
288         assert( rw->ltrw_r_wait >= 0 ); 
289
290         if ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 ) {
291                 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
292                 return LDAP_PVT_THREAD_EBUSY;
293         }
294
295         rw->ltrw_w_active++;
296
297         ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
298
299         return 0;
300 }
301
302 int ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rwlock )
303 {
304         struct ldap_int_thread_rdwr_s *rw;
305
306         assert( rwlock != NULL );
307         rw = *rwlock;
308
309         assert( rw != NULL );
310         assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
311
312         if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
313                 return LDAP_PVT_THREAD_EINVAL;
314
315         ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
316
317         rw->ltrw_w_active--;
318
319         assert( rw->ltrw_w_active >= 0 ); 
320         assert( rw->ltrw_w_wait >= 0 ); 
321         assert( rw->ltrw_r_active >= 0 ); 
322         assert( rw->ltrw_r_wait >= 0 ); 
323
324         if (rw->ltrw_r_wait > 0) {
325                 ldap_pvt_thread_cond_broadcast( &rw->ltrw_read );
326
327         } else if (rw->ltrw_w_wait > 0) {
328                 ldap_pvt_thread_cond_signal( &rw->ltrw_write );
329         }
330
331         ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
332
333         return 0;
334 }
335
336 #ifdef LDAP_RDWR_DEBUG
337
338 /* just for testing, 
339  * return 0 if false, suitable for assert(ldap_pvt_thread_rdwr_Xchk(rdwr))
340  * 
341  * Currently they don't check if the calling thread is the one 
342  * that has the lock, just that there is a reader or writer.
343  *
344  * Basically sufficent for testing that places that should have
345  * a lock are caught.
346  */
347
348 int ldap_pvt_thread_rdwr_readers(ldap_pvt_thread_rdwr_t *rwlock)
349 {
350         struct ldap_int_thread_rdwr_s *rw;
351
352         assert( rwlock != NULL );
353         rw = *rwlock;
354
355         assert( rw != NULL );
356         assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
357         assert( rw->ltrw_w_active >= 0 ); 
358         assert( rw->ltrw_w_wait >= 0 ); 
359         assert( rw->ltrw_r_active >= 0 ); 
360         assert( rw->ltrw_r_wait >= 0 ); 
361
362         return( rw->ltrw_r_active );
363 }
364
365 int ldap_pvt_thread_rdwr_writers(ldap_pvt_thread_rdwr_t *rwlock)
366 {
367         struct ldap_int_thread_rdwr_s *rw;
368
369         assert( rwlock != NULL );
370         rw = *rwlock;
371
372         assert( rw != NULL );
373         assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
374         assert( rw->ltrw_w_active >= 0 ); 
375         assert( rw->ltrw_w_wait >= 0 ); 
376         assert( rw->ltrw_r_active >= 0 ); 
377         assert( rw->ltrw_r_wait >= 0 ); 
378
379         return( rw->ltrw_w_active );
380 }
381
382 int ldap_pvt_thread_rdwr_active(ldap_pvt_thread_rdwr_t *rwlock)
383 {
384         struct ldap_int_thread_rdwr_s *rw;
385
386         assert( rwlock != NULL );
387         rw = *rwlock;
388
389         assert( rw != NULL );
390         assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
391         assert( rw->ltrw_w_active >= 0 ); 
392         assert( rw->ltrw_w_wait >= 0 ); 
393         assert( rw->ltrw_r_active >= 0 ); 
394         assert( rw->ltrw_r_wait >= 0 ); 
395
396         return(ldap_pvt_thread_rdwr_readers(rw) +
397                ldap_pvt_thread_rdwr_writers(rw));
398 }
399
400 #endif /* LDAP_DEBUG */
401
402 #endif /* LDAP_THREAD_HAVE_RDWR */