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.
8 ** Does not support cancellation nor does any status checking.
11 /********************************************************
13 * "Programming with Posix Threads"
16 ********************************************************
21 #include <ac/stdlib.h>
24 #include <ac/string.h>
26 #include "ldap_pvt_thread.h"
29 ldap_pvt_thread_rdwr_init( ldap_pvt_thread_rdwr_t *rw )
33 memset( rw, 0, sizeof(ldap_pvt_thread_rdwr_t) );
35 /* we should check return results */
36 ldap_pvt_thread_mutex_init( &rw->ltrw_mutex );
37 ldap_pvt_thread_cond_init( &rw->ltrw_read );
38 ldap_pvt_thread_cond_init( &rw->ltrw_write );
40 rw->ltrw_valid = LDAP_PVT_THREAD_RDWR_VALID;
45 ldap_pvt_thread_rdwr_destroy( ldap_pvt_thread_rdwr_t *rw )
48 assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
50 if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
51 return LDAP_PVT_THREAD_EINVAL;
53 ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
56 if( rw->ltrw_r_active > 0 || rw->ltrw_w_active > 1) {
57 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
58 return LDAP_PVT_THREAD_EBUSY;
61 /* waiting threads? */
62 if( rw->ltrw_r_wait > 0 || rw->ltrw_w_wait > 0) {
63 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
64 return LDAP_PVT_THREAD_EBUSY;
69 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
71 ldap_pvt_thread_mutex_destroy( &rw->ltrw_mutex );
72 ldap_pvt_thread_cond_destroy( &rw->ltrw_read );
73 ldap_pvt_thread_cond_destroy( &rw->ltrw_write );
78 int ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rw )
81 assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
83 if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
84 return LDAP_PVT_THREAD_EINVAL;
86 ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
88 if( rw->ltrw_w_active > 1 ) {
89 /* writer is active */
94 ldap_pvt_thread_cond_wait(
95 &rw->ltrw_read, &rw->ltrw_mutex );
96 } while( rw->ltrw_w_active > 1 );
103 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
108 int ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rw )
110 assert( rw != NULL );
111 assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
113 if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
114 return LDAP_PVT_THREAD_EINVAL;
116 ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
118 if( rw->ltrw_w_active > 1) {
119 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
120 return LDAP_PVT_THREAD_EBUSY;
125 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
130 int ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rw )
132 assert( rw != NULL );
133 assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
135 if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
136 return LDAP_PVT_THREAD_EINVAL;
138 ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
142 if (rw->ltrw_r_active == 0 && rw->ltrw_w_wait > 0 ) {
143 ldap_pvt_thread_cond_signal( &rw->ltrw_write );
146 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
151 int ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rw )
153 assert( rw != NULL );
154 assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
156 if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
157 return LDAP_PVT_THREAD_EINVAL;
159 ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
161 if ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 ) {
165 ldap_pvt_thread_cond_wait(
166 &rw->ltrw_write, &rw->ltrw_mutex );
167 } while ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 );
174 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
179 int ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rw )
181 assert( rw != NULL );
182 assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
184 if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
185 return LDAP_PVT_THREAD_EINVAL;
187 ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
189 if ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 ) {
190 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
191 return LDAP_PVT_THREAD_EBUSY;
196 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
201 int ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rw )
203 assert( rw != NULL );
204 assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
206 if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
207 return LDAP_PVT_THREAD_EINVAL;
209 ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
213 if (rw->ltrw_r_wait > 0) {
214 ldap_pvt_thread_cond_broadcast( &rw->ltrw_read );
216 } else if (rw->ltrw_w_wait > 0) {
217 ldap_pvt_thread_cond_signal( &rw->ltrw_write );
220 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
228 * return 0 if false, suitable for assert(ldap_pvt_thread_rdwr_Xchk(rdwr))
230 * Currently they don't check if the calling thread is the one
231 * that has the lock, just that there is a reader or writer.
233 * Basically sufficent for testing that places that should have
237 int ldap_pvt_thread_rdwr_readers(ldap_pvt_thread_rdwr_t *rw)
239 assert( rw != NULL );
240 assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
242 return( rw->ltrw_r_active );
245 int ldap_pvt_thread_rdwr_writers(ldap_pvt_thread_rdwr_t *rw)
247 assert( rw != NULL );
248 assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
250 return( rw->ltrw_w_active );
253 int ldap_pvt_thread_rdwr_active(ldap_pvt_thread_rdwr_t *rw)
255 assert( rw != NULL );
256 assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
258 return(ldap_pvt_thread_rdwr_readers(rw) +
259 ldap_pvt_thread_rdwr_writers(rw));
262 #endif /* LDAP_DEBUG */