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