/*- * See the file LICENSE for redistribution information. * * Copyright (c) 1996,2007 Oracle. All rights reserved. * * $Id: mut_fcntl.c,v 12.23 2007/05/17 15:15:45 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((DB_ENV *, db_mutex_t, u_int32_t)); */ int __db_fcntl_mutex_init(dbenv, mutex, flags) DB_ENV *dbenv; db_mutex_t mutex; u_int32_t flags; { COMPQUIET(dbenv, 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((DB_ENV *, db_mutex_t)); */ int __db_fcntl_mutex_lock(dbenv, mutex) DB_ENV *dbenv; db_mutex_t mutex; { DB_MUTEX *mutexp; DB_MUTEXMGR *mtxmgr; DB_MUTEXREGION *mtxregion; struct flock k_lock; int locked, ms, ret; if (!MUTEX_ON(dbenv) || F_ISSET(dbenv, DB_ENV_NOLOCKING)) return (0); mtxmgr = dbenv->mutex_handle; mtxregion = mtxmgr->reginfo.primary; mutexp = MUTEXP_SET(mutex); #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_sleep(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(dbenv->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); CHECK_MTX_THREAD(dbenv, mutexp); } /* Release the kernel lock. */ k_lock.l_type = F_UNLCK; if (fcntl(dbenv->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(dbenv); #endif return (0); err: ret = __os_get_syserr(); __db_syserr(dbenv, ret, "fcntl lock failed"); return (__db_panic(dbenv, __os_posix_err(ret))); } /* * __db_fcntl_mutex_unlock -- * Release a mutex. * * PUBLIC: int __db_fcntl_mutex_unlock __P((DB_ENV *, db_mutex_t)); */ int __db_fcntl_mutex_unlock(dbenv, mutex) DB_ENV *dbenv; db_mutex_t mutex; { DB_MUTEX *mutexp; DB_MUTEXMGR *mtxmgr; DB_MUTEXREGION *mtxregion; if (!MUTEX_ON(dbenv) || F_ISSET(dbenv, DB_ENV_NOLOCKING)) return (0); mtxmgr = dbenv->mutex_handle; mtxregion = mtxmgr->reginfo.primary; mutexp = MUTEXP_SET(mutex); #ifdef DIAGNOSTIC if (!F_ISSET(mutexp, DB_MUTEX_LOCKED)) { __db_errx(dbenv, "fcntl unlock failed: lock already unlocked"); return (__db_panic(dbenv, 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((DB_ENV *, db_mutex_t)); */ int __db_fcntl_mutex_destroy(dbenv, mutex) DB_ENV *dbenv; db_mutex_t mutex; { COMPQUIET(dbenv, NULL); COMPQUIET(mutex, MUTEX_INVALID); return (0); }