]> git.sur5r.net Git - openldap/blob - libraries/libldap_r/rdwr.c
Use ldap_pvt_strtok directly and unconditionally.
[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 "ldap_pvt_thread.h"
24
25 int 
26 ldap_pvt_thread_rdwr_init( ldap_pvt_thread_rdwr_t *rw )
27 {
28         memset( rw, 0, sizeof(ldap_pvt_thread_rdwr_t) );
29
30         /* we should check return results */
31         ldap_pvt_thread_mutex_init( &rw->ltrw_mutex );
32         ldap_pvt_thread_cond_init( &rw->ltrw_read );
33         ldap_pvt_thread_cond_init( &rw->ltrw_write );
34
35         rw->ltrw_valid = LDAP_PVT_THREAD_RDWR_VALUE;
36         return 0;
37 }
38
39 int 
40 ldap_pvt_thread_rdwr_destroy( ldap_pvt_thread_rdwr_t *rw )
41 {
42         if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALUE )
43                 return LDAP_PVT_THREAD_EINVAL;
44
45         ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
46
47         /* active threads? */
48         if( rw->ltrw_r_active > 0 || rw->ltrw_w_active > 1) {
49                 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
50                 return LDAP_PVT_THREAD_EBUSY;
51         }
52
53         /* waiting threads? */
54         if( rw->ltrw_r_wait > 0 || rw->ltrw_w_wait > 0) {
55                 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
56                 return LDAP_PVT_THREAD_EBUSY;
57         }
58
59         rw->ltrw_valid = 0;
60
61         ldap_pvt_thread_mutex_destroy( &rw->ltrw_mutex );
62         ldap_pvt_thread_cond_destroy( &rw->ltrw_read );
63         ldap_pvt_thread_cond_destroy( &rw->ltrw_write );
64
65         return 0;
66 }
67
68 int ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rw )
69 {
70         if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALUE )
71                 return LDAP_PVT_THREAD_EINVAL;
72
73         ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
74
75         if( rw->ltrw_w_active > 1 ) {
76                 /* writer is active */
77
78                 rw->ltrw_r_wait++;
79
80                 do {
81                         ldap_pvt_thread_cond_wait(
82                                 &rw->ltrw_read, &rw->ltrw_mutex );
83                 } while( rw->ltrw_w_active > 1 );
84
85                 rw->ltrw_r_wait--;
86         }
87
88         rw->ltrw_r_active++;
89
90         ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
91
92         return 0;
93 }
94
95 int ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rw )
96 {
97         if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALUE )
98                 return LDAP_PVT_THREAD_EINVAL;
99
100         ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
101
102         if( rw->ltrw_w_active > 1) {
103                 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
104                 return LDAP_PVT_THREAD_EBUSY;
105         }
106
107         rw->ltrw_r_active++;
108
109         ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
110
111         return 0;
112 }
113
114 int ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rw )
115 {
116         if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALUE )
117                 return LDAP_PVT_THREAD_EINVAL;
118
119         ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
120
121         rw->ltrw_r_active--;
122
123         if (rw->ltrw_r_active == 0 && rw->ltrw_w_wait > 0 ) {
124                 ldap_pvt_thread_cond_signal( &rw->ltrw_write );
125         }
126
127         ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
128
129         return 0;
130 }
131
132 int ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rw )
133 {
134         if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALUE )
135                 return LDAP_PVT_THREAD_EINVAL;
136
137         ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
138
139         if ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 ) {
140                 rw->ltrw_w_wait++;
141
142                 do {
143                         ldap_pvt_thread_cond_wait(
144                                 &rw->ltrw_write, &rw->ltrw_mutex );
145                 } while ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 );
146
147                 rw->ltrw_w_wait--;
148         }
149
150         rw->ltrw_w_active++;
151
152         ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
153
154         return 0;
155 }
156
157 int ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rw )
158 {
159         if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALUE )
160                 return LDAP_PVT_THREAD_EINVAL;
161
162         ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
163
164         if ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 ) {
165                 ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
166                 return LDAP_PVT_THREAD_EBUSY;
167         }
168
169         rw->ltrw_w_active++;
170
171         ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
172
173         return 0;
174 }
175
176 int ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rw )
177 {
178         if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALUE )
179                 return LDAP_PVT_THREAD_EINVAL;
180
181         ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
182
183         rw->ltrw_w_active--;
184
185         if (rw->ltrw_r_wait > 0) {
186                 ldap_pvt_thread_cond_broadcast( &rw->ltrw_read );
187
188         } else if (rw->ltrw_w_wait > 0) {
189                 ldap_pvt_thread_cond_signal( &rw->ltrw_write );
190         }
191
192         ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
193
194         return 0;
195 }
196
197 #ifdef LDAP_DEBUG
198
199 /* just for testing, 
200  * return 0 if false, suitable for assert(ldap_pvt_thread_rdwr_Xchk(rdwr))
201  * 
202  * Currently they don't check if the calling thread is the one 
203  * that has the lock, just that there is a reader or writer.
204  *
205  * Basically sufficent for testing that places that should have
206  * a lock are caught.
207  */
208
209 int ldap_pvt_thread_rdwr_readers(ldap_pvt_thread_rdwr_t *rw)
210 {
211         return( rw->ltrw_r_active );
212 }
213
214 int ldap_pvt_thread_rdwr_writers(ldap_pvt_thread_rdwr_t *rw)
215 {
216         return( rw->ltrw_w_active );
217 }
218
219 int ldap_pvt_thread_rdwr_active(ldap_pvt_thread_rdwr_t *rw)
220 {
221         return(ldap_pvt_thread_rdwr_readers(rw) +
222                ldap_pvt_thread_rdwr_writers(rw));
223 }
224
225 #endif /* LDAP_DEBUG */