summaryrefslogtreecommitdiff
path: root/src/lock/lock.c
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2015-02-17 17:25:57 +0000
committer <>2015-03-17 16:26:24 +0000
commit780b92ada9afcf1d58085a83a0b9e6bc982203d1 (patch)
tree598f8b9fa431b228d29897e798de4ac0c1d3d970 /src/lock/lock.c
parent7a2660ba9cc2dc03a69ddfcfd95369395cc87444 (diff)
downloadberkeleydb-master.tar.gz
Imported from /home/lorry/working-area/delta_berkeleydb/db-6.1.23.tar.gz.HEADdb-6.1.23master
Diffstat (limited to 'src/lock/lock.c')
-rw-r--r--src/lock/lock.c50
1 files changed, 35 insertions, 15 deletions
diff --git a/src/lock/lock.c b/src/lock/lock.c
index e4627734..bcebbe44 100644
--- a/src/lock/lock.c
+++ b/src/lock/lock.c
@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 1996, 2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2015 Oracle and/or its affiliates. All rights reserved.
*
* $Id$
*/
@@ -31,8 +31,8 @@ static int __lock_trade __P((ENV *, DB_LOCK *, DB_LOCKER *));
static int __lock_vec_api __P((ENV *,
u_int32_t, u_int32_t, DB_LOCKREQ *, int, DB_LOCKREQ **));
-static const char __db_lock_invalid[] = "%s: Lock is no longer valid";
-static const char __db_locker_invalid[] = "Locker is not valid";
+#define LOCK_INVALID_ERR DB_STR_A("2056", "%s: Lock is no longer valid", "%s")
+#define LOCKER_INVALID_ERR DB_STR("2057", "Locker is not valid")
#ifdef DEBUG
extern void __db_loadme (void);
@@ -111,7 +111,8 @@ __lock_vec(env, sh_locker, flags, list, nlist, elistp)
DB_LOCKREQ *list, **elistp;
{
struct __db_lock *lp, *next_lock;
- DB_LOCK lock; DB_LOCKOBJ *sh_obj;
+ DB_LOCK lock;
+ DB_LOCKOBJ *sh_obj;
DB_LOCKREGION *region;
DB_LOCKTAB *lt;
DBT *objlist, *np;
@@ -200,12 +201,18 @@ __lock_vec(env, sh_locker, flags, list, nlist, elistp)
if (writes == 1 ||
lp->mode == DB_LOCK_READ ||
lp->mode == DB_LOCK_READ_UNCOMMITTED) {
- SH_LIST_REMOVE(lp,
- locker_links, __db_lock);
+ /*
+ * It is safe to look at lp before
+ * locking because any threads sharing
+ * this locker must not be in the API
+ * at the same time.
+ */
sh_obj = SH_OFF_TO_PTR(lp,
lp->obj, DB_LOCKOBJ);
ndx = sh_obj->indx;
OBJECT_LOCK_NDX(lt, region, ndx);
+ SH_LIST_REMOVE(lp,
+ locker_links, __db_lock);
/*
* We are not letting lock_put_internal
* unlink the lock, so we'll have to
@@ -423,7 +430,7 @@ __lock_get_api(env, locker, flags, obj, lock_mode, lock)
region = env->lk_handle->reginfo.primary;
LOCK_LOCKERS(env, region);
- ret = __lock_getlocker_int(env->lk_handle, locker, 0, &sh_locker);
+ ret = __lock_getlocker_int(env->lk_handle, locker, 0, NULL, &sh_locker);
UNLOCK_LOCKERS(env, region);
LOCK_SYSTEM_LOCK(env->lk_handle, region);
if (ret == 0)
@@ -979,12 +986,21 @@ in_abort: newl->status = DB_LSTAT_WAITING;
goto err;
}
+ /*
+ * Sleep until someone releases a lock which might let us in.
+ * Since we want to set the thread state back to ACTIVE, don't
+ * use the normal MUTEX_LOCK() macro, which would immediately
+ * return a panic error code. Instead, return the panic after
+ * restoring the thread state.
+ */
PERFMON2(env, lock, suspend, (DBT *) obj, lock_mode);
- MUTEX_LOCK(env, newl->mtx_lock);
+ ret = __mutex_lock(env, newl->mtx_lock);
PERFMON2(env, lock, resume, (DBT *) obj, lock_mode);
if (ip != NULL)
ip->dbth_state = THREAD_ACTIVE;
+ if (ret != 0)
+ return (ret);
LOCK_SYSTEM_LOCK(lt, region);
OBJECT_LOCK_NDX(lt, region, ndx);
@@ -1165,7 +1181,7 @@ __lock_put_nolock(env, lock, runp, flags)
lockp = R_ADDR(&lt->reginfo, lock->off);
DB_ASSERT(env, lock->gen == lockp->gen);
if (lock->gen != lockp->gen) {
- __db_errx(env, __db_lock_invalid, "DB_LOCK->lock_put");
+ __db_errx(env, LOCK_INVALID_ERR, "DB_LOCK->lock_put");
LOCK_INIT(*lock);
return (EINVAL);
}
@@ -1224,7 +1240,7 @@ __lock_downgrade(env, lock, new_mode, flags)
lockp = R_ADDR(&lt->reginfo, lock->off);
if (lock->gen != lockp->gen) {
- __db_errx(env, __db_lock_invalid, "lock_downgrade");
+ __db_errx(env, LOCK_INVALID_ERR, "lock_downgrade");
ret = EINVAL;
goto out;
}
@@ -1662,7 +1678,7 @@ __lock_inherit_locks(lt, sh_locker, flags)
* locks, so inheritance is easy!
*/
if (sh_locker == NULL) {
- __db_errx(env, __db_locker_invalid);
+ __db_errx(env, LOCKER_INVALID_ERR);
return (EINVAL);
}
@@ -1683,11 +1699,15 @@ __lock_inherit_locks(lt, sh_locker, flags)
for (lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock);
lp != NULL;
lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock)) {
- SH_LIST_REMOVE(lp, locker_links, __db_lock);
-
- /* See if the parent already has a lock. */
+ /*
+ * See if the parent already has a lock. It is safe to look at
+ * lp before locking it because any threads sharing this locker
+ * must not be in the API with the same time.
+ */
obj = SH_OFF_TO_PTR(lp, lp->obj, DB_LOCKOBJ);
OBJECT_LOCK_NDX(lt, region, obj->indx);
+ SH_LIST_REMOVE(lp, locker_links, __db_lock);
+
SH_TAILQ_FOREACH(hlp, &obj->holders, links, __db_lock)
if (hlp->holder == poff && lp->mode == hlp->mode)
break;
@@ -1917,7 +1937,7 @@ __lock_trade(env, lock, new_locker)
/* If the lock is already released, simply return. */
if (lp->gen != lock->gen)
- return (DB_NOTFOUND);
+ return (USR_ERR(env, DB_NOTFOUND));
if (new_locker == NULL) {
__db_errx(env, DB_STR("2040", "Locker does not exist"));