diff --git a/include/ldap_int_thread.h b/include/ldap_int_thread.h
index ccf293bf2a..46c79ae8de 100644
--- a/include/ldap_int_thread.h
+++ b/include/ldap_int_thread.h
@@ -227,6 +227,7 @@ LDAP_F(int) ldap_int_thread_pool_shutdown ( void );
typedef struct ldap_int_thread_pool_s * ldap_int_thread_pool_t;
#endif
+typedef struct ldap_int_thread_rmutex_s * ldap_int_thread_rmutex_t;
LDAP_END_DECL
diff --git a/include/ldap_pvt_thread.h b/include/ldap_pvt_thread.h
index 3f2d48fb11..76a371ebf5 100644
--- a/include/ldap_pvt_thread.h
+++ b/include/ldap_pvt_thread.h
@@ -33,6 +33,7 @@ typedef ldap_int_thread_mutex_t ldap_pvt_thread_mutex_t;
typedef ldap_int_thread_cond_t ldap_pvt_thread_cond_t;
typedef ldap_int_thread_rdwr_t ldap_pvt_thread_rdwr_t;
#endif
+typedef ldap_int_thread_rmutex_t ldap_pvt_thread_rmutex_t;
#endif /* !LDAP_PVT_THREAD_H_DONE */
#if 0 && defined(LDAP_DEVEL)
@@ -122,6 +123,21 @@ ldap_pvt_thread_mutex_trylock LDAP_P(( ldap_pvt_thread_mutex_t *mutex ));
LDAP_F( int )
ldap_pvt_thread_mutex_unlock LDAP_P(( ldap_pvt_thread_mutex_t *mutex ));
+LDAP_F( int )
+ldap_pvt_thread_rmutex_init LDAP_P(( ldap_pvt_thread_rmutex_t *rmutex ));
+
+LDAP_F( int )
+ldap_pvt_thread_rmutex_destroy LDAP_P(( ldap_pvt_thread_rmutex_t *rmutex ));
+
+LDAP_F( int )
+ldap_pvt_thread_rmutex_lock LDAP_P(( ldap_pvt_thread_rmutex_t *rmutex ));
+
+LDAP_F( int )
+ldap_pvt_thread_rmutex_trylock LDAP_P(( ldap_pvt_thread_rmutex_t *rmutex ));
+
+LDAP_F( int )
+ldap_pvt_thread_rmutex_unlock LDAP_P(( ldap_pvt_thread_rmutex_t *rmutex ));
+
LDAP_F( ldap_pvt_thread_t )
ldap_pvt_thread_self LDAP_P(( void ));
diff --git a/libraries/libldap_r/Makefile.in b/libraries/libldap_r/Makefile.in
index 7ad2ceca35..2629234e0f 100644
--- a/libraries/libldap_r/Makefile.in
+++ b/libraries/libldap_r/Makefile.in
@@ -29,10 +29,10 @@ XXSRCS = apitest.c test.c \
init.c options.c print.c string.c util-int.c schema.c \
charray.c tls.c os-local.c dnssrv.c utf-8.c utf-8-conv.c \
turn.c ppolicy.c dds.c txn.c
-SRCS = threads.c rdwr.c tpool.c rq.c \
+SRCS = threads.c rdwr.c rmutex.c tpool.c rq.c \
thr_posix.c thr_cthreads.c thr_thr.c thr_lwp.c thr_nt.c \
thr_pth.c thr_stub.c thr_debug.c
-OBJS = threads.lo rdwr.lo tpool.lo rq.lo \
+OBJS = threads.lo rdwr.lo rmutex.lo tpool.lo rq.lo \
thr_posix.lo thr_cthreads.lo thr_thr.lo thr_lwp.lo thr_nt.lo \
thr_pth.lo thr_stub.lo thr_debug.lo \
bind.lo open.lo result.lo error.lo compare.lo search.lo \
diff --git a/libraries/libldap_r/rmutex.c b/libraries/libldap_r/rmutex.c
new file mode 100644
index 0000000000..eb04f5674d
--- /dev/null
+++ b/libraries/libldap_r/rmutex.c
@@ -0,0 +1,225 @@
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software .
+ *
+ * Copyright 2006 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * .
+ */
+/* This work was initially developed by Howard Chu for inclusion
+ * in OpenLDAP Software.
+ */
+
+/*
+ * This is an implementation of recursive mutexes.
+ */
+
+#include "portable.h"
+
+#include
+
+#include
+#include
+#include
+
+#include "ldap-int.h"
+#include "ldap_pvt_thread.h" /* Get the thread interface */
+
+struct ldap_int_thread_rmutex_s {
+ ldap_pvt_thread_mutex_t ltrm_mutex;
+ ldap_pvt_thread_cond_t ltrm_cond;
+ ldap_pvt_thread_t ltrm_owner;
+ int ltrm_valid;
+#define LDAP_PVT_THREAD_RMUTEX_VALID 0x0cdb
+ int ltrm_depth;
+ int ltrm_waits;
+};
+
+static const ldap_pvt_thread_t tid_zero;
+
+int
+ldap_pvt_thread_rmutex_init( ldap_pvt_thread_rmutex_t *rmutex )
+{
+ struct ldap_int_thread_rmutex_s *rm;
+
+ assert( rmutex != NULL );
+
+ rm = (struct ldap_int_thread_rmutex_s *) LDAP_CALLOC( 1,
+ sizeof( struct ldap_int_thread_rmutex_s ) );
+ if ( !rm )
+ return LDAP_NO_MEMORY;
+
+ /* we should check return results */
+ ldap_pvt_thread_mutex_init( &rm->ltrm_mutex );
+ ldap_pvt_thread_cond_init( &rm->ltrm_cond );
+
+ rm->ltrm_valid = LDAP_PVT_THREAD_RMUTEX_VALID;
+
+ *rmutex = rm;
+ return 0;
+}
+
+int
+ldap_pvt_thread_rmutex_destroy( ldap_pvt_thread_rmutex_t *rmutex )
+{
+ struct ldap_int_thread_rmutex_s *rm;
+
+ assert( rmutex != NULL );
+ rm = *rmutex;
+
+ assert( rm != NULL );
+ assert( rm->ltrm_valid == LDAP_PVT_THREAD_RMUTEX_VALID );
+
+ if( rm->ltrm_valid != LDAP_PVT_THREAD_RMUTEX_VALID )
+ return LDAP_PVT_THREAD_EINVAL;
+
+ ldap_pvt_thread_mutex_lock( &rm->ltrm_mutex );
+
+ assert( rm->ltrm_depth >= 0 );
+ assert( rm->ltrm_waits >= 0 );
+
+ /* in use? */
+ if( rm->ltrm_depth > 0 || rm->ltrm_waits > 0 ) {
+ ldap_pvt_thread_mutex_unlock( &rm->ltrm_mutex );
+ return LDAP_PVT_THREAD_EBUSY;
+ }
+
+ rm->ltrm_valid = 0;
+
+ ldap_pvt_thread_mutex_unlock( &rm->ltrm_mutex );
+
+ ldap_pvt_thread_mutex_destroy( &rm->ltrm_mutex );
+ ldap_pvt_thread_cond_destroy( &rm->ltrm_cond );
+
+ LDAP_FREE(rm);
+ *rmutex = NULL;
+ return 0;
+}
+
+int ldap_pvt_thread_rmutex_lock( ldap_pvt_thread_rmutex_t *rmutex )
+{
+ struct ldap_int_thread_rmutex_s *rm;
+ ldap_pvt_thread_t tid;
+
+ assert( rmutex != NULL );
+ rm = *rmutex;
+
+ assert( rm != NULL );
+ assert( rm->ltrm_valid == LDAP_PVT_THREAD_RMUTEX_VALID );
+
+ if( rm->ltrm_valid != LDAP_PVT_THREAD_RMUTEX_VALID )
+ return LDAP_PVT_THREAD_EINVAL;
+
+ ldap_pvt_thread_mutex_lock( &rm->ltrm_mutex );
+
+ assert( rm->ltrm_depth >= 0 );
+ assert( rm->ltrm_waits >= 0 );
+
+ tid = ldap_pvt_thread_self();
+
+ if( rm->ltrm_depth > 0 ) {
+ /* already locked */
+ if ( !ldap_pvt_thread_equal( rm->ltrm_owner, tid )) {
+ rm->ltrm_waits++;
+ do {
+ ldap_pvt_thread_cond_wait( &rm->ltrm_cond,
+ &rm->ltrm_mutex );
+ } while( rm->ltrm_depth > 0 );
+
+ rm->ltrm_waits--;
+ assert( rm->ltrm_waits >= 0 );
+ rm->ltrm_owner = tid;
+ }
+ } else {
+ rm->ltrm_owner = tid;
+ }
+
+ rm->ltrm_depth++;
+
+ ldap_pvt_thread_mutex_unlock( &rm->ltrm_mutex );
+
+ return 0;
+}
+
+int ldap_pvt_thread_rmutex_trylock( ldap_pvt_thread_rmutex_t *rmutex )
+{
+ struct ldap_int_thread_rmutex_s *rm;
+ ldap_pvt_thread_t tid;
+
+ assert( rmutex != NULL );
+ rm = *rmutex;
+
+ assert( rm != NULL );
+ assert( rm->ltrm_valid == LDAP_PVT_THREAD_RMUTEX_VALID );
+
+ if( rm->ltrm_valid != LDAP_PVT_THREAD_RMUTEX_VALID )
+ return LDAP_PVT_THREAD_EINVAL;
+
+ ldap_pvt_thread_mutex_lock( &rm->ltrm_mutex );
+
+ assert( rm->ltrm_depth >= 0 );
+ assert( rm->ltrm_waits >= 0 );
+
+ tid = ldap_pvt_thread_self();
+
+ if( rm->ltrm_depth > 0 ) {
+ if ( !ldap_pvt_thread_equal( tid, rm->ltrm_owner )) {
+ ldap_pvt_thread_mutex_unlock( &rm->ltrm_mutex );
+ return LDAP_PVT_THREAD_EBUSY;
+ }
+ } else {
+ rm->ltrm_owner = tid;
+ }
+
+ rm->ltrm_depth++;
+
+ ldap_pvt_thread_mutex_unlock( &rm->ltrm_mutex );
+
+ return 0;
+}
+
+int ldap_pvt_thread_rmutex_unlock( ldap_pvt_thread_rmutex_t *rmutex )
+{
+ struct ldap_int_thread_rmutex_s *rm;
+ ldap_pvt_thread_t tid;
+
+ assert( rmutex != NULL );
+ rm = *rmutex;
+
+ assert( rm != NULL );
+ assert( rm->ltrm_valid == LDAP_PVT_THREAD_RMUTEX_VALID );
+
+ if( rm->ltrm_valid != LDAP_PVT_THREAD_RMUTEX_VALID )
+ return LDAP_PVT_THREAD_EINVAL;
+
+ ldap_pvt_thread_mutex_lock( &rm->ltrm_mutex );
+
+ tid = ldap_pvt_thread_self();
+
+ if( !ldap_pvt_thread_equal( tid, rm->ltrm_owner )) {
+ ldap_pvt_thread_mutex_unlock( &rm->ltrm_mutex );
+ return LDAP_PVT_THREAD_EINVAL;
+ }
+
+ rm->ltrm_depth--;
+ if ( !rm->ltrm_depth )
+ rm->ltrm_owner = tid_zero;
+
+ assert( rm->ltrm_depth >= 0 );
+ assert( rm->ltrm_waits >= 0 );
+
+ if ( !rm->ltrm_depth && rm->ltrm_waits ) {
+ ldap_pvt_thread_cond_signal( &rm->ltrm_cond );
+ }
+
+ ldap_pvt_thread_mutex_unlock( &rm->ltrm_mutex );
+
+ return 0;
+}
+
diff --git a/libraries/libldap_r/threads.c b/libraries/libldap_r/threads.c
index 9caee1469b..c810ad56be 100644
--- a/libraries/libldap_r/threads.c
+++ b/libraries/libldap_r/threads.c
@@ -38,6 +38,7 @@ int ldap_pvt_thread_initialize( void )
{
int rc;
static int init = 0;
+ ldap_pvt_thread_rmutex_t rm;
/* we only get one shot at this */
if( init++ ) return -1;
@@ -50,6 +51,14 @@ int ldap_pvt_thread_initialize( void )
if( rc ) return rc;
#endif
+ /* kludge to pull symbol definitions in */
+ ldap_pvt_thread_rmutex_init( &rm );
+ ldap_pvt_thread_rmutex_lock( &rm );
+ ldap_pvt_thread_rmutex_trylock( &rm );
+ ldap_pvt_thread_rmutex_unlock( &rm );
+ ldap_pvt_thread_rmutex_unlock( &rm );
+ ldap_pvt_thread_rmutex_destroy( &rm );
+
return 0;
}