Back to index

openldap  2.4.31
rmutex.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 2006-2012 The OpenLDAP Foundation.
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted only as authorized by the OpenLDAP
00009  * Public License.
00010  *
00011  * A copy of this license is available in file LICENSE in the
00012  * top-level directory of the distribution or, alternatively, at
00013  * <http://www.OpenLDAP.org/license.html>.
00014  */
00015 /* This work was initially developed by Howard Chu for inclusion
00016  * in OpenLDAP Software.
00017  */
00018 
00019 /*
00020  * This is an implementation of recursive mutexes.
00021  */
00022 
00023 #include "portable.h"
00024 
00025 #include <ac/stdlib.h>
00026 
00027 #include <ac/errno.h>
00028 #include <ac/string.h>
00029 #include <ac/time.h>
00030 
00031 #include "ldap-int.h"
00032 #include "ldap_pvt_thread.h" /* Get the thread interface */
00033 
00034 struct ldap_int_thread_rmutex_s {
00035        ldap_pvt_thread_mutex_t ltrm_mutex;
00036        ldap_pvt_thread_cond_t ltrm_cond;
00037        ldap_pvt_thread_t ltrm_owner;
00038        int ltrm_valid;
00039 #define LDAP_PVT_THREAD_RMUTEX_VALID      0x0cdb
00040        int ltrm_depth;
00041        int ltrm_waits;
00042 };
00043 
00044 static const ldap_pvt_thread_t tid_zero;
00045 
00046 int 
00047 ldap_pvt_thread_rmutex_init( ldap_pvt_thread_rmutex_t *rmutex )
00048 {
00049        struct ldap_int_thread_rmutex_s *rm;
00050 
00051        assert( rmutex != NULL );
00052 
00053        rm = (struct ldap_int_thread_rmutex_s *) LDAP_CALLOC( 1,
00054               sizeof( struct ldap_int_thread_rmutex_s ) );
00055        if ( !rm )
00056               return LDAP_NO_MEMORY;
00057 
00058        /* we should check return results */
00059        ldap_pvt_thread_mutex_init( &rm->ltrm_mutex );
00060        ldap_pvt_thread_cond_init( &rm->ltrm_cond );
00061 
00062        rm->ltrm_valid = LDAP_PVT_THREAD_RMUTEX_VALID;
00063 
00064        *rmutex = rm;
00065        return 0;
00066 }
00067 
00068 int 
00069 ldap_pvt_thread_rmutex_destroy( ldap_pvt_thread_rmutex_t *rmutex )
00070 {
00071        struct ldap_int_thread_rmutex_s *rm;
00072 
00073        assert( rmutex != NULL );
00074        rm = *rmutex;
00075 
00076        assert( rm != NULL );
00077        assert( rm->ltrm_valid == LDAP_PVT_THREAD_RMUTEX_VALID );
00078 
00079        if( rm->ltrm_valid != LDAP_PVT_THREAD_RMUTEX_VALID )
00080               return LDAP_PVT_THREAD_EINVAL;
00081 
00082        ldap_pvt_thread_mutex_lock( &rm->ltrm_mutex );
00083 
00084        assert( rm->ltrm_depth >= 0 );
00085        assert( rm->ltrm_waits >= 0 );
00086 
00087        /* in use? */
00088        if( rm->ltrm_depth > 0 || rm->ltrm_waits > 0 ) {
00089               ldap_pvt_thread_mutex_unlock( &rm->ltrm_mutex );
00090               return LDAP_PVT_THREAD_EBUSY;
00091        }
00092 
00093        rm->ltrm_valid = 0;
00094 
00095        ldap_pvt_thread_mutex_unlock( &rm->ltrm_mutex );
00096 
00097        ldap_pvt_thread_mutex_destroy( &rm->ltrm_mutex );
00098        ldap_pvt_thread_cond_destroy( &rm->ltrm_cond );
00099 
00100        LDAP_FREE(rm);
00101        *rmutex = NULL;
00102        return 0;
00103 }
00104 
00105 int ldap_pvt_thread_rmutex_lock( ldap_pvt_thread_rmutex_t *rmutex,
00106        ldap_pvt_thread_t owner )
00107 {
00108        struct ldap_int_thread_rmutex_s *rm;
00109 
00110        assert( rmutex != NULL );
00111        rm = *rmutex;
00112 
00113        assert( rm != NULL );
00114        assert( rm->ltrm_valid == LDAP_PVT_THREAD_RMUTEX_VALID );
00115 
00116        if( rm->ltrm_valid != LDAP_PVT_THREAD_RMUTEX_VALID )
00117               return LDAP_PVT_THREAD_EINVAL;
00118 
00119        ldap_pvt_thread_mutex_lock( &rm->ltrm_mutex );
00120 
00121        assert( rm->ltrm_depth >= 0 );
00122        assert( rm->ltrm_waits >= 0 );
00123 
00124        if( rm->ltrm_depth > 0 ) {
00125               /* already locked */
00126               if ( !ldap_pvt_thread_equal( rm->ltrm_owner, owner )) {
00127                      rm->ltrm_waits++;
00128                      do {
00129                             ldap_pvt_thread_cond_wait( &rm->ltrm_cond,
00130                                    &rm->ltrm_mutex );
00131                      } while( rm->ltrm_depth > 0 );
00132 
00133                      rm->ltrm_waits--;
00134                      assert( rm->ltrm_waits >= 0 );
00135                      rm->ltrm_owner = owner;
00136               }
00137        } else {
00138               rm->ltrm_owner = owner;
00139        }
00140 
00141        rm->ltrm_depth++;
00142 
00143        ldap_pvt_thread_mutex_unlock( &rm->ltrm_mutex );
00144 
00145        return 0;
00146 }
00147 
00148 int ldap_pvt_thread_rmutex_trylock( ldap_pvt_thread_rmutex_t *rmutex,
00149        ldap_pvt_thread_t owner )
00150 {
00151        struct ldap_int_thread_rmutex_s *rm;
00152 
00153        assert( rmutex != NULL );
00154        rm = *rmutex;
00155 
00156        assert( rm != NULL );
00157        assert( rm->ltrm_valid == LDAP_PVT_THREAD_RMUTEX_VALID );
00158 
00159        if( rm->ltrm_valid != LDAP_PVT_THREAD_RMUTEX_VALID )
00160               return LDAP_PVT_THREAD_EINVAL;
00161 
00162        ldap_pvt_thread_mutex_lock( &rm->ltrm_mutex );
00163 
00164        assert( rm->ltrm_depth >= 0 );
00165        assert( rm->ltrm_waits >= 0 );
00166 
00167        if( rm->ltrm_depth > 0 ) {
00168               if ( !ldap_pvt_thread_equal( owner, rm->ltrm_owner )) {
00169                      ldap_pvt_thread_mutex_unlock( &rm->ltrm_mutex );
00170                      return LDAP_PVT_THREAD_EBUSY;
00171               }
00172        } else {
00173               rm->ltrm_owner = owner;
00174        }
00175 
00176        rm->ltrm_depth++;
00177 
00178        ldap_pvt_thread_mutex_unlock( &rm->ltrm_mutex );
00179 
00180        return 0;
00181 }
00182 
00183 int ldap_pvt_thread_rmutex_unlock( ldap_pvt_thread_rmutex_t *rmutex,
00184        ldap_pvt_thread_t owner )
00185 {
00186        struct ldap_int_thread_rmutex_s *rm;
00187 
00188        assert( rmutex != NULL );
00189        rm = *rmutex;
00190 
00191        assert( rm != NULL );
00192        assert( rm->ltrm_valid == LDAP_PVT_THREAD_RMUTEX_VALID );
00193 
00194        if( rm->ltrm_valid != LDAP_PVT_THREAD_RMUTEX_VALID )
00195               return LDAP_PVT_THREAD_EINVAL;
00196 
00197        ldap_pvt_thread_mutex_lock( &rm->ltrm_mutex );
00198 
00199        if( !ldap_pvt_thread_equal( owner, rm->ltrm_owner )) {
00200               ldap_pvt_thread_mutex_unlock( &rm->ltrm_mutex );
00201               return LDAP_PVT_THREAD_EINVAL;
00202        }
00203 
00204        rm->ltrm_depth--;
00205        if ( !rm->ltrm_depth )
00206               rm->ltrm_owner = tid_zero;
00207 
00208        assert( rm->ltrm_depth >= 0 );
00209        assert( rm->ltrm_waits >= 0 );
00210 
00211        if ( !rm->ltrm_depth && rm->ltrm_waits ) {
00212               ldap_pvt_thread_cond_signal( &rm->ltrm_cond );
00213        }
00214 
00215        ldap_pvt_thread_mutex_unlock( &rm->ltrm_mutex );
00216 
00217        return 0;
00218 }
00219