xref: /netbsd-src/external/bsd/openldap/dist/libraries/libldap/rdwr.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
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