3 * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
4 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
7 ** This is an improved implementation of Reader/Writer locks does
8 ** not protect writers from starvation. That is, if a writer is
9 ** currently waiting on a reader, any new reader will get
10 ** the lock before the writer.
12 ** Does not support cancellation nor does any status checking.
14 /* Adapted from publically available examples for:
15 * "Programming with Posix Threads"
16 * by David R Butenhof, Addison-Wesley
17 * http://cseng.aw.com/bookpage.taf?ISBN=0-201-63392-2
22 #include <ac/stdlib.h>
25 #include <ac/string.h>
29 #include "ldap_pvt_thread.h"
32 * implementations that provide their own compatible
33 * reader/writer locks define LDAP_THREAD_HAVE_RDWR
34 * in ldap_pvt_thread.h
36 #ifndef LDAP_THREAD_HAVE_RDWR
38 struct ldap_int_thread_rdwr_s {
39 ldap_pvt_thread_mutex_t ltrw_mutex;
40 ldap_pvt_thread_cond_t ltrw_read; /* wait for read */
41 ldap_pvt_thread_cond_t ltrw_write; /* wait for write */
43 #define LDAP_PVT_THREAD_RDWR_VALID 0x0bad
51 ldap_pvt_thread_rdwr_init( ldap_pvt_thread_rdwr_t *rwlock )
53 struct ldap_int_thread_rdwr_s *rw;
55 assert( rwlock != NULL );
57 rw = (struct ldap_int_thread_rdwr_s *) LDAP_CALLOC( 1,
58 sizeof( struct ldap_int_thread_rdwr_s ) );
60 /* we should check return results */
61 ldap_pvt_thread_mutex_init( &rw->ltrw_mutex );
62 ldap_pvt_thread_cond_init( &rw->ltrw_read );
63 ldap_pvt_thread_cond_init( &rw->ltrw_write );
65 rw->ltrw_valid = LDAP_PVT_THREAD_RDWR_VALID;
72 ldap_pvt_thread_rdwr_destroy( ldap_pvt_thread_rdwr_t *rwlock )
74 struct ldap_int_thread_rdwr_s *rw;
76 assert( rwlock != NULL );
80 assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
82 if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
83 return LDAP_PVT_THREAD_EINVAL;
85 ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
87 assert( rw->ltrw_w_active >= 0 );
88 assert( rw->ltrw_w_wait >= 0 );
89 assert( rw->ltrw_r_active >= 0 );
90 assert( rw->ltrw_r_wait >= 0 );
93 if( rw->ltrw_r_active > 0 || rw->ltrw_w_active > 0) {
94 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
95 return LDAP_PVT_THREAD_EBUSY;
98 /* waiting threads? */
99 if( rw->ltrw_r_wait > 0 || rw->ltrw_w_wait > 0) {
100 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
101 return LDAP_PVT_THREAD_EBUSY;
106 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
108 ldap_pvt_thread_mutex_destroy( &rw->ltrw_mutex );
109 ldap_pvt_thread_cond_destroy( &rw->ltrw_read );
110 ldap_pvt_thread_cond_destroy( &rw->ltrw_write );
117 int ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rwlock )
119 struct ldap_int_thread_rdwr_s *rw;
121 assert( rwlock != NULL );
124 assert( rw != NULL );
125 assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
127 if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
128 return LDAP_PVT_THREAD_EINVAL;
130 ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
132 assert( rw->ltrw_w_active >= 0 );
133 assert( rw->ltrw_w_wait >= 0 );
134 assert( rw->ltrw_r_active >= 0 );
135 assert( rw->ltrw_r_wait >= 0 );
137 if( rw->ltrw_w_active > 0 ) {
138 /* writer is active */
143 ldap_pvt_thread_cond_wait(
144 &rw->ltrw_read, &rw->ltrw_mutex );
145 } while( rw->ltrw_w_active > 0 );
148 assert( rw->ltrw_r_wait >= 0 );
153 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
158 int ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rwlock )
160 struct ldap_int_thread_rdwr_s *rw;
162 assert( rwlock != NULL );
165 assert( rw != NULL );
166 assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
168 if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
169 return LDAP_PVT_THREAD_EINVAL;
171 ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
173 assert( rw->ltrw_w_active >= 0 );
174 assert( rw->ltrw_w_wait >= 0 );
175 assert( rw->ltrw_r_active >= 0 );
176 assert( rw->ltrw_r_wait >= 0 );
178 if( rw->ltrw_w_active > 0) {
179 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
180 return LDAP_PVT_THREAD_EBUSY;
185 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
190 int ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rwlock )
192 struct ldap_int_thread_rdwr_s *rw;
194 assert( rwlock != NULL );
197 assert( rw != NULL );
198 assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
200 if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
201 return LDAP_PVT_THREAD_EINVAL;
203 ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
207 assert( rw->ltrw_w_active >= 0 );
208 assert( rw->ltrw_w_wait >= 0 );
209 assert( rw->ltrw_r_active >= 0 );
210 assert( rw->ltrw_r_wait >= 0 );
212 if (rw->ltrw_r_active == 0 && rw->ltrw_w_wait > 0 ) {
213 ldap_pvt_thread_cond_signal( &rw->ltrw_write );
216 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
221 int ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rwlock )
223 struct ldap_int_thread_rdwr_s *rw;
225 assert( rwlock != NULL );
228 assert( rw != NULL );
229 assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
231 if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
232 return LDAP_PVT_THREAD_EINVAL;
234 ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
236 assert( rw->ltrw_w_active >= 0 );
237 assert( rw->ltrw_w_wait >= 0 );
238 assert( rw->ltrw_r_active >= 0 );
239 assert( rw->ltrw_r_wait >= 0 );
241 if ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 ) {
245 ldap_pvt_thread_cond_wait(
246 &rw->ltrw_write, &rw->ltrw_mutex );
247 } while ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 );
250 assert( rw->ltrw_w_wait >= 0 );
255 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
260 int ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rwlock )
262 struct ldap_int_thread_rdwr_s *rw;
264 assert( rwlock != NULL );
267 assert( rw != NULL );
268 assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
270 if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
271 return LDAP_PVT_THREAD_EINVAL;
273 ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
275 assert( rw->ltrw_w_active >= 0 );
276 assert( rw->ltrw_w_wait >= 0 );
277 assert( rw->ltrw_r_active >= 0 );
278 assert( rw->ltrw_r_wait >= 0 );
280 if ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 ) {
281 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
282 return LDAP_PVT_THREAD_EBUSY;
287 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
292 int ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rwlock )
294 struct ldap_int_thread_rdwr_s *rw;
296 assert( rwlock != NULL );
299 assert( rw != NULL );
300 assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
302 if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
303 return LDAP_PVT_THREAD_EINVAL;
305 ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
309 assert( rw->ltrw_w_active >= 0 );
310 assert( rw->ltrw_w_wait >= 0 );
311 assert( rw->ltrw_r_active >= 0 );
312 assert( rw->ltrw_r_wait >= 0 );
314 if (rw->ltrw_r_wait > 0) {
315 ldap_pvt_thread_cond_broadcast( &rw->ltrw_read );
317 } else if (rw->ltrw_w_wait > 0) {
318 ldap_pvt_thread_cond_signal( &rw->ltrw_write );
321 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
326 #ifdef LDAP_RDWR_DEBUG
329 * return 0 if false, suitable for assert(ldap_pvt_thread_rdwr_Xchk(rdwr))
331 * Currently they don't check if the calling thread is the one
332 * that has the lock, just that there is a reader or writer.
334 * Basically sufficent for testing that places that should have
338 int ldap_pvt_thread_rdwr_readers(ldap_pvt_thread_rdwr_t *rwlock)
340 struct ldap_int_thread_rdwr_s *rw;
342 assert( rwlock != NULL );
345 assert( rw != NULL );
346 assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
347 assert( rw->ltrw_w_active >= 0 );
348 assert( rw->ltrw_w_wait >= 0 );
349 assert( rw->ltrw_r_active >= 0 );
350 assert( rw->ltrw_r_wait >= 0 );
352 return( rw->ltrw_r_active );
355 int ldap_pvt_thread_rdwr_writers(ldap_pvt_thread_rdwr_t *rwlock)
357 struct ldap_int_thread_rdwr_s *rw;
359 assert( rwlock != NULL );
362 assert( rw != NULL );
363 assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
364 assert( rw->ltrw_w_active >= 0 );
365 assert( rw->ltrw_w_wait >= 0 );
366 assert( rw->ltrw_r_active >= 0 );
367 assert( rw->ltrw_r_wait >= 0 );
369 return( rw->ltrw_w_active );
372 int ldap_pvt_thread_rdwr_active(ldap_pvt_thread_rdwr_t *rwlock)
374 struct ldap_int_thread_rdwr_s *rw;
376 assert( rwlock != NULL );
379 assert( rw != NULL );
380 assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
381 assert( rw->ltrw_w_active >= 0 );
382 assert( rw->ltrw_w_wait >= 0 );
383 assert( rw->ltrw_r_active >= 0 );
384 assert( rw->ltrw_r_wait >= 0 );
386 return(ldap_pvt_thread_rdwr_readers(rw) +
387 ldap_pvt_thread_rdwr_writers(rw));
390 #endif /* LDAP_DEBUG */
392 #endif /* LDAP_THREAD_HAVE_RDWR */