1/* $OpenLDAP$ */ 2/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 3 * 4 * Copyright 2006-2011 The OpenLDAP Foundation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted only as authorized by the OpenLDAP 9 * Public License. 10 * 11 * A copy of this license is available in file LICENSE in the 12 * top-level directory of the distribution or, alternatively, at 13 * <http://www.OpenLDAP.org/license.html>. 14 */ 15/* This work was initially developed by Howard Chu for inclusion 16 * in OpenLDAP Software. 17 */ 18 19/* 20 * This is an implementation of recursive mutexes. 21 */ 22 23#include "portable.h" 24 25#include <ac/stdlib.h> 26 27#include <ac/errno.h> 28#include <ac/string.h> 29#include <ac/time.h> 30 31#include "ldap-int.h" 32#include "ldap_pvt_thread.h" /* Get the thread interface */ 33 34struct ldap_int_thread_rmutex_s { 35 ldap_pvt_thread_mutex_t ltrm_mutex; 36 ldap_pvt_thread_cond_t ltrm_cond; 37 ldap_pvt_thread_t ltrm_owner; 38 int ltrm_valid; 39#define LDAP_PVT_THREAD_RMUTEX_VALID 0x0cdb 40 int ltrm_depth; 41 int ltrm_waits; 42}; 43 44static const ldap_pvt_thread_t tid_zero; 45 46int 47ldap_pvt_thread_rmutex_init( ldap_pvt_thread_rmutex_t *rmutex ) 48{ 49 struct ldap_int_thread_rmutex_s *rm; 50 51 assert( rmutex != NULL ); 52 53 rm = (struct ldap_int_thread_rmutex_s *) LDAP_CALLOC( 1, 54 sizeof( struct ldap_int_thread_rmutex_s ) ); 55 if ( !rm ) 56 return LDAP_NO_MEMORY; 57 58 /* we should check return results */ 59 ldap_pvt_thread_mutex_init( &rm->ltrm_mutex ); 60 ldap_pvt_thread_cond_init( &rm->ltrm_cond ); 61 62 rm->ltrm_valid = LDAP_PVT_THREAD_RMUTEX_VALID; 63 64 *rmutex = rm; 65 return 0; 66} 67 68int 69ldap_pvt_thread_rmutex_destroy( ldap_pvt_thread_rmutex_t *rmutex ) 70{ 71 struct ldap_int_thread_rmutex_s *rm; 72 73 assert( rmutex != NULL ); 74 rm = *rmutex; 75 76 assert( rm != NULL ); 77 assert( rm->ltrm_valid == LDAP_PVT_THREAD_RMUTEX_VALID ); 78 79 if( rm->ltrm_valid != LDAP_PVT_THREAD_RMUTEX_VALID ) 80 return LDAP_PVT_THREAD_EINVAL; 81 82 ldap_pvt_thread_mutex_lock( &rm->ltrm_mutex ); 83 84 assert( rm->ltrm_depth >= 0 ); 85 assert( rm->ltrm_waits >= 0 ); 86 87 /* in use? */ 88 if( rm->ltrm_depth > 0 || rm->ltrm_waits > 0 ) { 89 ldap_pvt_thread_mutex_unlock( &rm->ltrm_mutex ); 90 return LDAP_PVT_THREAD_EBUSY; 91 } 92 93 rm->ltrm_valid = 0; 94 95 ldap_pvt_thread_mutex_unlock( &rm->ltrm_mutex ); 96 97 ldap_pvt_thread_mutex_destroy( &rm->ltrm_mutex ); 98 ldap_pvt_thread_cond_destroy( &rm->ltrm_cond ); 99 100 LDAP_FREE(rm); 101 *rmutex = NULL; 102 return 0; 103} 104 105int ldap_pvt_thread_rmutex_lock( ldap_pvt_thread_rmutex_t *rmutex, 106 ldap_pvt_thread_t owner ) 107{ 108 struct ldap_int_thread_rmutex_s *rm; 109 110 assert( rmutex != NULL ); 111 rm = *rmutex; 112 113 assert( rm != NULL ); 114 assert( rm->ltrm_valid == LDAP_PVT_THREAD_RMUTEX_VALID ); 115 116 if( rm->ltrm_valid != LDAP_PVT_THREAD_RMUTEX_VALID ) 117 return LDAP_PVT_THREAD_EINVAL; 118 119 ldap_pvt_thread_mutex_lock( &rm->ltrm_mutex ); 120 121 assert( rm->ltrm_depth >= 0 ); 122 assert( rm->ltrm_waits >= 0 ); 123 124 if( rm->ltrm_depth > 0 ) { 125 /* already locked */ 126 if ( !ldap_pvt_thread_equal( rm->ltrm_owner, owner )) { 127 rm->ltrm_waits++; 128 do { 129 ldap_pvt_thread_cond_wait( &rm->ltrm_cond, 130 &rm->ltrm_mutex ); 131 } while( rm->ltrm_depth > 0 ); 132 133 rm->ltrm_waits--; 134 assert( rm->ltrm_waits >= 0 ); 135 rm->ltrm_owner = owner; 136 } 137 } else { 138 rm->ltrm_owner = owner; 139 } 140 141 rm->ltrm_depth++; 142 143 ldap_pvt_thread_mutex_unlock( &rm->ltrm_mutex ); 144 145 return 0; 146} 147 148int ldap_pvt_thread_rmutex_trylock( ldap_pvt_thread_rmutex_t *rmutex, 149 ldap_pvt_thread_t owner ) 150{ 151 struct ldap_int_thread_rmutex_s *rm; 152 153 assert( rmutex != NULL ); 154 rm = *rmutex; 155 156 assert( rm != NULL ); 157 assert( rm->ltrm_valid == LDAP_PVT_THREAD_RMUTEX_VALID ); 158 159 if( rm->ltrm_valid != LDAP_PVT_THREAD_RMUTEX_VALID ) 160 return LDAP_PVT_THREAD_EINVAL; 161 162 ldap_pvt_thread_mutex_lock( &rm->ltrm_mutex ); 163 164 assert( rm->ltrm_depth >= 0 ); 165 assert( rm->ltrm_waits >= 0 ); 166 167 if( rm->ltrm_depth > 0 ) { 168 if ( !ldap_pvt_thread_equal( owner, rm->ltrm_owner )) { 169 ldap_pvt_thread_mutex_unlock( &rm->ltrm_mutex ); 170 return LDAP_PVT_THREAD_EBUSY; 171 } 172 } else { 173 rm->ltrm_owner = owner; 174 } 175 176 rm->ltrm_depth++; 177 178 ldap_pvt_thread_mutex_unlock( &rm->ltrm_mutex ); 179 180 return 0; 181} 182 183int ldap_pvt_thread_rmutex_unlock( ldap_pvt_thread_rmutex_t *rmutex, 184 ldap_pvt_thread_t owner ) 185{ 186 struct ldap_int_thread_rmutex_s *rm; 187 188 assert( rmutex != NULL ); 189 rm = *rmutex; 190 191 assert( rm != NULL ); 192 assert( rm->ltrm_valid == LDAP_PVT_THREAD_RMUTEX_VALID ); 193 194 if( rm->ltrm_valid != LDAP_PVT_THREAD_RMUTEX_VALID ) 195 return LDAP_PVT_THREAD_EINVAL; 196 197 ldap_pvt_thread_mutex_lock( &rm->ltrm_mutex ); 198 199 if( !ldap_pvt_thread_equal( owner, rm->ltrm_owner )) { 200 ldap_pvt_thread_mutex_unlock( &rm->ltrm_mutex ); 201 return LDAP_PVT_THREAD_EINVAL; 202 } 203 204 rm->ltrm_depth--; 205 if ( !rm->ltrm_depth ) 206 rm->ltrm_owner = tid_zero; 207 208 assert( rm->ltrm_depth >= 0 ); 209 assert( rm->ltrm_waits >= 0 ); 210 211 if ( !rm->ltrm_depth && rm->ltrm_waits ) { 212 ldap_pvt_thread_cond_signal( &rm->ltrm_cond ); 213 } 214 215 ldap_pvt_thread_mutex_unlock( &rm->ltrm_mutex ); 216 217 return 0; 218} 219 220