2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1998-2003 The OpenLDAP Foundation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
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>.
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.
22 ** Does not support cancellation nor does any status checking.
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
32 #include <ac/stdlib.h>
35 #include <ac/string.h>
39 #include "ldap_pvt_thread.h"
42 * implementations that provide their own compatible
43 * reader/writer locks define LDAP_THREAD_HAVE_RDWR
44 * in ldap_pvt_thread.h
46 #ifndef LDAP_THREAD_HAVE_RDWR
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 */
53 #define LDAP_PVT_THREAD_RDWR_VALID 0x0bad
61 ldap_pvt_thread_rdwr_init( ldap_pvt_thread_rdwr_t *rwlock )
63 struct ldap_int_thread_rdwr_s *rw;
65 assert( rwlock != NULL );
67 rw = (struct ldap_int_thread_rdwr_s *) LDAP_CALLOC( 1,
68 sizeof( struct ldap_int_thread_rdwr_s ) );
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 );
75 rw->ltrw_valid = LDAP_PVT_THREAD_RDWR_VALID;
82 ldap_pvt_thread_rdwr_destroy( ldap_pvt_thread_rdwr_t *rwlock )
84 struct ldap_int_thread_rdwr_s *rw;
86 assert( rwlock != NULL );
90 assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
92 if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
93 return LDAP_PVT_THREAD_EINVAL;
95 ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
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 );
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;
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;
116 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
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 );
127 int ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rwlock )
129 struct ldap_int_thread_rdwr_s *rw;
131 assert( rwlock != NULL );
134 assert( rw != NULL );
135 assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
137 if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
138 return LDAP_PVT_THREAD_EINVAL;
140 ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
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 );
147 if( rw->ltrw_w_active > 0 ) {
148 /* writer is active */
153 ldap_pvt_thread_cond_wait(
154 &rw->ltrw_read, &rw->ltrw_mutex );
155 } while( rw->ltrw_w_active > 0 );
158 assert( rw->ltrw_r_wait >= 0 );
163 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
168 int ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rwlock )
170 struct ldap_int_thread_rdwr_s *rw;
172 assert( rwlock != NULL );
175 assert( rw != NULL );
176 assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
178 if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
179 return LDAP_PVT_THREAD_EINVAL;
181 ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
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 );
188 if( rw->ltrw_w_active > 0) {
189 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
190 return LDAP_PVT_THREAD_EBUSY;
195 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
200 int ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rwlock )
202 struct ldap_int_thread_rdwr_s *rw;
204 assert( rwlock != NULL );
207 assert( rw != NULL );
208 assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
210 if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
211 return LDAP_PVT_THREAD_EINVAL;
213 ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
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 );
222 if (rw->ltrw_r_active == 0 && rw->ltrw_w_wait > 0 ) {
223 ldap_pvt_thread_cond_signal( &rw->ltrw_write );
226 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
231 int ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rwlock )
233 struct ldap_int_thread_rdwr_s *rw;
235 assert( rwlock != NULL );
238 assert( rw != NULL );
239 assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
241 if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
242 return LDAP_PVT_THREAD_EINVAL;
244 ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
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 );
251 if ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 ) {
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 );
260 assert( rw->ltrw_w_wait >= 0 );
265 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
270 int ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rwlock )
272 struct ldap_int_thread_rdwr_s *rw;
274 assert( rwlock != NULL );
277 assert( rw != NULL );
278 assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
280 if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
281 return LDAP_PVT_THREAD_EINVAL;
283 ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
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 );
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;
297 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
302 int ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rwlock )
304 struct ldap_int_thread_rdwr_s *rw;
306 assert( rwlock != NULL );
309 assert( rw != NULL );
310 assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
312 if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
313 return LDAP_PVT_THREAD_EINVAL;
315 ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
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 );
324 if (rw->ltrw_r_wait > 0) {
325 ldap_pvt_thread_cond_broadcast( &rw->ltrw_read );
327 } else if (rw->ltrw_w_wait > 0) {
328 ldap_pvt_thread_cond_signal( &rw->ltrw_write );
331 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
336 #ifdef LDAP_RDWR_DEBUG
339 * return 0 if false, suitable for assert(ldap_pvt_thread_rdwr_Xchk(rdwr))
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.
344 * Basically sufficent for testing that places that should have
348 int ldap_pvt_thread_rdwr_readers(ldap_pvt_thread_rdwr_t *rwlock)
350 struct ldap_int_thread_rdwr_s *rw;
352 assert( rwlock != NULL );
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 );
362 return( rw->ltrw_r_active );
365 int ldap_pvt_thread_rdwr_writers(ldap_pvt_thread_rdwr_t *rwlock)
367 struct ldap_int_thread_rdwr_s *rw;
369 assert( rwlock != NULL );
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 );
379 return( rw->ltrw_w_active );
382 int ldap_pvt_thread_rdwr_active(ldap_pvt_thread_rdwr_t *rwlock)
384 struct ldap_int_thread_rdwr_s *rw;
386 assert( rwlock != NULL );
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 );
396 return(ldap_pvt_thread_rdwr_readers(rw) +
397 ldap_pvt_thread_rdwr_writers(rw));
400 #endif /* LDAP_DEBUG */
402 #endif /* LDAP_THREAD_HAVE_RDWR */