summaryrefslogtreecommitdiff
path: root/src/mutex/mut_alloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mutex/mut_alloc.c')
-rw-r--r--src/mutex/mut_alloc.c234
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);
+}