Merge "Add a regression test for a long-fixed pthread_once bug."
diff --git a/libc/Android.mk b/libc/Android.mk
index ed7d055..c0da9b2 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -747,10 +747,6 @@
LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
LOCAL_SYSTEM_SHARED_LIBRARIES :=
-# Set -DPTHREAD_DEBUG_ENABLED=true to enable support for pthread deadlock prediction.
-# Since this code is experimental it is disabled by default.
-LOCAL_CFLAGS += -DPTHREAD_DEBUG_ENABLED=false
-
ifneq ($(TARGET_USES_LOGD),false)
LOCAL_CFLAGS += -DTARGET_USES_LOGD
endif
@@ -889,7 +885,6 @@
bionic/malloc_debug_common.cpp \
bionic/debug_mapinfo.cpp \
bionic/debug_stacktrace.cpp \
- bionic/pthread_debug.cpp \
bionic/libc_init_dynamic.cpp \
bionic/NetdClient.cpp \
diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp
index 3d98861..659cf39 100644
--- a/libc/bionic/libc_init_dynamic.cpp
+++ b/libc/bionic/libc_init_dynamic.cpp
@@ -55,7 +55,6 @@
#include "private/KernelArgumentBlock.h"
extern "C" {
- extern void pthread_debug_init(void);
extern void malloc_debug_init(void);
extern void malloc_debug_fini(void);
extern void netdClientInit(void);
@@ -77,11 +76,8 @@
__libc_init_common(*args);
- // Hooks for the debug malloc and pthread libraries to let them know that we're starting up.
- pthread_debug_init();
+ // Hooks for various libraries to let them know that we're starting up.
malloc_debug_init();
-
- // Hook for the netd client library to let it know that we're starting up.
netdClientInit();
}
diff --git a/libc/bionic/pthread_debug.cpp b/libc/bionic/pthread_debug.cpp
deleted file mode 100644
index be89b46..0000000
--- a/libc/bionic/pthread_debug.cpp
+++ /dev/null
@@ -1,717 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/types.h>
-#include <sys/atomics.h>
-#include <sys/system_properties.h>
-#include <sys/mman.h>
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <pthread.h>
-#include <unwind.h>
-#include <unistd.h>
-
-#include "private/bionic_tls.h"
-#include "debug_mapinfo.h"
-#include "debug_stacktrace.h"
-#include "private/libc_logging.h"
-
-/*
- * ===========================================================================
- * Deadlock prediction
- * ===========================================================================
- */
-/*
-The idea is to predict the possibility of deadlock by recording the order
-in which locks are acquired. If we see an attempt to acquire a lock
-out of order, we can identify the locks and offending code.
-
-To make this work, we need to keep track of the locks held by each thread,
-and create history trees for each lock. When a thread tries to acquire
-a new lock, we walk through the "history children" of the lock, looking
-for a match with locks the thread already holds. If we find a match,
-it means the thread has made a request that could result in a deadlock.
-
-To support recursive locks, we always allow re-locking a currently-held
-lock, and maintain a recursion depth count.
-
-An ASCII-art example, where letters represent locks:
-
- A
- /|\
- / | \
- B | D
- \ |
- \|
- C
-
-The above is the tree we'd have after handling lock synchronization
-sequences "ABC", "AC", "AD". A has three children, {B, C, D}. C is also
-a child of B. (The lines represent pointers between parent and child.
-Every node can have multiple parents and multiple children.)
-
-If we hold AC, and want to lock B, we recursively search through B's
-children to see if A or C appears. It does, so we reject the attempt.
-(A straightforward way to implement it: add a link from C to B, then
-determine whether the graph starting at B contains a cycle.)
-
-If we hold AC and want to lock D, we would succeed, creating a new link
-from C to D.
-
-Updates to MutexInfo structs are only allowed for the thread that holds
-the lock, so we actually do most of our deadlock prediction work after
-the lock has been acquired.
-*/
-
-#if PTHREAD_DEBUG_ENABLED
-
-// =============================================================================
-// log functions
-// =============================================================================
-
-#define LOGD(format, ...) \
- __libc_format_log(ANDROID_LOG_DEBUG, "pthread_debug", (format), ##__VA_ARGS__ )
-
-#define LOGW(format, ...) \
- __libc_format_log(ANDROID_LOG_WARN, "pthread_debug", (format), ##__VA_ARGS__ )
-
-#define LOGE(format, ...) \
- __libc_format_log(ANDROID_LOG_ERROR, "pthread_debug", (format), ##__VA_ARGS__ )
-
-#define LOGI(format, ...) \
- __libc_format_log(ANDROID_LOG_INFO, "pthread_debug", (format), ##__VA_ARGS__ )
-
-static const char* const kStartBanner =
- "===============================================================";
-
-static const char* const kEndBanner =
- "===============================================================";
-
-extern const char* __progname;
-
-#define STACK_TRACE_DEPTH 16
-
-/****************************************************************************/
-
-/*
- * level <= 0 : deadlock prediction disabled
- * level 1 : deadlock prediction enabled, w/o call stacks
- * level 2 : deadlock prediction enabled w/ call stacks
- */
-#define CAPTURE_CALLSTACK 2
-static int g_pthread_debug_level = 0;
-static pid_t g_pthread_debug_disabled_thread = -1;
-static pthread_mutex_t g_dbg_lock = PTHREAD_MUTEX_INITIALIZER;
-
-/****************************************************************************/
-
-/* some simple/lame malloc replacement
- * NOT thread-safe and leaks everything
- */
-
-#define DBG_ALLOC_BLOCK_SIZE PAGESIZE
-static size_t g_dbg_alloc_offset = DBG_ALLOC_BLOCK_SIZE;
-static char* g_dbg_alloc_ptr = NULL;
-
-template <typename T>
-static T* DbgAllocLocked(size_t count = 1) {
- size_t size = sizeof(T) * count;
- if ((g_dbg_alloc_offset + size) > DBG_ALLOC_BLOCK_SIZE) {
- g_dbg_alloc_offset = 0;
- g_dbg_alloc_ptr = reinterpret_cast<char*>(mmap(NULL, DBG_ALLOC_BLOCK_SIZE,
- PROT_READ|PROT_WRITE,
- MAP_ANON | MAP_PRIVATE, 0, 0));
- if (g_dbg_alloc_ptr == MAP_FAILED) {
- return NULL;
- }
- }
- void* addr = g_dbg_alloc_ptr + g_dbg_alloc_offset;
- g_dbg_alloc_offset += size;
- return reinterpret_cast<T*>(addr);
-}
-
-static void* debug_realloc(void *ptr, size_t size, size_t old_size) {
- void* addr = mmap(NULL, size, PROT_READ|PROT_WRITE,
- MAP_ANON | MAP_PRIVATE, 0, 0);
- if (addr != MAP_FAILED) {
- if (ptr) {
- memcpy(addr, ptr, old_size);
- munmap(ptr, old_size);
- }
- } else {
- addr = NULL;
- }
- return addr;
-}
-
-/*****************************************************************************/
-
-struct MutexInfo;
-
-typedef struct CallStack {
- uintptr_t depth;
- uintptr_t* addrs;
-} CallStack;
-
-typedef struct MutexInfo* MutexInfoListEntry;
-typedef struct CallStack CallStackListEntry;
-
-typedef struct GrowingList {
- int alloc;
- int count;
- union {
- void* data;
- MutexInfoListEntry* list;
- CallStackListEntry* stack;
- };
-} GrowingList;
-
-typedef GrowingList MutexInfoList;
-typedef GrowingList CallStackList;
-
-typedef struct MutexInfo {
- // thread currently holding the lock or 0
- pid_t owner;
-
- // most-recently-locked doubly-linked list
- struct MutexInfo* prev;
- struct MutexInfo* next;
-
- // for reentrant locks
- int lockCount;
- // when looking for loops in the graph, marks visited nodes
- int historyMark;
- // the actual mutex
- pthread_mutex_t* mutex;
- // list of locks directly acquired AFTER this one in the same thread
- MutexInfoList children;
- // list of locks directly acquired BEFORE this one in the same thread
- MutexInfoList parents;
- // list of call stacks when a new link is established to this lock form its parent
- CallStackList stacks;
- // call stack when this lock was acquired last
- int stackDepth;
- uintptr_t stackTrace[STACK_TRACE_DEPTH];
-} MutexInfo;
-
-static void growingListInit(GrowingList* list) {
- list->alloc = 0;
- list->count = 0;
- list->data = NULL;
-}
-
-static void growingListAdd(GrowingList* pList, size_t objSize) {
- if (pList->count == pList->alloc) {
- size_t oldsize = pList->alloc * objSize;
- pList->alloc += PAGESIZE / objSize;
- size_t size = pList->alloc * objSize;
- pList->data = debug_realloc(pList->data, size, oldsize);
- }
- pList->count++;
-}
-
-static void initMutexInfo(MutexInfo* object, pthread_mutex_t* mutex) {
- object->owner = 0;
- object->prev = 0;
- object->next = 0;
- object->lockCount = 0;
- object->historyMark = 0;
- object->mutex = mutex;
- growingListInit(&object->children);
- growingListInit(&object->parents);
- growingListInit(&object->stacks);
- object->stackDepth = 0;
-}
-
-typedef struct ThreadInfo {
- pid_t pid;
- MutexInfo* mrl;
-} ThreadInfo;
-
-static void initThreadInfo(ThreadInfo* object, pid_t pid) {
- object->pid = pid;
- object->mrl = NULL;
-}
-
-/****************************************************************************/
-
-static MutexInfo* get_mutex_info(pthread_mutex_t *mutex);
-static void mutex_lock_checked(MutexInfo* mrl, MutexInfo* object);
-static void mutex_unlock_checked(MutexInfo* object);
-
-/****************************************************************************/
-
-extern "C" int pthread_mutex_lock_impl(pthread_mutex_t *mutex);
-extern "C" int pthread_mutex_unlock_impl(pthread_mutex_t *mutex);
-
-static int pthread_mutex_lock_unchecked(pthread_mutex_t *mutex) {
- return pthread_mutex_lock_impl(mutex);
-}
-
-static int pthread_mutex_unlock_unchecked(pthread_mutex_t *mutex) {
- return pthread_mutex_unlock_impl(mutex);
-}
-
-/****************************************************************************/
-
-static void dup_backtrace(CallStack* stack, size_t count, uintptr_t const* addrs) {
- stack->depth = count;
- stack->addrs = DbgAllocLocked<uintptr_t>(count);
- memcpy(stack->addrs, addrs, count * sizeof(uintptr_t));
-}
-
-/****************************************************************************/
-
-static int historyListHas(
- const MutexInfoList* list, MutexInfo const * obj) {
- int i;
- for (i=0; i<list->count; i++) {
- if (list->list[i] == obj) {
- return i;
- }
- }
- return -1;
-}
-
-static void historyListAdd(MutexInfoList* pList, MutexInfo* obj) {
- growingListAdd(pList, sizeof(MutexInfoListEntry));
- pList->list[pList->count - 1] = obj;
-}
-
-static int historyListRemove(MutexInfoList* pList, MutexInfo* obj) {
- int i;
- for (i = pList->count-1; i >= 0; i--) {
- if (pList->list[i] == obj) {
- break;
- }
- }
- if (i < 0) {
- // not found!
- return 0;
- }
-
- if (i != pList->count-1) {
- // copy the last entry to the new free slot
- pList->list[i] = pList->list[pList->count-1];
- }
- pList->count--;
- memset(&pList->list[pList->count], 0, sizeof(MutexInfoListEntry));
- return 1;
-}
-
-static void linkParentToChild(MutexInfo* parent, MutexInfo* child) {
- historyListAdd(&parent->children, child);
- historyListAdd(&child->parents, parent);
-}
-
-static void unlinkParentFromChild(MutexInfo* parent, MutexInfo* child) {
- historyListRemove(&parent->children, child);
- historyListRemove(&child->parents, parent);
-}
-
-/****************************************************************************/
-
-static void callstackListAdd(CallStackList* pList,
- int count, uintptr_t const* addrs) {
- growingListAdd(pList, sizeof(CallStackListEntry));
- dup_backtrace(&pList->stack[pList->count - 1], count, addrs);
-}
-
-/****************************************************************************/
-
-/*
- * Recursively traverse the object hierarchy starting at "obj". We mark
- * ourselves on entry and clear the mark on exit. If we ever encounter
- * a marked object, we have a cycle.
- *
- * Returns "true" if all is well, "false" if we found a cycle.
- */
-
-static int traverseTree(MutexInfo* obj, MutexInfo const* objParent)
-{
- /*
- * Have we been here before?
- */
- if (obj->historyMark) {
- int stackDepth;
- uintptr_t addrs[STACK_TRACE_DEPTH];
-
- /* Turn off prediction temporarily in this thread while logging */
- g_pthread_debug_disabled_thread = gettid();
-
- backtrace_startup();
-
- LOGW("%s\n", kStartBanner);
- LOGW("pid: %d, tid: %d >>> %s <<<", getpid(), gettid(), __progname);
- LOGW("Illegal lock attempt:\n");
- LOGW("--- pthread_mutex_t at %p\n", obj->mutex);
- stackDepth = get_backtrace(addrs, STACK_TRACE_DEPTH);
- log_backtrace(addrs, stackDepth);
-
- LOGW("+++ Currently held locks in this thread (in reverse order):");
- MutexInfo* cur = obj;
- pid_t ourtid = gettid();
- int i;
- for (i=0 ; i<cur->parents.count ; i++) {
- MutexInfo* parent = cur->parents.list[i];
- if (parent->owner == ourtid) {
- LOGW("--- pthread_mutex_t at %p\n", parent->mutex);
- if (g_pthread_debug_level >= CAPTURE_CALLSTACK) {
- log_backtrace(parent->stackTrace, parent->stackDepth);
- }
- cur = parent;
- break;
- }
- }
-
- LOGW("+++ Earlier, the following lock order (from last to first) was established\n");
- return 0;
- }
-
- obj->historyMark = 1;
-
- MutexInfoList* pList = &obj->children;
- int result = 1;
- int i;
- for (i = pList->count-1; i >= 0; i--) {
- MutexInfo* child = pList->list[i];
- if (!traverseTree(child, obj)) {
- LOGW("--- pthread_mutex_t at %p\n", obj->mutex);
- if (g_pthread_debug_level >= CAPTURE_CALLSTACK) {
- int index = historyListHas(&obj->parents, objParent);
- if ((size_t)index < (size_t)obj->stacks.count) {
- log_backtrace(obj->stacks.stack[index].addrs, obj->stacks.stack[index].depth);
- } else {
- log_backtrace(obj->stackTrace, obj->stackDepth);
- }
- }
- result = 0;
- break;
- }
- }
-
- obj->historyMark = 0;
- return result;
-}
-
-/****************************************************************************/
-
-static void mutex_lock_checked(MutexInfo* mrl, MutexInfo* object)
-{
- pid_t tid = gettid();
- if (object->owner == tid) {
- object->lockCount++;
- return;
- }
-
- object->owner = tid;
- object->lockCount = 0;
-
- if (g_pthread_debug_level >= CAPTURE_CALLSTACK) {
- // always record the call stack when acquiring a lock.
- // it's not efficient, but is useful during diagnostics
- object->stackDepth = get_backtrace(object->stackTrace, STACK_TRACE_DEPTH);
- }
-
- // no other locks held in this thread -- no deadlock possible!
- if (mrl == NULL)
- return;
-
- // check if the lock we're trying to acquire is a direct descendant of
- // the most recently locked mutex in this thread, in which case we're
- // in a good situation -- no deadlock possible
- if (historyListHas(&mrl->children, object) >= 0)
- return;
-
- pthread_mutex_lock_unchecked(&g_dbg_lock);
-
- linkParentToChild(mrl, object);
- if (!traverseTree(object, mrl)) {
- backtrace_shutdown();
- LOGW("%s\n", kEndBanner);
- unlinkParentFromChild(mrl, object);
- // reenable pthread debugging for this thread
- g_pthread_debug_disabled_thread = -1;
- } else {
- // record the call stack for this link
- // NOTE: the call stack is added at the same index
- // as mrl in object->parents[]
- // ie: object->parents.count == object->stacks.count, which is
- // also the index.
- if (g_pthread_debug_level >= CAPTURE_CALLSTACK) {
- callstackListAdd(&object->stacks,
- object->stackDepth, object->stackTrace);
- }
- }
-
- pthread_mutex_unlock_unchecked(&g_dbg_lock);
-}
-
-static void mutex_unlock_checked(MutexInfo* object)
-{
- pid_t tid = gettid();
- if (object->owner == tid) {
- if (object->lockCount == 0) {
- object->owner = 0;
- } else {
- object->lockCount--;
- }
- }
-}
-
-
-// =============================================================================
-// Hash Table functions
-// =============================================================================
-
-/****************************************************************************/
-
-#define HASHTABLE_SIZE 256
-
-typedef struct HashEntry HashEntry;
-struct HashEntry {
- size_t slot;
- HashEntry* prev;
- HashEntry* next;
- void* data;
-};
-
-typedef struct HashTable HashTable;
-struct HashTable {
- HashEntry* slots[HASHTABLE_SIZE];
-};
-
-static HashTable g_mutex_map;
-static HashTable g_thread_map;
-
-/****************************************************************************/
-
-static uint32_t get_hashcode(void const * key, size_t keySize)
-{
- uint32_t h = keySize;
- char const* data = (char const*)key;
- size_t i;
- for (i = 0; i < keySize; i++) {
- h = h * 31 + *data;
- data++;
- }
- return (uint32_t)h;
-}
-
-static size_t get_index(uint32_t h)
-{
- // We apply this secondary hashing discovered by Doug Lea to defend
- // against bad hashes.
- h += ~(h << 9);
- h ^= (((unsigned int) h) >> 14);
- h += (h << 4);
- h ^= (((unsigned int) h) >> 10);
- return (size_t)h & (HASHTABLE_SIZE - 1);
-}
-
-/****************************************************************************/
-
-static void hashmap_init(HashTable* table) {
- memset(table, 0, sizeof(HashTable));
-}
-
-static void hashmap_removeEntry(HashTable* table, HashEntry* entry)
-{
- HashEntry* prev = entry->prev;
- HashEntry* next = entry->next;
- if (prev != NULL) entry->prev->next = next;
- if (next != NULL) entry->next->prev = prev;
- if (prev == NULL) {
- // we are the head of the list. set the head to be next
- table->slots[entry->slot] = entry->next;
- }
-}
-
-static HashEntry* hashmap_lookup(HashTable* table,
- void const* key, size_t ksize,
- int (*equals)(void const* data, void const* key))
-{
- const uint32_t hash = get_hashcode(key, ksize);
- const size_t slot = get_index(hash);
-
- HashEntry* entry = table->slots[slot];
- while (entry) {
- if (equals(entry->data, key)) {
- break;
- }
- entry = entry->next;
- }
-
- if (entry == NULL) {
- // create a new entry
- entry = DbgAllocLocked<HashEntry>();
- entry->data = NULL;
- entry->slot = slot;
- entry->prev = NULL;
- entry->next = table->slots[slot];
- if (entry->next != NULL) {
- entry->next->prev = entry;
- }
- table->slots[slot] = entry;
- }
- return entry;
-}
-
-/****************************************************************************/
-
-static int MutexInfo_equals(void const* data, void const* key) {
- return ((MutexInfo const *)data)->mutex == *(pthread_mutex_t **)key;
-}
-
-static MutexInfo* get_mutex_info(pthread_mutex_t *mutex)
-{
- pthread_mutex_lock_unchecked(&g_dbg_lock);
-
- HashEntry* entry = hashmap_lookup(&g_mutex_map,
- &mutex, sizeof(mutex),
- &MutexInfo_equals);
- if (entry->data == NULL) {
- MutexInfo* mutex_info = DbgAllocLocked<MutexInfo>();
- entry->data = mutex_info;
- initMutexInfo(mutex_info, mutex);
- }
-
- pthread_mutex_unlock_unchecked(&g_dbg_lock);
-
- return (MutexInfo *)entry->data;
-}
-
-/****************************************************************************/
-
-static int ThreadInfo_equals(void const* data, void const* key) {
- return ((ThreadInfo const *)data)->pid == *(pid_t *)key;
-}
-
-static ThreadInfo* get_thread_info(pid_t pid)
-{
- pthread_mutex_lock_unchecked(&g_dbg_lock);
-
- HashEntry* entry = hashmap_lookup(&g_thread_map,
- &pid, sizeof(pid),
- &ThreadInfo_equals);
- if (entry->data == NULL) {
- ThreadInfo* thread_info = DbgAllocLocked<ThreadInfo>();
- entry->data = thread_info;
- initThreadInfo(thread_info, pid);
- }
-
- pthread_mutex_unlock_unchecked(&g_dbg_lock);
-
- return (ThreadInfo *)entry->data;
-}
-
-static void push_most_recently_locked(MutexInfo* mrl) {
- ThreadInfo* tinfo = get_thread_info(gettid());
- mrl->next = NULL;
- mrl->prev = tinfo->mrl;
- tinfo->mrl = mrl;
-}
-
-static void remove_most_recently_locked(MutexInfo* mrl) {
- ThreadInfo* tinfo = get_thread_info(gettid());
- if (mrl->next) {
- (mrl->next)->prev = mrl->prev;
- }
- if (mrl->prev) {
- (mrl->prev)->next = mrl->next;
- }
- if (tinfo->mrl == mrl) {
- tinfo->mrl = mrl->next;
- }
-}
-
-static MutexInfo* get_most_recently_locked() {
- ThreadInfo* tinfo = get_thread_info(gettid());
- return tinfo->mrl;
-}
-
-/****************************************************************************/
-
-/*
- * See if we were allowed to grab the lock at this time. We do it
- * *after* acquiring the lock, rather than before, so that we can
- * freely update the MutexInfo struct. This seems counter-intuitive,
- * but our goal is deadlock *prediction* not deadlock *prevention*.
- * (If we actually deadlock, the situation is easy to diagnose from
- * a thread dump, so there's no point making a special effort to do
- * the checks before the lock is held.)
- */
-
-extern "C" __LIBC_HIDDEN__ void pthread_debug_mutex_lock_check(pthread_mutex_t *mutex)
-{
- if (g_pthread_debug_level == 0) return;
- // prediction disabled for this thread
- if (g_pthread_debug_disabled_thread == gettid())
- return;
- MutexInfo* object = get_mutex_info(mutex);
- MutexInfo* mrl = get_most_recently_locked();
- mutex_lock_checked(mrl, object);
- push_most_recently_locked(object);
-}
-
-/*
- * pthread_debug_mutex_unlock_check() must be called with the mutex
- * still held (ie: before calling the real unlock)
- */
-
-extern "C" __LIBC_HIDDEN__ void pthread_debug_mutex_unlock_check(pthread_mutex_t *mutex)
-{
- if (g_pthread_debug_level == 0) return;
- // prediction disabled for this thread
- if (g_pthread_debug_disabled_thread == gettid())
- return;
- MutexInfo* object = get_mutex_info(mutex);
- remove_most_recently_locked(object);
- mutex_unlock_checked(object);
-}
-
-#endif // PTHREAD_DEBUG_ENABLED
-
-// Called from libc_init_dynamic() just after system properties have been initialized.
-extern "C" __LIBC_HIDDEN__ void pthread_debug_init() {
-#if PTHREAD_DEBUG_ENABLED
- char env[PROP_VALUE_MAX];
- if (__system_property_get("debug.libc.pthread", env)) {
- int level = atoi(env);
- if (level) {
- LOGI("pthread deadlock detection level %d enabled for pid %d (%s)",
- level, getpid(), __progname);
- hashmap_init(&g_mutex_map);
- g_pthread_debug_level = level;
- }
- }
-#endif
-}
diff --git a/libc/bionic/pthread_mutex.cpp b/libc/bionic/pthread_mutex.cpp
index c4cd9e0..9fd5d32 100644
--- a/libc/bionic/pthread_mutex.cpp
+++ b/libc/bionic/pthread_mutex.cpp
@@ -445,9 +445,7 @@
}
}
-__LIBC_HIDDEN__
-int pthread_mutex_lock_impl(pthread_mutex_t *mutex)
-{
+int pthread_mutex_lock(pthread_mutex_t* mutex) {
int mvalue, mtype, tid, shared;
mvalue = mutex->value;
@@ -523,20 +521,7 @@
/* NOTREACHED */
}
-int pthread_mutex_lock(pthread_mutex_t *mutex)
-{
- int err = pthread_mutex_lock_impl(mutex);
- if (PTHREAD_DEBUG_ENABLED) {
- if (!err) {
- pthread_debug_mutex_lock_check(mutex);
- }
- }
- return err;
-}
-
-__LIBC_HIDDEN__
-int pthread_mutex_unlock_impl(pthread_mutex_t *mutex)
-{
+int pthread_mutex_unlock(pthread_mutex_t* mutex) {
int mvalue, mtype, tid, shared;
mvalue = mutex->value;
@@ -588,17 +573,7 @@
return 0;
}
-int pthread_mutex_unlock(pthread_mutex_t *mutex)
-{
- if (PTHREAD_DEBUG_ENABLED) {
- pthread_debug_mutex_unlock_check(mutex);
- }
- return pthread_mutex_unlock_impl(mutex);
-}
-
-__LIBC_HIDDEN__
-int pthread_mutex_trylock_impl(pthread_mutex_t *mutex)
-{
+int pthread_mutex_trylock(pthread_mutex_t* mutex) {
int mvalue, mtype, tid, shared;
mvalue = mutex->value;
@@ -638,17 +613,6 @@
return EBUSY;
}
-int pthread_mutex_trylock(pthread_mutex_t *mutex)
-{
- int err = pthread_mutex_trylock_impl(mutex);
- if (PTHREAD_DEBUG_ENABLED) {
- if (!err) {
- pthread_debug_mutex_lock_check(mutex);
- }
- }
- return err;
-}
-
static int __pthread_mutex_timedlock(pthread_mutex_t* mutex, const timespec* abs_timeout, clockid_t clock) {
timespec ts;
@@ -761,16 +725,11 @@
abs_timeout.tv_nsec -= 1000000000;
}
- int err = __pthread_mutex_timedlock(mutex, &abs_timeout, CLOCK_MONOTONIC);
- if (err == ETIMEDOUT) {
- err = EBUSY;
+ int error = __pthread_mutex_timedlock(mutex, &abs_timeout, CLOCK_MONOTONIC);
+ if (error == ETIMEDOUT) {
+ error = EBUSY;
}
- if (PTHREAD_DEBUG_ENABLED) {
- if (!err) {
- pthread_debug_mutex_lock_check(mutex);
- }
- }
- return err;
+ return error;
}
#endif
@@ -778,16 +737,12 @@
return __pthread_mutex_timedlock(mutex, abs_timeout, CLOCK_REALTIME);
}
-int pthread_mutex_destroy(pthread_mutex_t *mutex)
-{
- int ret;
-
- /* use trylock to ensure that the mutex value is
- * valid and is not already locked. */
- ret = pthread_mutex_trylock_impl(mutex);
- if (ret != 0)
- return ret;
-
- mutex->value = 0xdead10cc;
- return 0;
+int pthread_mutex_destroy(pthread_mutex_t* mutex) {
+ // Use trylock to ensure that the mutex is valid and not already locked.
+ int error = pthread_mutex_trylock(mutex);
+ if (error != 0) {
+ return error;
+ }
+ mutex->value = 0xdead10cc;
+ return 0;
}