2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1996-2009 Oracle. All rights reserved.
13 static inline int __db_fcntl_mutex_lock_int __P((ENV *, db_mutex_t, int));
16 * __db_fcntl_mutex_init --
17 * Initialize a fcntl mutex.
19 * PUBLIC: int __db_fcntl_mutex_init __P((ENV *, db_mutex_t, u_int32_t));
22 __db_fcntl_mutex_init(env, mutex, flags)
28 COMPQUIET(mutex, MUTEX_INVALID);
35 * __db_fcntl_mutex_lock_int
36 * Internal function to lock a mutex, blocking only when requested
39 __db_fcntl_mutex_lock_int(env, mutex, wait)
53 if (!MUTEX_ON(env) || F_ISSET(dbenv, DB_ENV_NOLOCKING))
56 mtxmgr = env->mutex_handle;
57 mutexp = MUTEXP_SET(mtxmgr, mutex);
59 CHECK_MTX_THREAD(env, mutexp);
61 #ifdef HAVE_STATISTICS
62 if (F_ISSET(mutexp, DB_MUTEX_LOCKED))
63 ++mutexp->mutex_set_wait;
65 ++mutexp->mutex_set_nowait;
68 /* Initialize the lock. */
69 k_lock.l_whence = SEEK_SET;
70 k_lock.l_start = mutex;
74 * Only check the thread state once, by initializing the thread
75 * control block pointer to null. If it is not the failchk
76 * thread, then ip will have a valid value subsequent times
83 * Wait for the lock to become available; wait 1ms initially,
86 for (ms = 1; F_ISSET(mutexp, DB_MUTEX_LOCKED);) {
87 if (F_ISSET(dbenv, DB_ENV_FAILCHK) &&
88 ip == NULL && dbenv->is_alive(dbenv,
89 mutexp->pid, mutexp->tid, 0) == 0) {
90 ret = __env_set_state(env, &ip, THREAD_VERIFY);
92 ip->dbth_state == THREAD_FAILCHK)
93 return (DB_RUNRECOVERY);
96 return (DB_LOCK_NOTGRANTED);
97 __os_yield(NULL, 0, ms * US_PER_MS);
98 if ((ms <<= 1) > MS_PER_SEC)
102 /* Acquire an exclusive kernel lock on the byte. */
103 k_lock.l_type = F_WRLCK;
104 if (fcntl(env->lockfhp->fd, F_SETLKW, &k_lock))
107 /* If the resource is still available, it's ours. */
108 if (!F_ISSET(mutexp, DB_MUTEX_LOCKED)) {
111 F_SET(mutexp, DB_MUTEX_LOCKED);
112 dbenv->thread_id(dbenv, &mutexp->pid, &mutexp->tid);
115 /* Release the kernel lock. */
116 k_lock.l_type = F_UNLCK;
117 if (fcntl(env->lockfhp->fd, F_SETLK, &k_lock))
121 * If we got the resource lock we're done.
124 * We can't check to see if the lock is ours, because we may
125 * be trying to block ourselves in the lock manager, and so
126 * the holder of the lock that's preventing us from getting
127 * the lock may be us! (Seriously.)
135 * We want to switch threads as often as possible. Yield every time
136 * we get a mutex to ensure contention.
138 if (F_ISSET(dbenv, DB_ENV_YIELDCPU))
139 __os_yield(env, 0, 0);
143 err: ret = __os_get_syserr();
144 __db_syserr(env, ret, "fcntl lock failed");
145 return (__env_panic(env, __os_posix_err(ret)));
149 * __db_fcntl_mutex_lock
150 * Lock a mutex, blocking if necessary.
152 * PUBLIC: int __db_fcntl_mutex_lock __P((ENV *, db_mutex_t));
155 __db_fcntl_mutex_lock(env, mutex)
159 return (__db_fcntl_mutex_lock_int(env, mutex, 1));
163 * __db_fcntl_mutex_trylock
164 * Try to lock a mutex, without blocking when it is busy.
166 * PUBLIC: int __db_fcntl_mutex_trylock __P((ENV *, db_mutex_t));
169 __db_fcntl_mutex_trylock(env, mutex)
173 return (__db_fcntl_mutex_lock_int(env, mutex, 0));
177 * __db_fcntl_mutex_unlock --
180 * PUBLIC: int __db_fcntl_mutex_unlock __P((ENV *, db_mutex_t));
183 __db_fcntl_mutex_unlock(env, mutex)
193 if (!MUTEX_ON(env) || F_ISSET(dbenv, DB_ENV_NOLOCKING))
196 mtxmgr = env->mutex_handle;
197 mutexp = MUTEXP_SET(mtxmgr, mutex);
200 if (!F_ISSET(mutexp, DB_MUTEX_LOCKED)) {
201 __db_errx(env, "fcntl unlock failed: lock already unlocked");
202 return (__env_panic(env, EACCES));
207 * Release the resource. We don't have to acquire any locks because
208 * processes trying to acquire the lock are waiting for the flag to
209 * go to 0. Once that happens the waiters will serialize acquiring
210 * an exclusive kernel lock before locking the mutex.
212 F_CLR(mutexp, DB_MUTEX_LOCKED);
218 * __db_fcntl_mutex_destroy --
221 * PUBLIC: int __db_fcntl_mutex_destroy __P((ENV *, db_mutex_t));
224 __db_fcntl_mutex_destroy(env, mutex)
228 COMPQUIET(env, NULL);
229 COMPQUIET(mutex, MUTEX_INVALID);