From 0a7808fbad2534c7f300d26f9b1d4ea14dad8dae Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Fri, 28 Apr 2006 20:12:45 +0000 Subject: [PATCH] Added recursive mutex implementation --- include/ldap_int_thread.h | 1 + include/ldap_pvt_thread.h | 16 +++ libraries/libldap_r/Makefile.in | 4 +- libraries/libldap_r/rmutex.c | 225 ++++++++++++++++++++++++++++++++ libraries/libldap_r/threads.c | 9 ++ 5 files changed, 253 insertions(+), 2 deletions(-) create mode 100644 libraries/libldap_r/rmutex.c 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; } -- 2.39.5