/*- * See the file LICENSE for redistribution information. * * Copyright (c) 1996,2008 Oracle. All rights reserved. * * $Id: mut_fcntl.c,v 12.28 2008/01/08 20:58:43 bostic Exp $ */ #include "db_config.h" #include "db_int.h" #include "dbinc/mutex_int.h" /* * __db_fcntl_mutex_init -- * Initialize a fcntl mutex. * * PUBLIC: int __db_fcntl_mutex_init __P((ENV *, db_mutex_t, u_int32_t)); */ int __db_fcntl_mutex_init(env, mutex, flags) ENV *env; db_mutex_t mutex; u_int32_t flags; { COMPQUIET(env, NULL); COMPQUIET(mutex, MUTEX_INVALID); COMPQUIET(flags, 0); return (0); } /* * __db_fcntl_mutex_lock * Lock on a mutex, blocking if necessary. * * PUBLIC: int __db_fcntl_mutex_lock __P((ENV *, db_mutex_t)); */ int __db_fcntl_mutex_lock(env, mutex) ENV *env; db_mutex_t mutex; { DB_ENV *dbenv; DB_MUTEX *mutexp; DB_MUTEXMGR *mtxmgr; DB_MUTEXREGION *mtxregion; struct flock k_lock; int locked, ms, ret; dbenv = env->dbenv; if (!MUTEX_ON(env) || F_ISSET(dbenv, DB_ENV_NOLOCKING)) return (0); mtxmgr = env->mutex_handle; mtxregion = mtxmgr->reginfo.primary; mutexp = MUTEXP_SET(mutex); CHECK_MTX_THREAD(env, mutexp); #ifdef HAVE_STATISTICS if (F_ISSET(mutexp, DB_MUTEX_LOCKED)) ++mutexp->mutex_set_wait; else ++mutexp->mutex_set_nowait; #endif /* Initialize the lock. */ k_lock.l_whence = SEEK_SET; k_lock.l_start = mutex; k_lock.l_len = 1; for (locked = 0;;) { /* * Wait for the lock to become available; wait 1ms initially, * up to 1 second. */ for (ms = 1; F_ISSET(mutexp, DB_MUTEX_LOCKED);) { __os_yield(NULL, 0, ms * US_PER_MS); if ((ms <<= 1) > MS_PER_SEC) ms = MS_PER_SEC; } /* Acquire an exclusive kernel lock. */ k_lock.l_type = F_WRLCK; if (fcntl(env->lockfhp->fd, F_SETLKW, &k_lock)) goto err; /* If the resource is still available, it's ours. */ if (!F_ISSET(mutexp, DB_MUTEX_LOCKED)) { locked = 1; F_SET(mutexp, DB_MUTEX_LOCKED); dbenv->thread_id(dbenv, &mutexp->pid, &mutexp->tid); } /* Release the kernel lock. */ k_lock.l_type = F_UNLCK; if (fcntl(env->lockfhp->fd, F_SETLK, &k_lock)) goto err; /* * If we got the resource lock we're done. * * !!! * We can't check to see if the lock is ours, because we may * be trying to block ourselves in the lock manager, and so * the holder of the lock that's preventing us from getting * the lock may be us! (Seriously.) */ if (locked) break; } #ifdef DIAGNOSTIC /* * We want to switch threads as often as possible. Yield every time * we get a mutex to ensure contention. */ if (F_ISSET(dbenv, DB_ENV_YIELDCPU)) __os_yield(env, 0, 0); #endif return (0); err: ret = __os_get_syserr(); __db_syserr(env, ret, "fcntl lock failed"); return (__env_panic(env, __os_posix_err(ret))); } /* * __db_fcntl_mutex_unlock -- * Release a mutex. * * PUBLIC: int __db_fcntl_mutex_unlock __P((ENV *, db_mutex_t)); */ int __db_fcntl_mutex_unlock(env, mutex) ENV *env; db_mutex_t mutex; { DB_ENV *dbenv; DB_MUTEX *mutexp; DB_MUTEXMGR *mtxmgr; DB_MUTEXREGION *mtxregion; dbenv = env->dbenv; if (!MUTEX_ON(env) || F_ISSET(dbenv, DB_ENV_NOLOCKING)) return (0); mtxmgr = env->mutex_handle; mtxregion = mtxmgr->reginfo.primary; mutexp = MUTEXP_SET(mutex); #ifdef DIAGNOSTIC if (!F_ISSET(mutexp, DB_MUTEX_LOCKED)) { __db_errx(env, "fcntl unlock failed: lock already unlocked"); return (__env_panic(env, EACCES)); } #endif /* * Release the resource. We don't have to acquire any locks because * processes trying to acquire the lock are waiting for the flag to * go to 0. Once that happens the waiters will serialize acquiring * an exclusive kernel lock before locking the mutex. */ F_CLR(mutexp, DB_MUTEX_LOCKED); return (0); } /* * __db_fcntl_mutex_destroy -- * Destroy a mutex. * * PUBLIC: int __db_fcntl_mutex_destroy __P((ENV *, db_mutex_t)); */ int __db_fcntl_mutex_destroy(env, mutex) ENV *env; db_mutex_t mutex; { COMPQUIET(env, NULL); COMPQUIET(mutex, MUTEX_INVALID); return (0); }