1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996,2008 Oracle. All rights reserved. 5 * 6 * $Id: mut_fcntl.c,v 12.28 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 * __db_fcntl_mutex_init -- 16 * Initialize a fcntl mutex. 17 * 18 * PUBLIC: int __db_fcntl_mutex_init __P((ENV *, db_mutex_t, u_int32_t)); 19 */ 20int 21__db_fcntl_mutex_init(env, mutex, flags) 22 ENV *env; 23 db_mutex_t mutex; 24 u_int32_t flags; 25{ 26 COMPQUIET(env, NULL); 27 COMPQUIET(mutex, MUTEX_INVALID); 28 COMPQUIET(flags, 0); 29 30 return (0); 31} 32 33/* 34 * __db_fcntl_mutex_lock 35 * Lock on a mutex, blocking if necessary. 36 * 37 * PUBLIC: int __db_fcntl_mutex_lock __P((ENV *, db_mutex_t)); 38 */ 39int 40__db_fcntl_mutex_lock(env, mutex) 41 ENV *env; 42 db_mutex_t mutex; 43{ 44 DB_ENV *dbenv; 45 DB_MUTEX *mutexp; 46 DB_MUTEXMGR *mtxmgr; 47 DB_MUTEXREGION *mtxregion; 48 struct flock k_lock; 49 int locked, ms, ret; 50 51 dbenv = env->dbenv; 52 53 if (!MUTEX_ON(env) || F_ISSET(dbenv, DB_ENV_NOLOCKING)) 54 return (0); 55 56 mtxmgr = env->mutex_handle; 57 mtxregion = mtxmgr->reginfo.primary; 58 mutexp = MUTEXP_SET(mutex); 59 60 CHECK_MTX_THREAD(env, mutexp); 61 62#ifdef HAVE_STATISTICS 63 if (F_ISSET(mutexp, DB_MUTEX_LOCKED)) 64 ++mutexp->mutex_set_wait; 65 else 66 ++mutexp->mutex_set_nowait; 67#endif 68 69 /* Initialize the lock. */ 70 k_lock.l_whence = SEEK_SET; 71 k_lock.l_start = mutex; 72 k_lock.l_len = 1; 73 74 for (locked = 0;;) { 75 /* 76 * Wait for the lock to become available; wait 1ms initially, 77 * up to 1 second. 78 */ 79 for (ms = 1; F_ISSET(mutexp, DB_MUTEX_LOCKED);) { 80 __os_yield(NULL, 0, ms * US_PER_MS); 81 if ((ms <<= 1) > MS_PER_SEC) 82 ms = MS_PER_SEC; 83 } 84 85 /* Acquire an exclusive kernel lock. */ 86 k_lock.l_type = F_WRLCK; 87 if (fcntl(env->lockfhp->fd, F_SETLKW, &k_lock)) 88 goto err; 89 90 /* If the resource is still available, it's ours. */ 91 if (!F_ISSET(mutexp, DB_MUTEX_LOCKED)) { 92 locked = 1; 93 94 F_SET(mutexp, DB_MUTEX_LOCKED); 95 dbenv->thread_id(dbenv, &mutexp->pid, &mutexp->tid); 96 } 97 98 /* Release the kernel lock. */ 99 k_lock.l_type = F_UNLCK; 100 if (fcntl(env->lockfhp->fd, F_SETLK, &k_lock)) 101 goto err; 102 103 /* 104 * If we got the resource lock we're done. 105 * 106 * !!! 107 * We can't check to see if the lock is ours, because we may 108 * be trying to block ourselves in the lock manager, and so 109 * the holder of the lock that's preventing us from getting 110 * the lock may be us! (Seriously.) 111 */ 112 if (locked) 113 break; 114 } 115 116#ifdef DIAGNOSTIC 117 /* 118 * We want to switch threads as often as possible. Yield every time 119 * we get a mutex to ensure contention. 120 */ 121 if (F_ISSET(dbenv, DB_ENV_YIELDCPU)) 122 __os_yield(env, 0, 0); 123#endif 124 return (0); 125 126err: ret = __os_get_syserr(); 127 __db_syserr(env, ret, "fcntl lock failed"); 128 return (__env_panic(env, __os_posix_err(ret))); 129} 130 131/* 132 * __db_fcntl_mutex_unlock -- 133 * Release a mutex. 134 * 135 * PUBLIC: int __db_fcntl_mutex_unlock __P((ENV *, db_mutex_t)); 136 */ 137int 138__db_fcntl_mutex_unlock(env, mutex) 139 ENV *env; 140 db_mutex_t mutex; 141{ 142 DB_ENV *dbenv; 143 DB_MUTEX *mutexp; 144 DB_MUTEXMGR *mtxmgr; 145 DB_MUTEXREGION *mtxregion; 146 147 dbenv = env->dbenv; 148 149 if (!MUTEX_ON(env) || F_ISSET(dbenv, DB_ENV_NOLOCKING)) 150 return (0); 151 152 mtxmgr = env->mutex_handle; 153 mtxregion = mtxmgr->reginfo.primary; 154 mutexp = MUTEXP_SET(mutex); 155 156#ifdef DIAGNOSTIC 157 if (!F_ISSET(mutexp, DB_MUTEX_LOCKED)) { 158 __db_errx(env, "fcntl unlock failed: lock already unlocked"); 159 return (__env_panic(env, EACCES)); 160 } 161#endif 162 163 /* 164 * Release the resource. We don't have to acquire any locks because 165 * processes trying to acquire the lock are waiting for the flag to 166 * go to 0. Once that happens the waiters will serialize acquiring 167 * an exclusive kernel lock before locking the mutex. 168 */ 169 F_CLR(mutexp, DB_MUTEX_LOCKED); 170 171 return (0); 172} 173 174/* 175 * __db_fcntl_mutex_destroy -- 176 * Destroy a mutex. 177 * 178 * PUBLIC: int __db_fcntl_mutex_destroy __P((ENV *, db_mutex_t)); 179 */ 180int 181__db_fcntl_mutex_destroy(env, mutex) 182 ENV *env; 183 db_mutex_t mutex; 184{ 185 COMPQUIET(env, NULL); 186 COMPQUIET(mutex, MUTEX_INVALID); 187 188 return (0); 189} 190