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/mutex/mut_alloc.c | |
parent | 7a2660ba9cc2dc03a69ddfcfd95369395cc87444 (diff) | |
download | berkeleydb-master.tar.gz |
Diffstat (limited to 'src/mutex/mut_alloc.c')
-rw-r--r-- | src/mutex/mut_alloc.c | 234 |
1 files changed, 212 insertions, 22 deletions
diff --git a/src/mutex/mut_alloc.c b/src/mutex/mut_alloc.c index 5df3de53..06b3541e 100644 --- a/src/mutex/mut_alloc.c +++ b/src/mutex/mut_alloc.c @@ -1,7 +1,7 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1999, 2012 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015 Oracle and/or its affiliates. All rights reserved. * * $Id$ */ @@ -9,6 +9,9 @@ #include "db_config.h" #include "db_int.h" +#include "dbinc/log.h" + +static char *__mutex_action_print __P((MUTEX_ACTION)); /* * __mutex_alloc -- @@ -35,8 +38,7 @@ __mutex_alloc(env, alloc_id, flags, indxp) if (alloc_id != MTX_APPLICATION && alloc_id != MTX_MUTEX_TEST && (F_ISSET(env->dbenv, DB_ENV_NOLOCKING) || (!F_ISSET(env, ENV_THREAD) && - (LF_ISSET(DB_MUTEX_PROCESS_ONLY) || - F_ISSET(env, ENV_PRIVATE))))) + (LF_ISSET(DB_MUTEX_PROCESS_ONLY) || F_ISSET(env, ENV_PRIVATE))))) return (0); /* Private environments never share mutexes. */ @@ -109,13 +111,17 @@ nomem: __db_errx(env, DB_STR("2034", mtxregion->stat.st_mutex_max) cnt = mtxregion->stat.st_mutex_max - mtxregion->stat.st_mutex_cnt; + + /* Set i to the first newly created db_mutex_t. */ if (F_ISSET(env, ENV_PRIVATE)) { F_SET(&mtxmgr->reginfo, REGION_TRACKED); while (__env_alloc(&mtxmgr->reginfo, (cnt * mtxregion->mutex_size) + - mtxregion->stat.st_mutex_align, &i) != 0) - if ((cnt >> 1) == 0) + mtxregion->stat.st_mutex_align, &i) != 0) { + cnt >>= 1; + if (cnt == 0) break; + } F_CLR(&mtxmgr->reginfo, REGION_TRACKED); i = (db_mutex_t)ALIGNP_INC(i, mtxregion->stat.st_mutex_align); @@ -130,21 +136,16 @@ nomem: __db_errx(env, DB_STR("2034", } if (cnt == 0) goto nomem; - mutexp = MUTEXP_SET(env, i); + mtxregion->stat.st_mutex_free = cnt; mtxregion->mutex_next = i; mtxregion->stat.st_mutex_cnt += cnt; - while (--cnt > 0) { - mutexp->flags = 0; - if (F_ISSET(env, ENV_PRIVATE)) - mutexp->mutex_next_link = - (uintptr_t)(mutexp + 1); - else - mutexp->mutex_next_link = ++i; - mutexp++; - } - mutexp->flags = 0; - mutexp->mutex_next_link = MUTEX_INVALID; + + /* + * Now link the rest of the newly allocated db_mutex_t's into + * the free list. + */ + MUTEX_BULK_INIT(env, mtxregion, i, cnt); } *indxp = mtxregion->mutex_next; @@ -158,14 +159,12 @@ nomem: __db_errx(env, DB_STR("2034", if (mtxregion->stat.st_mutex_inuse > mtxregion->stat.st_mutex_inuse_max) mtxregion->stat.st_mutex_inuse_max = mtxregion->stat.st_mutex_inuse; - if (locksys) - MUTEX_SYSTEM_UNLOCK(env); /* Initialize the mutex. */ memset(mutexp, 0, sizeof(*mutexp)); F_SET(mutexp, DB_MUTEX_ALLOCATED | - LF_ISSET(DB_MUTEX_LOGICAL_LOCK | - DB_MUTEX_PROCESS_ONLY | DB_MUTEX_SHARED)); + LF_ISSET(DB_MUTEX_LOGICAL_LOCK | DB_MUTEX_PROCESS_ONLY | + DB_MUTEX_SELF_BLOCK | DB_MUTEX_SHARED)); /* * If the mutex is associated with a single process, set the process @@ -182,7 +181,9 @@ nomem: __db_errx(env, DB_STR("2034", #endif if ((ret = __mutex_init(env, *indxp, flags)) != 0) - (void)__mutex_free_int(env, locksys, indxp); + (void)__mutex_free_int(env, 0, indxp); + if (locksys) + MUTEX_SYSTEM_UNLOCK(env); return (ret); } @@ -262,6 +263,44 @@ __mutex_free_int(env, locksys, indxp) return (ret); } +#ifdef HAVE_FAILCHK_BROADCAST +/* + * __mutex_died -- + * Announce that a mutex request couldn't been granted because the last + * thread to own it was killed by failchk. Sets ENV_DEAD_MUTEX in the + * possibly shared environment so that mutex unlock calls don't complain. + * + * + * PUBLIC: int __mutex_died __P((ENV *, db_mutex_t)); + */ +int +__mutex_died(env, mutex) + ENV *env; + db_mutex_t mutex; +{ + DB_ENV *dbenv; + DB_EVENT_MUTEX_DIED_INFO info; + DB_MUTEX *mutexp; + char tidstr[DB_THREADID_STRLEN], failmsg[DB_FAILURE_SYMPTOM_SIZE]; + + dbenv = env->dbenv; + + mutexp = MUTEXP_SET(env, mutex); + info.mutex = mutex; + info.pid = mutexp->pid; + info.tid = mutexp->tid; + (void)dbenv->thread_id_string(dbenv, mutexp->pid, mutexp->tid, tidstr); + (void)__mutex_describe(env, mutex, info.desc); + (void)snprintf(failmsg, sizeof(failmsg), DB_STR_A("2073", + "Mutex died: %s owned %s", "%s %s"), tidstr, info.desc); + __db_errx(env, "%s", failmsg); + /* If this is the first crashed process, save its description. */ + (void)__env_failure_remember(env, failmsg); + DB_EVENT(env, DB_EVENT_MUTEX_DIED, &info); + return (__env_panic(env, USR_ERR(env, DB_RUNRECOVERY))); +} +#endif + /* * __mutex_refresh -- * Reinitialize a mutex, if we are not sure of its state. @@ -289,3 +328,154 @@ __mutex_refresh(env, mutex) } return (ret); } + +/* + * __mutex_record_lock -- + * Record that this thread is about to lock a latch. + * The last parameter is updated to point to this mutex's entry in the + * per-thread mutex state array, so that it can update it if it gets the + * mutex, or free it if the mutex is not acquired (e.g. it times out). + * Mutexes which can be unlocked by other threads are not placed in this + * list, because it would be too costly for that other thread to to find + * the right slot to clear. The caller has already checked that thread + * tracking is enabled. + * + * PUBLIC: int __mutex_record_lock + * PUBLIC: __P((ENV *, db_mutex_t, MUTEX_ACTION, MUTEX_STATE **)); + */ +int +__mutex_record_lock(env, mutex, action, retp) + ENV *env; + db_mutex_t mutex; + MUTEX_ACTION action; + MUTEX_STATE **retp; +{ + DB_MUTEX *mutexp; + DB_THREAD_INFO *ip; + int i, ret; + + *retp = NULL; + mutexp = MUTEXP_SET(env, mutex); + if (!F_ISSET(mutexp, DB_MUTEX_SHARED)) + return (0); + if ((ret = __env_set_state(env, &ip, THREAD_VERIFY)) != 0) + return (ret); + for (i = 0; i != MUTEX_STATE_MAX; i++) { + if (ip->dbth_latches[i].action == MUTEX_ACTION_UNLOCKED) { + ip->dbth_latches[i].mutex = mutex; + ip->dbth_latches[i].action = action; +#ifdef DIAGNOSTIC + __os_gettime(env, &ip->dbth_latches[i].when, 0); +#endif + *retp = &ip->dbth_latches[i]; + return (0); + } + } + __db_errx(env, DB_STR_A("2074", + "No space available in latch table for %lu", "%lu"), (u_long)mutex); + (void)__mutex_record_print(env, ip); + return (__env_panic(env, USR_ERR(env, DB_RUNRECOVERY))); +} + +/* + * __mutex_record_unlock -- + * Verify that this thread owns the mutex it is about to unlock. + * + * PUBLIC: int __mutex_record_unlock __P((ENV *, db_mutex_t)); + */ +int +__mutex_record_unlock(env, mutex) + ENV *env; + db_mutex_t mutex; +{ + DB_MUTEX *mutexp; + DB_THREAD_INFO *ip; + int i, ret; + + if (env->thr_hashtab == NULL) + return (0); + mutexp = MUTEXP_SET(env, mutex); + if (!F_ISSET(mutexp, DB_MUTEX_SHARED)) + return (0); + if ((ret = __env_set_state(env, &ip, THREAD_VERIFY)) != 0) + return (ret); + for (i = 0; i != MUTEX_STATE_MAX; i++) { + if (ip->dbth_latches[i].mutex == mutex && + ip->dbth_latches[i].action != MUTEX_ACTION_UNLOCKED) { + ip->dbth_latches[i].action = MUTEX_ACTION_UNLOCKED; + return (0); + } + } + (void)__mutex_record_print(env, ip); + if (ip->dbth_state == THREAD_FAILCHK) { + DB_DEBUG_MSG(env, "mutex_record_unlock %lu by failchk thread", + (u_long)mutex); + return (0); + } + __db_errx(env, DB_STR_A("2075", + "Latch %lu was not held", "%lu"), (u_long)mutex); + return (__env_panic(env, USR_ERR(env, DB_RUNRECOVERY))); +} + +static char * +__mutex_action_print(action) + MUTEX_ACTION action; +{ + switch (action) { + case MUTEX_ACTION_UNLOCKED: + return ("unlocked"); + case MUTEX_ACTION_INTEND_SHARE: + return ("waiting to share"); + case MUTEX_ACTION_SHARED: + return ("sharing"); + default: + return ("unknown"); + } + /* NOTREACHED */ +} + +/* + * __mutex_record_print -- + * Display the thread's mutex state via __db_msg(), including any + * information which would be relevant for db_stat or diagnostic messages. + * + * PUBLIC: int __mutex_record_print __P((ENV *, DB_THREAD_INFO *)); + */ +int +__mutex_record_print(env, ip) + ENV *env; + DB_THREAD_INFO *ip; +{ + DB_MSGBUF mb, *mbp; + db_mutex_t mutex; + int i; + char desc[DB_MUTEX_DESCRIBE_STRLEN]; + char time_buf[CTIME_BUFLEN]; + + DB_MSGBUF_INIT(&mb); + mbp = &mb; + for (i = 0; i != MUTEX_STATE_MAX; i++) { + if (ip->dbth_latches[i].action == MUTEX_ACTION_UNLOCKED) + continue; + if ((mutex = ip->dbth_latches[i].mutex) == + MUTEX_INVALID) + continue; + time_buf[4] = '\0'; +#ifdef DIAGNOSTIC + if (timespecisset(&ip->dbth_latches[i].when)) + (void)__db_ctimespec(&ip->dbth_latches[i].when, + time_buf); + else +#endif + time_buf[0] = '\0'; + + __db_msgadd(env, mbp, "%s %s %s ", + __mutex_describe(env, mutex, desc), + __mutex_action_print(ip->dbth_latches[i].action), time_buf); +#ifdef HAVE_STATISTICS + __mutex_print_debug_stats(env, mbp, mutex, 0); +#endif + DB_MSGBUF_FLUSH(env, mbp); + } + return (0); +} |