1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996,2008 Oracle. All rights reserved. 5 * 6 * $Id: mut_method.c,v 12.17 2008/01/08 20:58:43 bostic Exp $ 7 */ 8 9#include "db_config.h" 10 11#include "db_int.h" 12#include "dbinc/mutex_int.h" 13 14/* 15 * __mutex_alloc_pp -- 16 * Allocate a mutex, application method. 17 * 18 * PUBLIC: int __mutex_alloc_pp __P((DB_ENV *, u_int32_t, db_mutex_t *)); 19 */ 20int 21__mutex_alloc_pp(dbenv, flags, indxp) 22 DB_ENV *dbenv; 23 u_int32_t flags; 24 db_mutex_t *indxp; 25{ 26 DB_THREAD_INFO *ip; 27 ENV *env; 28 int ret; 29 30 env = dbenv->env; 31 32 switch (flags) { 33 case 0: 34 case DB_MUTEX_PROCESS_ONLY: 35 case DB_MUTEX_SELF_BLOCK: 36 break; 37 default: 38 return (__db_ferr(env, "DB_ENV->mutex_alloc", 0)); 39 } 40 41 ENV_ENTER(env, ip); 42 ret = __mutex_alloc(env, MTX_APPLICATION, flags, indxp); 43 ENV_LEAVE(env, ip); 44 45 return (ret); 46} 47 48/* 49 * __mutex_free_pp -- 50 * Destroy a mutex, application method. 51 * 52 * PUBLIC: int __mutex_free_pp __P((DB_ENV *, db_mutex_t)); 53 */ 54int 55__mutex_free_pp(dbenv, indx) 56 DB_ENV *dbenv; 57 db_mutex_t indx; 58{ 59 DB_THREAD_INFO *ip; 60 ENV *env; 61 int ret; 62 63 env = dbenv->env; 64 65 if (indx == MUTEX_INVALID) 66 return (EINVAL); 67 68 /* 69 * Internally Berkeley DB passes around the db_mutex_t address on 70 * free, because we want to make absolutely sure the slot gets 71 * overwritten with MUTEX_INVALID. We don't export MUTEX_INVALID, 72 * so we don't export that part of the API, either. 73 */ 74 ENV_ENTER(env, ip); 75 ret = __mutex_free(env, &indx); 76 ENV_LEAVE(env, ip); 77 78 return (ret); 79} 80 81/* 82 * __mutex_lock -- 83 * Lock a mutex, application method. 84 * 85 * PUBLIC: int __mutex_lock_pp __P((DB_ENV *, db_mutex_t)); 86 */ 87int 88__mutex_lock_pp(dbenv, indx) 89 DB_ENV *dbenv; 90 db_mutex_t indx; 91{ 92 DB_THREAD_INFO *ip; 93 ENV *env; 94 int ret; 95 96 env = dbenv->env; 97 98 if (indx == MUTEX_INVALID) 99 return (EINVAL); 100 101 ENV_ENTER(env, ip); 102 ret = __mutex_lock(env, indx); 103 ENV_LEAVE(env, ip); 104 return (ret); 105} 106 107/* 108 * __mutex_unlock -- 109 * Unlock a mutex, application method. 110 * 111 * PUBLIC: int __mutex_unlock_pp __P((DB_ENV *, db_mutex_t)); 112 */ 113int 114__mutex_unlock_pp(dbenv, indx) 115 DB_ENV *dbenv; 116 db_mutex_t indx; 117{ 118 DB_THREAD_INFO *ip; 119 ENV *env; 120 int ret; 121 122 env = dbenv->env; 123 124 if (indx == MUTEX_INVALID) 125 return (EINVAL); 126 127 ENV_ENTER(env, ip); 128 ret = __mutex_unlock(env, indx); 129 ENV_LEAVE(env, ip); 130 return (ret); 131} 132 133/* 134 * __mutex_get_align -- 135 * DB_ENV->mutex_get_align. 136 * 137 * PUBLIC: int __mutex_get_align __P((DB_ENV *, u_int32_t *)); 138 */ 139int 140__mutex_get_align(dbenv, alignp) 141 DB_ENV *dbenv; 142 u_int32_t *alignp; 143{ 144 ENV *env; 145 146 env = dbenv->env; 147 148 if (MUTEX_ON(env)) { 149 /* Cannot be set after open, no lock required to read. */ 150 *alignp = ((DB_MUTEXREGION *) 151 env->mutex_handle->reginfo.primary)->stat.st_mutex_align; 152 } else 153 *alignp = dbenv->mutex_align; 154 return (0); 155} 156 157/* 158 * __mutex_set_align -- 159 * DB_ENV->mutex_set_align. 160 * 161 * PUBLIC: int __mutex_set_align __P((DB_ENV *, u_int32_t)); 162 */ 163int 164__mutex_set_align(dbenv, align) 165 DB_ENV *dbenv; 166 u_int32_t align; 167{ 168 ENV *env; 169 170 env = dbenv->env; 171 172 ENV_ILLEGAL_AFTER_OPEN(env, "DB_ENV->set_mutex_align"); 173 174 if (align == 0 || !POWER_OF_TWO(align)) { 175 __db_errx(env, 176 "DB_ENV->mutex_set_align: alignment value must be a non-zero power-of-two"); 177 return (EINVAL); 178 } 179 180 dbenv->mutex_align = align; 181 return (0); 182} 183 184/* 185 * __mutex_get_increment -- 186 * DB_ENV->mutex_get_increment. 187 * 188 * PUBLIC: int __mutex_get_increment __P((DB_ENV *, u_int32_t *)); 189 */ 190int 191__mutex_get_increment(dbenv, incrementp) 192 DB_ENV *dbenv; 193 u_int32_t *incrementp; 194{ 195 /* 196 * We don't maintain the increment in the region (it just makes 197 * no sense). Return whatever we have configured on this handle, 198 * nobody is ever going to notice. 199 */ 200 *incrementp = dbenv->mutex_inc; 201 return (0); 202} 203 204/* 205 * __mutex_set_increment -- 206 * DB_ENV->mutex_set_increment. 207 * 208 * PUBLIC: int __mutex_set_increment __P((DB_ENV *, u_int32_t)); 209 */ 210int 211__mutex_set_increment(dbenv, increment) 212 DB_ENV *dbenv; 213 u_int32_t increment; 214{ 215 ENV *env; 216 217 env = dbenv->env; 218 219 ENV_ILLEGAL_AFTER_OPEN(env, "DB_ENV->set_mutex_increment"); 220 221 dbenv->mutex_cnt = 0; 222 dbenv->mutex_inc = increment; 223 return (0); 224} 225 226/* 227 * __mutex_get_max -- 228 * DB_ENV->mutex_get_max. 229 * 230 * PUBLIC: int __mutex_get_max __P((DB_ENV *, u_int32_t *)); 231 */ 232int 233__mutex_get_max(dbenv, maxp) 234 DB_ENV *dbenv; 235 u_int32_t *maxp; 236{ 237 ENV *env; 238 239 env = dbenv->env; 240 241 if (MUTEX_ON(env)) { 242 /* Cannot be set after open, no lock required to read. */ 243 *maxp = ((DB_MUTEXREGION *) 244 env->mutex_handle->reginfo.primary)->stat.st_mutex_cnt; 245 } else 246 *maxp = dbenv->mutex_cnt; 247 return (0); 248} 249 250/* 251 * __mutex_set_max -- 252 * DB_ENV->mutex_set_max. 253 * 254 * PUBLIC: int __mutex_set_max __P((DB_ENV *, u_int32_t)); 255 */ 256int 257__mutex_set_max(dbenv, max) 258 DB_ENV *dbenv; 259 u_int32_t max; 260{ 261 ENV *env; 262 263 env = dbenv->env; 264 265 ENV_ILLEGAL_AFTER_OPEN(env, "DB_ENV->set_mutex_max"); 266 267 dbenv->mutex_cnt = max; 268 dbenv->mutex_inc = 0; 269 return (0); 270} 271 272/* 273 * __mutex_get_tas_spins -- 274 * DB_ENV->mutex_get_tas_spins. 275 * 276 * PUBLIC: int __mutex_get_tas_spins __P((DB_ENV *, u_int32_t *)); 277 */ 278int 279__mutex_get_tas_spins(dbenv, tas_spinsp) 280 DB_ENV *dbenv; 281 u_int32_t *tas_spinsp; 282{ 283 ENV *env; 284 285 env = dbenv->env; 286 287 if (MUTEX_ON(env)) { 288 /* Cannot be set after open, no lock required to read. */ 289 *tas_spinsp = ((DB_MUTEXREGION *)env-> 290 mutex_handle->reginfo.primary)->stat.st_mutex_tas_spins; 291 } else 292 *tas_spinsp = dbenv->mutex_tas_spins; 293 return (0); 294} 295 296/* 297 * __mutex_set_tas_spins -- 298 * DB_ENV->mutex_set_tas_spins. 299 * 300 * PUBLIC: int __mutex_set_tas_spins __P((DB_ENV *, u_int32_t)); 301 */ 302int 303__mutex_set_tas_spins(dbenv, tas_spins) 304 DB_ENV *dbenv; 305 u_int32_t tas_spins; 306{ 307 ENV *env; 308 309 env = dbenv->env; 310 311 /* 312 * Bound the value -- less than 1 makes no sense, greater than 1M 313 * makes no sense. 314 */ 315 if (tas_spins == 0) 316 tas_spins = 1; 317 else if (tas_spins > 1000000) 318 tas_spins = 1000000; 319 320 /* 321 * There's a theoretical race here, but I'm not interested in locking 322 * the test-and-set spin count. The worst possibility is a thread 323 * reads out a bad spin count and spins until it gets the lock, but 324 * that's awfully unlikely. 325 */ 326 if (MUTEX_ON(env)) 327 ((DB_MUTEXREGION *)env->mutex_handle 328 ->reginfo.primary)->stat.st_mutex_tas_spins = tas_spins; 329 else 330 dbenv->mutex_tas_spins = tas_spins; 331 return (0); 332} 333