diff options
| author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2015-02-17 17:25:57 +0000 |
|---|---|---|
| committer | <> | 2015-03-17 16:26:24 +0000 |
| commit | 780b92ada9afcf1d58085a83a0b9e6bc982203d1 (patch) | |
| tree | 598f8b9fa431b228d29897e798de4ac0c1d3d970 /src/lock/lock.c | |
| parent | 7a2660ba9cc2dc03a69ddfcfd95369395cc87444 (diff) | |
| download | berkeleydb-master.tar.gz | |
Diffstat (limited to 'src/lock/lock.c')
| -rw-r--r-- | src/lock/lock.c | 50 |
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(<->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(<->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")); |
