]> git.sur5r.net Git - openldap/blob - libraries/libldap_r/rdwr.c
ifdef SLAP_CLEANUP: close db files, free memory, some other cleanup before exit
[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_VALUE;
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_VALUE )
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 #ifdef SLAP_CLEANUP
64         ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
65 #endif
66         ldap_pvt_thread_mutex_destroy( &rw->ltrw_mutex );
67         ldap_pvt_thread_cond_destroy( &rw->ltrw_read );
68         ldap_pvt_thread_cond_destroy( &rw->ltrw_write );
69
70         return 0;
71 }
72
73 int ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rw )
74 {
75         if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALUE )
76                 return LDAP_PVT_THREAD_EINVAL;
77
78         ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
79
80         if( rw->ltrw_w_active > 1 ) {
81                 /* writer is active */
82
83                 rw->ltrw_r_wait++;
84
85                 do {
86                         ldap_pvt_thread_cond_wait(
87                                 &rw->ltrw_read, &rw->ltrw_mutex );
88                 } while( rw->ltrw_w_active > 1 );
89
90                 rw->ltrw_r_wait--;
91         }
92
93         rw->ltrw_r_active++;
94
95         ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
96
97         return 0;
98 }
99
100 int ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rw )
101 {
102         if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALUE )
103                 return LDAP_PVT_THREAD_EINVAL;
104
105         ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
106
107         if( rw->ltrw_w_active > 1) {
108                 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
109                 return LDAP_PVT_THREAD_EBUSY;
110         }
111
112         rw->ltrw_r_active++;
113
114         ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
115
116         return 0;
117 }
118
119 int ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rw )
120 {
121         if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALUE )
122                 return LDAP_PVT_THREAD_EINVAL;
123
124         ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
125
126         rw->ltrw_r_active--;
127
128         if (rw->ltrw_r_active == 0 && rw->ltrw_w_wait > 0 ) {
129                 ldap_pvt_thread_cond_signal( &rw->ltrw_write );
130         }
131
132         ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
133
134         return 0;
135 }
136
137 int ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rw )
138 {
139         if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALUE )
140                 return LDAP_PVT_THREAD_EINVAL;
141
142         ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
143
144         if ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 ) {
145                 rw->ltrw_w_wait++;
146
147                 do {
148                         ldap_pvt_thread_cond_wait(
149                                 &rw->ltrw_write, &rw->ltrw_mutex );
150                 } while ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 );
151
152                 rw->ltrw_w_wait--;
153         }
154
155         rw->ltrw_w_active++;
156
157         ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
158
159         return 0;
160 }
161
162 int ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rw )
163 {
164         if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALUE )
165                 return LDAP_PVT_THREAD_EINVAL;
166
167         ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
168
169         if ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 ) {
170                 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
171                 return LDAP_PVT_THREAD_EBUSY;
172         }
173
174         rw->ltrw_w_active++;
175
176         ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
177
178         return 0;
179 }
180
181 int ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rw )
182 {
183         if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALUE )
184                 return LDAP_PVT_THREAD_EINVAL;
185
186         ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
187
188         rw->ltrw_w_active--;
189
190         if (rw->ltrw_r_wait > 0) {
191                 ldap_pvt_thread_cond_broadcast( &rw->ltrw_read );
192
193         } else if (rw->ltrw_w_wait > 0) {
194                 ldap_pvt_thread_cond_signal( &rw->ltrw_write );
195         }
196
197         ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
198
199         return 0;
200 }
201
202 #ifdef LDAP_DEBUG
203
204 /* just for testing, 
205  * return 0 if false, suitable for assert(ldap_pvt_thread_rdwr_Xchk(rdwr))
206  * 
207  * Currently they don't check if the calling thread is the one 
208  * that has the lock, just that there is a reader or writer.
209  *
210  * Basically sufficent for testing that places that should have
211  * a lock are caught.
212  */
213
214 int ldap_pvt_thread_rdwr_readers(ldap_pvt_thread_rdwr_t *rw)
215 {
216         return( rw->ltrw_r_active );
217 }
218
219 int ldap_pvt_thread_rdwr_writers(ldap_pvt_thread_rdwr_t *rw)
220 {
221         return( rw->ltrw_w_active );
222 }
223
224 int ldap_pvt_thread_rdwr_active(ldap_pvt_thread_rdwr_t *rw)
225 {
226         return(ldap_pvt_thread_rdwr_readers(rw) +
227                ldap_pvt_thread_rdwr_writers(rw));
228 }
229
230 #endif /* LDAP_DEBUG */