summaryrefslogtreecommitdiffstats
path: root/ldap/servers/slapd/rwlock.c
diff options
context:
space:
mode:
authorcvsadm <cvsadm>2005-01-21 00:44:34 +0000
committercvsadm <cvsadm>2005-01-21 00:44:34 +0000
commitb2093e3016027d6b5cf06b3f91f30769bfc099e2 (patch)
treecf58939393a9032182c4fbc4441164a9456e82f8 /ldap/servers/slapd/rwlock.c
downloadds-b2093e3016027d6b5cf06b3f91f30769bfc099e2.tar.gz
ds-b2093e3016027d6b5cf06b3f91f30769bfc099e2.tar.xz
ds-b2093e3016027d6b5cf06b3f91f30769bfc099e2.zip
Moving NSCP Directory Server from DirectoryBranch to TRUNK, initial drop. (foxworth)ldapserver7x
Diffstat (limited to 'ldap/servers/slapd/rwlock.c')
-rw-r--r--ldap/servers/slapd/rwlock.c222
1 files changed, 222 insertions, 0 deletions
diff --git a/ldap/servers/slapd/rwlock.c b/ldap/servers/slapd/rwlock.c
new file mode 100644
index 00000000..8642a9ea
--- /dev/null
+++ b/ldap/servers/slapd/rwlock.c
@@ -0,0 +1,222 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * rwlock.c - generic multiple reader, single-writer locking routines.
+ *
+ * The general idea is:
+ *
+ * If you have a data structure which you'd like to allow multiple threads
+ * to read, but only one thread at a time to write, you include in your
+ * data structure a pointer to an rwl structure, and call rwl_new() to
+ * obtain an allocated and initialized rwl structure.
+ *
+ * Then, call the appropriate functions via the provided function pointers
+ * to acquire/relinquish read or write locks on your data structure. You
+ * may want to provide some convenience macros to make the code prettier.
+ *
+ * The semantics are:
+ * - a thread attempting to obtain a read lock will succeed immediately as
+ * long as there are no threads with write locks.
+ * - a thread attempting to obtain a write lock will wait until all readers
+ * have relinquished their read locks.
+ * - a thread attempting to obtain a write lock blocks other threads from
+ * obtaining read locks. As long as all readers release their locks,
+ * the write will eventually get the lock.
+ */
+
+#include "slap.h"
+
+#include <prlock.h>
+#include <prcvar.h>
+#include "rwlock.h"
+
+/*
+ * Function: __rwl_acquire_read_lock
+ *
+ * Description: acquire a read lock.
+ *
+ * Arguments: rp: pointer to an rwl stucture
+ *
+ * Returns: 0 on success, -1 on failure.
+ */
+static int
+__rwl_acquire_read_lock( rwl *rp )
+{
+ if ( rp == NULL ) {
+ return -1;
+ }
+ PR_Lock( rp->rwl_writers_mutex );
+ PR_Lock( rp->rwl_readers_mutex );
+ rp->rwl_num_readers++;
+ (void)PR_Unlock( rp->rwl_readers_mutex );
+ (void)PR_Unlock( rp->rwl_writers_mutex );
+ return 0;
+}
+
+
+
+
+/*
+ * Function: __rwl_acquire_write_lock
+ *
+ * Description: acquire a write lock.
+ *
+ * Arguments: rp: pointer to an rwl stucture
+ *
+ * Returns: 0 on success, -1 on failure.
+ */
+static int
+__rwl_acquire_write_lock( rwl *rp )
+{
+ if ( rp == NULL ) {
+ return -1;
+ }
+ PR_Lock( rp->rwl_writers_mutex );
+ PR_Lock( rp->rwl_readers_mutex );
+ rp->rwl_writer_waiting = 1;
+ while ( rp->rwl_num_readers > 0 ) {
+ if ( PR_WaitCondVar( rp->rwl_writer_waiting_cv, PR_INTERVAL_NO_TIMEOUT ) != 0 ) {
+ (void)PR_Unlock( rp->rwl_writers_mutex );
+ (void)PR_Unlock( rp->rwl_readers_mutex );
+ return -1;
+ }
+ }
+ /* XXXggood should rwl_writer_waiting be set zero here? */
+ return 0;
+}
+
+
+
+
+/*
+ * Function: __rwl_relinquish_read_lock
+ *
+ * Description: relinquish a read lock.
+ *
+ * Arguments: rp: pointer to an rwl stucture
+ *
+ * Returns: 0 on success, -1 on failure.
+ */
+static int
+__rwl_relinquish_read_lock( rwl *rp )
+{
+ if ( rp == NULL ) {
+ return -1;
+ }
+ PR_Lock( rp->rwl_readers_mutex );
+ if ( --rp->rwl_num_readers == 0 && rp->rwl_writer_waiting ) {
+ PR_NotifyCondVar( rp->rwl_writer_waiting_cv );
+ }
+ (void)PR_Unlock( rp->rwl_readers_mutex );
+ return 0;
+}
+
+
+
+
+/*
+ * Function: __rwl_relinquish_write_lock
+ *
+ * Description: relinquish a write lock.
+ *
+ * Arguments: rp: pointer to an rwl stucture
+ *
+ * Returns: 0 on success, -1 on failure.
+ */
+static int
+__rwl_relinquish_write_lock( rwl *rp )
+{
+ if ( rp == NULL ) {
+ return -1;
+ }
+ rp->rwl_writer_waiting = 0;
+ (void)PR_Unlock( rp->rwl_readers_mutex );
+ (void)PR_Unlock( rp->rwl_writers_mutex );
+ return 0;
+}
+
+
+
+/*
+ * Function: rwl_new
+ *
+ * Description: allocate and initialize a wrl structure.
+ *
+ * Arguments: none
+ *
+ * Returns: on success, returns a pointer to an allocated, initialized rwl structure.
+ * on failure, returns NULL.
+ *
+ */
+rwl *
+rwl_new()
+{
+ rwl *rp;
+
+ if (( rp = (rwl *)malloc( sizeof( rwl ))) == NULL ) {
+ return NULL;
+ }
+
+ if (( rp->rwl_readers_mutex = PR_NewLock()) == NULL ) {
+ free( rp );
+ return NULL;
+ }
+ if (( rp->rwl_writers_mutex = PR_NewLock()) == NULL ) {
+ PR_DestroyLock( rp->rwl_readers_mutex );
+ free( rp );
+ return NULL;
+ }
+ if (( rp->rwl_writer_waiting_cv = PR_NewCondVar( rp->rwl_readers_mutex )) == NULL ) {
+ PR_DestroyLock( rp->rwl_readers_mutex );
+ PR_DestroyLock( rp->rwl_writers_mutex );
+ free( rp );
+ }
+ rp->rwl_num_readers = rp->rwl_writer_waiting = 0;
+
+ rp->rwl_acquire_read_lock = __rwl_acquire_read_lock;
+ rp->rwl_relinquish_read_lock = __rwl_relinquish_read_lock;
+
+ rp->rwl_acquire_write_lock = __rwl_acquire_write_lock;
+ rp->rwl_relinquish_write_lock = __rwl_relinquish_write_lock;
+
+ return rp;
+}
+
+
+
+
+/*
+ * Function: rwl_free
+ *
+ * Description: deallocates and frees an rwl structure.
+ *
+ * Arguments: rh: handle to an rwl structure.
+ *
+ * Returns: nothing
+ */
+void
+rwl_free( rwl **rh )
+{
+ rwl *rp;
+
+ if ( rh == NULL || *rh == NULL ) {
+ return;
+ }
+ rp = *rh;
+
+ if ( rp->rwl_readers_mutex != NULL ) {
+ PR_DestroyLock( rp->rwl_readers_mutex );
+ }
+ if ( rp->rwl_writers_mutex != NULL ) {
+ PR_DestroyLock( rp->rwl_writers_mutex );
+ }
+ if ( rp->rwl_writer_waiting_cv != NULL ) {
+ PR_DestroyCondVar( rp->rwl_writer_waiting_cv );
+ }
+ memset( rp, '\0', sizeof( rwl ));
+ free( rp );
+ *rh = NULL;
+}