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