1*549b59edSchristos /* $NetBSD: rdwr.c,v 1.2 2021/08/14 16:14:56 christos Exp $ */
2e670fd5cSchristos
3e670fd5cSchristos /* $OpenLDAP$ */
4e670fd5cSchristos /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5e670fd5cSchristos *
6e670fd5cSchristos * Copyright 1998-2021 The OpenLDAP Foundation.
7e670fd5cSchristos * All rights reserved.
8e670fd5cSchristos *
9e670fd5cSchristos * Redistribution and use in source and binary forms, with or without
10e670fd5cSchristos * modification, are permitted only as authorized by the OpenLDAP
11e670fd5cSchristos * Public License.
12e670fd5cSchristos *
13e670fd5cSchristos * A copy of this license is available in file LICENSE in the
14e670fd5cSchristos * top-level directory of the distribution or, alternatively, at
15e670fd5cSchristos * <http://www.OpenLDAP.org/license.html>.
16e670fd5cSchristos */
17e670fd5cSchristos /* This work was initially developed by Kurt D. Zeilenga for inclusion
18e670fd5cSchristos * in OpenLDAP Software. Additional significant contributors include:
19e670fd5cSchristos * Stuart Lynne
20e670fd5cSchristos */
21e670fd5cSchristos
22e670fd5cSchristos /*
23e670fd5cSchristos * This is an improved implementation of Reader/Writer locks does
24e670fd5cSchristos * not protect writers from starvation. That is, if a writer is
25e670fd5cSchristos * currently waiting on a reader, any new reader will get
26e670fd5cSchristos * the lock before the writer.
27e670fd5cSchristos *
28e670fd5cSchristos * Does not support cancellation nor does any status checking.
29e670fd5cSchristos */
30e670fd5cSchristos /* Adapted from publicly available examples for:
31e670fd5cSchristos * "Programming with Posix Threads"
32e670fd5cSchristos * by David R Butenhof, Addison-Wesley
33e670fd5cSchristos * http://cseng.aw.com/bookpage.taf?ISBN=0-201-63392-2
34e670fd5cSchristos */
35e670fd5cSchristos
36e670fd5cSchristos #include <sys/cdefs.h>
37*549b59edSchristos __RCSID("$NetBSD: rdwr.c,v 1.2 2021/08/14 16:14:56 christos Exp $");
38e670fd5cSchristos
39e670fd5cSchristos #include "portable.h"
40e670fd5cSchristos
41e670fd5cSchristos #include <ac/stdlib.h>
42e670fd5cSchristos
43e670fd5cSchristos #include <ac/errno.h>
44e670fd5cSchristos #include <ac/string.h>
45e670fd5cSchristos #include <ac/time.h>
46e670fd5cSchristos
47e670fd5cSchristos #include "ldap-int.h"
48e670fd5cSchristos
49e670fd5cSchristos #ifdef LDAP_R_COMPILE
50e670fd5cSchristos
51e670fd5cSchristos #include "ldap_pvt_thread.h" /* Get the thread interface */
52e670fd5cSchristos #define LDAP_THREAD_RDWR_IMPLEMENTATION
53e670fd5cSchristos #include "ldap_thr_debug.h" /* May rename the symbols defined below */
54e670fd5cSchristos
55e670fd5cSchristos /*
56e670fd5cSchristos * implementations that provide their own compatible
57e670fd5cSchristos * reader/writer locks define LDAP_THREAD_HAVE_RDWR
58e670fd5cSchristos * in ldap_pvt_thread.h
59e670fd5cSchristos */
60e670fd5cSchristos #ifndef LDAP_THREAD_HAVE_RDWR
61e670fd5cSchristos
62e670fd5cSchristos struct ldap_int_thread_rdwr_s {
63e670fd5cSchristos ldap_pvt_thread_mutex_t ltrw_mutex;
64e670fd5cSchristos ldap_pvt_thread_cond_t ltrw_read; /* wait for read */
65e670fd5cSchristos ldap_pvt_thread_cond_t ltrw_write; /* wait for write */
66e670fd5cSchristos int ltrw_valid;
67e670fd5cSchristos #define LDAP_PVT_THREAD_RDWR_VALID 0x0bad
68e670fd5cSchristos int ltrw_r_active;
69e670fd5cSchristos int ltrw_w_active;
70e670fd5cSchristos int ltrw_r_wait;
71e670fd5cSchristos int ltrw_w_wait;
72e670fd5cSchristos #ifdef LDAP_RDWR_DEBUG
73e670fd5cSchristos /* keep track of who has these locks */
74e670fd5cSchristos #define MAX_READERS 32
75e670fd5cSchristos int ltrw_more_readers; /* Set if ltrw_readers[] is incomplete */
76e670fd5cSchristos ldap_pvt_thread_t ltrw_readers[MAX_READERS];
77e670fd5cSchristos ldap_pvt_thread_t ltrw_writer;
78e670fd5cSchristos #endif
79e670fd5cSchristos };
80e670fd5cSchristos
81e670fd5cSchristos int
ldap_pvt_thread_rdwr_init(ldap_pvt_thread_rdwr_t * rwlock)82e670fd5cSchristos ldap_pvt_thread_rdwr_init( ldap_pvt_thread_rdwr_t *rwlock )
83e670fd5cSchristos {
84e670fd5cSchristos struct ldap_int_thread_rdwr_s *rw;
85e670fd5cSchristos
86e670fd5cSchristos assert( rwlock != NULL );
87e670fd5cSchristos
88e670fd5cSchristos rw = (struct ldap_int_thread_rdwr_s *) LDAP_CALLOC( 1,
89e670fd5cSchristos sizeof( struct ldap_int_thread_rdwr_s ) );
90e670fd5cSchristos if ( !rw )
91e670fd5cSchristos return LDAP_NO_MEMORY;
92e670fd5cSchristos
93e670fd5cSchristos /* we should check return results */
94e670fd5cSchristos ldap_pvt_thread_mutex_init( &rw->ltrw_mutex );
95e670fd5cSchristos ldap_pvt_thread_cond_init( &rw->ltrw_read );
96e670fd5cSchristos ldap_pvt_thread_cond_init( &rw->ltrw_write );
97e670fd5cSchristos
98e670fd5cSchristos rw->ltrw_valid = LDAP_PVT_THREAD_RDWR_VALID;
99e670fd5cSchristos
100e670fd5cSchristos *rwlock = rw;
101e670fd5cSchristos return 0;
102e670fd5cSchristos }
103e670fd5cSchristos
104e670fd5cSchristos int
ldap_pvt_thread_rdwr_destroy(ldap_pvt_thread_rdwr_t * rwlock)105e670fd5cSchristos ldap_pvt_thread_rdwr_destroy( ldap_pvt_thread_rdwr_t *rwlock )
106e670fd5cSchristos {
107e670fd5cSchristos struct ldap_int_thread_rdwr_s *rw;
108e670fd5cSchristos
109e670fd5cSchristos assert( rwlock != NULL );
110e670fd5cSchristos rw = *rwlock;
111e670fd5cSchristos
112e670fd5cSchristos assert( rw != NULL );
113e670fd5cSchristos assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
114e670fd5cSchristos
115e670fd5cSchristos if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
116e670fd5cSchristos return LDAP_PVT_THREAD_EINVAL;
117e670fd5cSchristos
118e670fd5cSchristos ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
119e670fd5cSchristos
120e670fd5cSchristos assert( rw->ltrw_w_active >= 0 );
121e670fd5cSchristos assert( rw->ltrw_w_wait >= 0 );
122e670fd5cSchristos assert( rw->ltrw_r_active >= 0 );
123e670fd5cSchristos assert( rw->ltrw_r_wait >= 0 );
124e670fd5cSchristos
125e670fd5cSchristos /* active threads? */
126e670fd5cSchristos if( rw->ltrw_r_active > 0 || rw->ltrw_w_active > 0) {
127e670fd5cSchristos ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
128e670fd5cSchristos return LDAP_PVT_THREAD_EBUSY;
129e670fd5cSchristos }
130e670fd5cSchristos
131e670fd5cSchristos /* waiting threads? */
132e670fd5cSchristos if( rw->ltrw_r_wait > 0 || rw->ltrw_w_wait > 0) {
133e670fd5cSchristos ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
134e670fd5cSchristos return LDAP_PVT_THREAD_EBUSY;
135e670fd5cSchristos }
136e670fd5cSchristos
137e670fd5cSchristos rw->ltrw_valid = 0;
138e670fd5cSchristos
139e670fd5cSchristos ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
140e670fd5cSchristos
141e670fd5cSchristos ldap_pvt_thread_mutex_destroy( &rw->ltrw_mutex );
142e670fd5cSchristos ldap_pvt_thread_cond_destroy( &rw->ltrw_read );
143e670fd5cSchristos ldap_pvt_thread_cond_destroy( &rw->ltrw_write );
144e670fd5cSchristos
145e670fd5cSchristos LDAP_FREE(rw);
146e670fd5cSchristos *rwlock = NULL;
147e670fd5cSchristos return 0;
148e670fd5cSchristos }
149e670fd5cSchristos
ldap_pvt_thread_rdwr_rlock(ldap_pvt_thread_rdwr_t * rwlock)150e670fd5cSchristos int ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rwlock )
151e670fd5cSchristos {
152e670fd5cSchristos struct ldap_int_thread_rdwr_s *rw;
153e670fd5cSchristos
154e670fd5cSchristos assert( rwlock != NULL );
155e670fd5cSchristos rw = *rwlock;
156e670fd5cSchristos
157e670fd5cSchristos assert( rw != NULL );
158e670fd5cSchristos assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
159e670fd5cSchristos
160e670fd5cSchristos if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
161e670fd5cSchristos return LDAP_PVT_THREAD_EINVAL;
162e670fd5cSchristos
163e670fd5cSchristos ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
164e670fd5cSchristos
165e670fd5cSchristos assert( rw->ltrw_w_active >= 0 );
166e670fd5cSchristos assert( rw->ltrw_w_wait >= 0 );
167e670fd5cSchristos assert( rw->ltrw_r_active >= 0 );
168e670fd5cSchristos assert( rw->ltrw_r_wait >= 0 );
169e670fd5cSchristos
170e670fd5cSchristos if( rw->ltrw_w_active > 0 ) {
171e670fd5cSchristos /* writer is active */
172e670fd5cSchristos
173e670fd5cSchristos rw->ltrw_r_wait++;
174e670fd5cSchristos
175e670fd5cSchristos do {
176e670fd5cSchristos ldap_pvt_thread_cond_wait(
177e670fd5cSchristos &rw->ltrw_read, &rw->ltrw_mutex );
178e670fd5cSchristos } while( rw->ltrw_w_active > 0 );
179e670fd5cSchristos
180e670fd5cSchristos rw->ltrw_r_wait--;
181e670fd5cSchristos assert( rw->ltrw_r_wait >= 0 );
182e670fd5cSchristos }
183e670fd5cSchristos
184e670fd5cSchristos #ifdef LDAP_RDWR_DEBUG
185e670fd5cSchristos if( rw->ltrw_r_active < MAX_READERS )
186e670fd5cSchristos rw->ltrw_readers[rw->ltrw_r_active] = ldap_pvt_thread_self();
187e670fd5cSchristos else
188e670fd5cSchristos rw->ltrw_more_readers = 1;
189e670fd5cSchristos #endif
190e670fd5cSchristos rw->ltrw_r_active++;
191e670fd5cSchristos
192e670fd5cSchristos
193e670fd5cSchristos ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
194e670fd5cSchristos
195e670fd5cSchristos return 0;
196e670fd5cSchristos }
197e670fd5cSchristos
ldap_pvt_thread_rdwr_rtrylock(ldap_pvt_thread_rdwr_t * rwlock)198e670fd5cSchristos int ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rwlock )
199e670fd5cSchristos {
200e670fd5cSchristos struct ldap_int_thread_rdwr_s *rw;
201e670fd5cSchristos
202e670fd5cSchristos assert( rwlock != NULL );
203e670fd5cSchristos rw = *rwlock;
204e670fd5cSchristos
205e670fd5cSchristos assert( rw != NULL );
206e670fd5cSchristos assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
207e670fd5cSchristos
208e670fd5cSchristos if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
209e670fd5cSchristos return LDAP_PVT_THREAD_EINVAL;
210e670fd5cSchristos
211e670fd5cSchristos ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
212e670fd5cSchristos
213e670fd5cSchristos assert( rw->ltrw_w_active >= 0 );
214e670fd5cSchristos assert( rw->ltrw_w_wait >= 0 );
215e670fd5cSchristos assert( rw->ltrw_r_active >= 0 );
216e670fd5cSchristos assert( rw->ltrw_r_wait >= 0 );
217e670fd5cSchristos
218e670fd5cSchristos if( rw->ltrw_w_active > 0) {
219e670fd5cSchristos ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
220e670fd5cSchristos return LDAP_PVT_THREAD_EBUSY;
221e670fd5cSchristos }
222e670fd5cSchristos
223e670fd5cSchristos #ifdef LDAP_RDWR_DEBUG
224e670fd5cSchristos if( rw->ltrw_r_active < MAX_READERS )
225e670fd5cSchristos rw->ltrw_readers[rw->ltrw_r_active] = ldap_pvt_thread_self();
226e670fd5cSchristos else
227e670fd5cSchristos rw->ltrw_more_readers = 1;
228e670fd5cSchristos #endif
229e670fd5cSchristos rw->ltrw_r_active++;
230e670fd5cSchristos
231e670fd5cSchristos ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
232e670fd5cSchristos
233e670fd5cSchristos return 0;
234e670fd5cSchristos }
235e670fd5cSchristos
ldap_pvt_thread_rdwr_runlock(ldap_pvt_thread_rdwr_t * rwlock)236e670fd5cSchristos int ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rwlock )
237e670fd5cSchristos {
238e670fd5cSchristos struct ldap_int_thread_rdwr_s *rw;
239e670fd5cSchristos
240e670fd5cSchristos assert( rwlock != NULL );
241e670fd5cSchristos rw = *rwlock;
242e670fd5cSchristos
243e670fd5cSchristos assert( rw != NULL );
244e670fd5cSchristos assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
245e670fd5cSchristos
246e670fd5cSchristos if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
247e670fd5cSchristos return LDAP_PVT_THREAD_EINVAL;
248e670fd5cSchristos
249e670fd5cSchristos ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
250e670fd5cSchristos
251e670fd5cSchristos rw->ltrw_r_active--;
252e670fd5cSchristos #ifdef LDAP_RDWR_DEBUG
253e670fd5cSchristos /* Remove us from the list of readers */
254e670fd5cSchristos {
255e670fd5cSchristos ldap_pvt_thread_t self = ldap_pvt_thread_self();
256e670fd5cSchristos int i, j;
257e670fd5cSchristos for( i = j = rw->ltrw_r_active; i >= 0; i--) {
258e670fd5cSchristos if (rw->ltrw_readers[i] == self) {
259e670fd5cSchristos rw->ltrw_readers[i] = rw->ltrw_readers[j];
260e670fd5cSchristos rw->ltrw_readers[j] = 0;
261e670fd5cSchristos break;
262e670fd5cSchristos }
263e670fd5cSchristos }
264e670fd5cSchristos if( !rw->ltrw_more_readers )
265e670fd5cSchristos assert( i >= 0 );
266e670fd5cSchristos else if( j == 0 )
267e670fd5cSchristos rw->ltrw_more_readers = 0;
268e670fd5cSchristos }
269e670fd5cSchristos #endif
270e670fd5cSchristos
271e670fd5cSchristos assert( rw->ltrw_w_active >= 0 );
272e670fd5cSchristos assert( rw->ltrw_w_wait >= 0 );
273e670fd5cSchristos assert( rw->ltrw_r_active >= 0 );
274e670fd5cSchristos assert( rw->ltrw_r_wait >= 0 );
275e670fd5cSchristos
276e670fd5cSchristos if (rw->ltrw_r_active == 0 && rw->ltrw_w_wait > 0 ) {
277e670fd5cSchristos ldap_pvt_thread_cond_signal( &rw->ltrw_write );
278e670fd5cSchristos }
279e670fd5cSchristos
280e670fd5cSchristos ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
281e670fd5cSchristos
282e670fd5cSchristos return 0;
283e670fd5cSchristos }
284e670fd5cSchristos
ldap_pvt_thread_rdwr_wlock(ldap_pvt_thread_rdwr_t * rwlock)285e670fd5cSchristos int ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rwlock )
286e670fd5cSchristos {
287e670fd5cSchristos struct ldap_int_thread_rdwr_s *rw;
288e670fd5cSchristos
289e670fd5cSchristos assert( rwlock != NULL );
290e670fd5cSchristos rw = *rwlock;
291e670fd5cSchristos
292e670fd5cSchristos assert( rw != NULL );
293e670fd5cSchristos assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
294e670fd5cSchristos
295e670fd5cSchristos if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
296e670fd5cSchristos return LDAP_PVT_THREAD_EINVAL;
297e670fd5cSchristos
298e670fd5cSchristos ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
299e670fd5cSchristos
300e670fd5cSchristos assert( rw->ltrw_w_active >= 0 );
301e670fd5cSchristos assert( rw->ltrw_w_wait >= 0 );
302e670fd5cSchristos assert( rw->ltrw_r_active >= 0 );
303e670fd5cSchristos assert( rw->ltrw_r_wait >= 0 );
304e670fd5cSchristos
305e670fd5cSchristos if ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 ) {
306e670fd5cSchristos rw->ltrw_w_wait++;
307e670fd5cSchristos
308e670fd5cSchristos do {
309e670fd5cSchristos ldap_pvt_thread_cond_wait(
310e670fd5cSchristos &rw->ltrw_write, &rw->ltrw_mutex );
311e670fd5cSchristos } while ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 );
312e670fd5cSchristos
313e670fd5cSchristos rw->ltrw_w_wait--;
314e670fd5cSchristos assert( rw->ltrw_w_wait >= 0 );
315e670fd5cSchristos }
316e670fd5cSchristos
317e670fd5cSchristos #ifdef LDAP_RDWR_DEBUG
318e670fd5cSchristos rw->ltrw_writer = ldap_pvt_thread_self();
319e670fd5cSchristos #endif
320e670fd5cSchristos rw->ltrw_w_active++;
321e670fd5cSchristos
322e670fd5cSchristos ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
323e670fd5cSchristos
324e670fd5cSchristos return 0;
325e670fd5cSchristos }
326e670fd5cSchristos
ldap_pvt_thread_rdwr_wtrylock(ldap_pvt_thread_rdwr_t * rwlock)327e670fd5cSchristos int ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rwlock )
328e670fd5cSchristos {
329e670fd5cSchristos struct ldap_int_thread_rdwr_s *rw;
330e670fd5cSchristos
331e670fd5cSchristos assert( rwlock != NULL );
332e670fd5cSchristos rw = *rwlock;
333e670fd5cSchristos
334e670fd5cSchristos assert( rw != NULL );
335e670fd5cSchristos assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
336e670fd5cSchristos
337e670fd5cSchristos if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
338e670fd5cSchristos return LDAP_PVT_THREAD_EINVAL;
339e670fd5cSchristos
340e670fd5cSchristos ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
341e670fd5cSchristos
342e670fd5cSchristos assert( rw->ltrw_w_active >= 0 );
343e670fd5cSchristos assert( rw->ltrw_w_wait >= 0 );
344e670fd5cSchristos assert( rw->ltrw_r_active >= 0 );
345e670fd5cSchristos assert( rw->ltrw_r_wait >= 0 );
346e670fd5cSchristos
347e670fd5cSchristos if ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 ) {
348e670fd5cSchristos ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
349e670fd5cSchristos return LDAP_PVT_THREAD_EBUSY;
350e670fd5cSchristos }
351e670fd5cSchristos
352e670fd5cSchristos #ifdef LDAP_RDWR_DEBUG
353e670fd5cSchristos rw->ltrw_writer = ldap_pvt_thread_self();
354e670fd5cSchristos #endif
355e670fd5cSchristos rw->ltrw_w_active++;
356e670fd5cSchristos
357e670fd5cSchristos ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
358e670fd5cSchristos
359e670fd5cSchristos return 0;
360e670fd5cSchristos }
361e670fd5cSchristos
ldap_pvt_thread_rdwr_wunlock(ldap_pvt_thread_rdwr_t * rwlock)362e670fd5cSchristos int ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rwlock )
363e670fd5cSchristos {
364e670fd5cSchristos struct ldap_int_thread_rdwr_s *rw;
365e670fd5cSchristos
366e670fd5cSchristos assert( rwlock != NULL );
367e670fd5cSchristos rw = *rwlock;
368e670fd5cSchristos
369e670fd5cSchristos assert( rw != NULL );
370e670fd5cSchristos assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
371e670fd5cSchristos
372e670fd5cSchristos if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
373e670fd5cSchristos return LDAP_PVT_THREAD_EINVAL;
374e670fd5cSchristos
375e670fd5cSchristos ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
376e670fd5cSchristos
377e670fd5cSchristos rw->ltrw_w_active--;
378e670fd5cSchristos
379e670fd5cSchristos assert( rw->ltrw_w_active >= 0 );
380e670fd5cSchristos assert( rw->ltrw_w_wait >= 0 );
381e670fd5cSchristos assert( rw->ltrw_r_active >= 0 );
382e670fd5cSchristos assert( rw->ltrw_r_wait >= 0 );
383e670fd5cSchristos
384e670fd5cSchristos if (rw->ltrw_r_wait > 0) {
385e670fd5cSchristos ldap_pvt_thread_cond_broadcast( &rw->ltrw_read );
386e670fd5cSchristos
387e670fd5cSchristos } else if (rw->ltrw_w_wait > 0) {
388e670fd5cSchristos ldap_pvt_thread_cond_signal( &rw->ltrw_write );
389e670fd5cSchristos }
390e670fd5cSchristos
391e670fd5cSchristos #ifdef LDAP_RDWR_DEBUG
392e670fd5cSchristos assert( rw->ltrw_writer == ldap_pvt_thread_self() );
393e670fd5cSchristos rw->ltrw_writer = 0;
394e670fd5cSchristos #endif
395e670fd5cSchristos ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
396e670fd5cSchristos
397e670fd5cSchristos return 0;
398e670fd5cSchristos }
399e670fd5cSchristos
400e670fd5cSchristos #ifdef LDAP_RDWR_DEBUG
401e670fd5cSchristos
402e670fd5cSchristos /* just for testing,
403e670fd5cSchristos * return 0 if false, suitable for assert(ldap_pvt_thread_rdwr_Xchk(rdwr))
404e670fd5cSchristos *
405e670fd5cSchristos * Currently they don't check if the calling thread is the one
406e670fd5cSchristos * that has the lock, just that there is a reader or writer.
407e670fd5cSchristos *
408e670fd5cSchristos * Basically sufficient for testing that places that should have
409e670fd5cSchristos * a lock are caught.
410e670fd5cSchristos */
411e670fd5cSchristos
ldap_pvt_thread_rdwr_readers(ldap_pvt_thread_rdwr_t * rwlock)412e670fd5cSchristos int ldap_pvt_thread_rdwr_readers(ldap_pvt_thread_rdwr_t *rwlock)
413e670fd5cSchristos {
414e670fd5cSchristos struct ldap_int_thread_rdwr_s *rw;
415e670fd5cSchristos
416e670fd5cSchristos assert( rwlock != NULL );
417e670fd5cSchristos rw = *rwlock;
418e670fd5cSchristos
419e670fd5cSchristos assert( rw != NULL );
420e670fd5cSchristos assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
421e670fd5cSchristos assert( rw->ltrw_w_active >= 0 );
422e670fd5cSchristos assert( rw->ltrw_w_wait >= 0 );
423e670fd5cSchristos assert( rw->ltrw_r_active >= 0 );
424e670fd5cSchristos assert( rw->ltrw_r_wait >= 0 );
425e670fd5cSchristos
426e670fd5cSchristos return( rw->ltrw_r_active );
427e670fd5cSchristos }
428e670fd5cSchristos
ldap_pvt_thread_rdwr_writers(ldap_pvt_thread_rdwr_t * rwlock)429e670fd5cSchristos int ldap_pvt_thread_rdwr_writers(ldap_pvt_thread_rdwr_t *rwlock)
430e670fd5cSchristos {
431e670fd5cSchristos struct ldap_int_thread_rdwr_s *rw;
432e670fd5cSchristos
433e670fd5cSchristos assert( rwlock != NULL );
434e670fd5cSchristos rw = *rwlock;
435e670fd5cSchristos
436e670fd5cSchristos assert( rw != NULL );
437e670fd5cSchristos assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
438e670fd5cSchristos assert( rw->ltrw_w_active >= 0 );
439e670fd5cSchristos assert( rw->ltrw_w_wait >= 0 );
440e670fd5cSchristos assert( rw->ltrw_r_active >= 0 );
441e670fd5cSchristos assert( rw->ltrw_r_wait >= 0 );
442e670fd5cSchristos
443e670fd5cSchristos return( rw->ltrw_w_active );
444e670fd5cSchristos }
445e670fd5cSchristos
ldap_pvt_thread_rdwr_active(ldap_pvt_thread_rdwr_t * rwlock)446e670fd5cSchristos int ldap_pvt_thread_rdwr_active(ldap_pvt_thread_rdwr_t *rwlock)
447e670fd5cSchristos {
448e670fd5cSchristos struct ldap_int_thread_rdwr_s *rw;
449e670fd5cSchristos
450e670fd5cSchristos assert( rwlock != NULL );
451e670fd5cSchristos rw = *rwlock;
452e670fd5cSchristos
453e670fd5cSchristos assert( rw != NULL );
454e670fd5cSchristos assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
455e670fd5cSchristos assert( rw->ltrw_w_active >= 0 );
456e670fd5cSchristos assert( rw->ltrw_w_wait >= 0 );
457e670fd5cSchristos assert( rw->ltrw_r_active >= 0 );
458e670fd5cSchristos assert( rw->ltrw_r_wait >= 0 );
459e670fd5cSchristos
460e670fd5cSchristos return(ldap_pvt_thread_rdwr_readers(rwlock) +
461e670fd5cSchristos ldap_pvt_thread_rdwr_writers(rwlock));
462e670fd5cSchristos }
463e670fd5cSchristos
464e670fd5cSchristos #endif /* LDAP_RDWR_DEBUG */
465e670fd5cSchristos
466e670fd5cSchristos #endif /* LDAP_THREAD_HAVE_RDWR */
467e670fd5cSchristos
468e670fd5cSchristos #endif /* LDAP_R_COMPILE */
469