1 /*
2 * Copyright (C) 2011 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/types.h>
30 #include <sys/atomics.h>
31 #include <sys/system_properties.h>
32 #include <sys/mman.h>
33
34 //#include <dlfcn.h>
35 #include <stdint.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <errno.h>
39 #include <pthread.h>
40 #include <unwind.h>
41 #include <unistd.h>
42
43 #include "bionic_tls.h"
44 #include "debug_mapinfo.h"
45 #include "debug_stacktrace.h"
46 #include "libc_logging.h"
47
48 /*
49 * ===========================================================================
50 * Deadlock prediction
51 * ===========================================================================
52 */
53 /*
54 The idea is to predict the possibility of deadlock by recording the order
55 in which locks are acquired. If we see an attempt to acquire a lock
56 out of order, we can identify the locks and offending code.
57
58 To make this work, we need to keep track of the locks held by each thread,
59 and create history trees for each lock. When a thread tries to acquire
60 a new lock, we walk through the "history children" of the lock, looking
61 for a match with locks the thread already holds. If we find a match,
62 it means the thread has made a request that could result in a deadlock.
63
64 To support recursive locks, we always allow re-locking a currently-held
65 lock, and maintain a recursion depth count.
66
67 An ASCII-art example, where letters represent locks:
68
69 A
70 /|\
71 / | \
72 B | D
73 \ |
74 \|
75 C
76
77 The above is the tree we'd have after handling lock synchronization
78 sequences "ABC", "AC", "AD". A has three children, {B, C, D}. C is also
79 a child of B. (The lines represent pointers between parent and child.
80 Every node can have multiple parents and multiple children.)
81
82 If we hold AC, and want to lock B, we recursively search through B's
83 children to see if A or C appears. It does, so we reject the attempt.
84 (A straightforward way to implement it: add a link from C to B, then
85 determine whether the graph starting at B contains a cycle.)
86
87 If we hold AC and want to lock D, we would succeed, creating a new link
88 from C to D.
89
90 Updates to MutexInfo structs are only allowed for the thread that holds
91 the lock, so we actually do most of our deadlock prediction work after
92 the lock has been acquired.
93 */
94
95 // =============================================================================
96 // log functions
97 // =============================================================================
98
99 #define LOGD(format, ...) \
100 __libc_format_log(ANDROID_LOG_DEBUG, "pthread_debug", (format), ##__VA_ARGS__ )
101
102 #define LOGW(format, ...) \
103 __libc_format_log(ANDROID_LOG_WARN, "pthread_debug", (format), ##__VA_ARGS__ )
104
105 #define LOGE(format, ...) \
106 __libc_format_log(ANDROID_LOG_ERROR, "pthread_debug", (format), ##__VA_ARGS__ )
107
108 #define LOGI(format, ...) \
109 __libc_format_log(ANDROID_LOG_INFO, "pthread_debug", (format), ##__VA_ARGS__ )
110
111 static const char* const kStartBanner =
112 "===============================================================";
113
114 static const char* const kEndBanner =
115 "===============================================================";
116
117 extern const char* __progname;
118
119 #define STACK_TRACE_DEPTH 16
120
121 /****************************************************************************/
122
123 /*
124 * level <= 0 : deadlock prediction disabled
125 * level 1 : deadlock prediction enabled, w/o call stacks
126 * level 2 : deadlock prediction enabled w/ call stacks
127 */
128 #define CAPTURE_CALLSTACK 2
129 static int sPthreadDebugLevel = 0;
130 static pid_t sPthreadDebugDisabledThread = -1;
131 static pthread_mutex_t sDbgLock = PTHREAD_MUTEX_INITIALIZER;
132
133 /****************************************************************************/
134
135 /* some simple/lame malloc replacement
136 * NOT thread-safe and leaks everything
137 */
138
139 #define DBG_ALLOC_BLOCK_SIZE PAGESIZE
140 static size_t sDbgAllocOffset = DBG_ALLOC_BLOCK_SIZE;
141 static char* sDbgAllocPtr = NULL;
142
143 template <typename T>
DbgAllocLocked(size_t count=1)144 static T* DbgAllocLocked(size_t count = 1) {
145 size_t size = sizeof(T) * count;
146 if ((sDbgAllocOffset + size) > DBG_ALLOC_BLOCK_SIZE) {
147 sDbgAllocOffset = 0;
148 sDbgAllocPtr = reinterpret_cast<char*>(mmap(NULL, DBG_ALLOC_BLOCK_SIZE,
149 PROT_READ|PROT_WRITE,
150 MAP_ANON | MAP_PRIVATE, 0, 0));
151 if (sDbgAllocPtr == MAP_FAILED) {
152 return NULL;
153 }
154 }
155 void* addr = sDbgAllocPtr + sDbgAllocOffset;
156 sDbgAllocOffset += size;
157 return reinterpret_cast<T*>(addr);
158 }
159
debug_realloc(void * ptr,size_t size,size_t old_size)160 static void* debug_realloc(void *ptr, size_t size, size_t old_size) {
161 void* addr = mmap(NULL, size, PROT_READ|PROT_WRITE,
162 MAP_ANON | MAP_PRIVATE, 0, 0);
163 if (addr != MAP_FAILED) {
164 if (ptr) {
165 memcpy(addr, ptr, old_size);
166 munmap(ptr, old_size);
167 }
168 } else {
169 addr = NULL;
170 }
171 return addr;
172 }
173
174 /*****************************************************************************/
175
176 struct MutexInfo;
177
178 typedef struct CallStack {
179 uintptr_t depth;
180 uintptr_t* addrs;
181 } CallStack;
182
183 typedef struct MutexInfo* MutexInfoListEntry;
184 typedef struct CallStack CallStackListEntry;
185
186 typedef struct GrowingList {
187 int alloc;
188 int count;
189 union {
190 void* data;
191 MutexInfoListEntry* list;
192 CallStackListEntry* stack;
193 };
194 } GrowingList;
195
196 typedef GrowingList MutexInfoList;
197 typedef GrowingList CallStackList;
198
199 typedef struct MutexInfo {
200 // thread currently holding the lock or 0
201 pid_t owner;
202
203 // most-recently-locked doubly-linked list
204 struct MutexInfo* prev;
205 struct MutexInfo* next;
206
207 // for reentrant locks
208 int lockCount;
209 // when looking for loops in the graph, marks visited nodes
210 int historyMark;
211 // the actual mutex
212 pthread_mutex_t* mutex;
213 // list of locks directly acquired AFTER this one in the same thread
214 MutexInfoList children;
215 // list of locks directly acquired BEFORE this one in the same thread
216 MutexInfoList parents;
217 // list of call stacks when a new link is established to this lock form its parent
218 CallStackList stacks;
219 // call stack when this lock was acquired last
220 int stackDepth;
221 uintptr_t stackTrace[STACK_TRACE_DEPTH];
222 } MutexInfo;
223
growingListInit(GrowingList * list)224 static void growingListInit(GrowingList* list) {
225 list->alloc = 0;
226 list->count = 0;
227 list->data = NULL;
228 }
229
growingListAdd(GrowingList * pList,size_t objSize)230 static void growingListAdd(GrowingList* pList, size_t objSize) {
231 if (pList->count == pList->alloc) {
232 size_t oldsize = pList->alloc * objSize;
233 pList->alloc += PAGESIZE / objSize;
234 size_t size = pList->alloc * objSize;
235 pList->data = debug_realloc(pList->data, size, oldsize);
236 }
237 pList->count++;
238 }
239
initMutexInfo(MutexInfo * object,pthread_mutex_t * mutex)240 static void initMutexInfo(MutexInfo* object, pthread_mutex_t* mutex) {
241 object->owner = 0;
242 object->prev = 0;
243 object->next = 0;
244 object->lockCount = 0;
245 object->historyMark = 0;
246 object->mutex = mutex;
247 growingListInit(&object->children);
248 growingListInit(&object->parents);
249 growingListInit(&object->stacks);
250 object->stackDepth = 0;
251 }
252
253 typedef struct ThreadInfo {
254 pid_t pid;
255 MutexInfo* mrl;
256 } ThreadInfo;
257
initThreadInfo(ThreadInfo * object,pid_t pid)258 static void initThreadInfo(ThreadInfo* object, pid_t pid) {
259 object->pid = pid;
260 object->mrl = NULL;
261 }
262
263 /****************************************************************************/
264
265 static MutexInfo* get_mutex_info(pthread_mutex_t *mutex);
266 static void mutex_lock_checked(MutexInfo* mrl, MutexInfo* object);
267 static void mutex_unlock_checked(MutexInfo* object);
268
269 /****************************************************************************/
270
271 extern "C" int pthread_mutex_lock_impl(pthread_mutex_t *mutex);
272 extern "C" int pthread_mutex_unlock_impl(pthread_mutex_t *mutex);
273
pthread_mutex_lock_unchecked(pthread_mutex_t * mutex)274 static int pthread_mutex_lock_unchecked(pthread_mutex_t *mutex) {
275 return pthread_mutex_lock_impl(mutex);
276 }
277
pthread_mutex_unlock_unchecked(pthread_mutex_t * mutex)278 static int pthread_mutex_unlock_unchecked(pthread_mutex_t *mutex) {
279 return pthread_mutex_unlock_impl(mutex);
280 }
281
282 /****************************************************************************/
283
dup_backtrace(CallStack * stack,size_t count,uintptr_t const * addrs)284 static void dup_backtrace(CallStack* stack, size_t count, uintptr_t const* addrs) {
285 stack->depth = count;
286 stack->addrs = DbgAllocLocked<uintptr_t>(count);
287 memcpy(stack->addrs, addrs, count * sizeof(uintptr_t));
288 }
289
290 /****************************************************************************/
291
historyListHas(const MutexInfoList * list,MutexInfo const * obj)292 static int historyListHas(
293 const MutexInfoList* list, MutexInfo const * obj) {
294 int i;
295 for (i=0; i<list->count; i++) {
296 if (list->list[i] == obj) {
297 return i;
298 }
299 }
300 return -1;
301 }
302
historyListAdd(MutexInfoList * pList,MutexInfo * obj)303 static void historyListAdd(MutexInfoList* pList, MutexInfo* obj) {
304 growingListAdd(pList, sizeof(MutexInfoListEntry));
305 pList->list[pList->count - 1] = obj;
306 }
307
historyListRemove(MutexInfoList * pList,MutexInfo * obj)308 static int historyListRemove(MutexInfoList* pList, MutexInfo* obj) {
309 int i;
310 for (i = pList->count-1; i >= 0; i--) {
311 if (pList->list[i] == obj) {
312 break;
313 }
314 }
315 if (i < 0) {
316 // not found!
317 return 0;
318 }
319
320 if (i != pList->count-1) {
321 // copy the last entry to the new free slot
322 pList->list[i] = pList->list[pList->count-1];
323 }
324 pList->count--;
325 memset(&pList->list[pList->count], 0, sizeof(MutexInfoListEntry));
326 return 1;
327 }
328
linkParentToChild(MutexInfo * parent,MutexInfo * child)329 static void linkParentToChild(MutexInfo* parent, MutexInfo* child) {
330 historyListAdd(&parent->children, child);
331 historyListAdd(&child->parents, parent);
332 }
333
unlinkParentFromChild(MutexInfo * parent,MutexInfo * child)334 static void unlinkParentFromChild(MutexInfo* parent, MutexInfo* child) {
335 historyListRemove(&parent->children, child);
336 historyListRemove(&child->parents, parent);
337 }
338
339 /****************************************************************************/
340
callstackListAdd(CallStackList * pList,int count,uintptr_t const * addrs)341 static void callstackListAdd(CallStackList* pList,
342 int count, uintptr_t const* addrs) {
343 growingListAdd(pList, sizeof(CallStackListEntry));
344 dup_backtrace(&pList->stack[pList->count - 1], count, addrs);
345 }
346
347 /****************************************************************************/
348
349 /*
350 * Recursively traverse the object hierarchy starting at "obj". We mark
351 * ourselves on entry and clear the mark on exit. If we ever encounter
352 * a marked object, we have a cycle.
353 *
354 * Returns "true" if all is well, "false" if we found a cycle.
355 */
356
traverseTree(MutexInfo * obj,MutexInfo const * objParent)357 static int traverseTree(MutexInfo* obj, MutexInfo const* objParent)
358 {
359 /*
360 * Have we been here before?
361 */
362 if (obj->historyMark) {
363 int stackDepth;
364 uintptr_t addrs[STACK_TRACE_DEPTH];
365
366 /* Turn off prediction temporarily in this thread while logging */
367 sPthreadDebugDisabledThread = gettid();
368
369 backtrace_startup();
370
371 LOGW("%s\n", kStartBanner);
372 LOGW("pid: %d, tid: %d >>> %s <<<", getpid(), gettid(), __progname);
373 LOGW("Illegal lock attempt:\n");
374 LOGW("--- pthread_mutex_t at %p\n", obj->mutex);
375 stackDepth = get_backtrace(addrs, STACK_TRACE_DEPTH);
376 log_backtrace(addrs, stackDepth);
377
378 LOGW("+++ Currently held locks in this thread (in reverse order):");
379 MutexInfo* cur = obj;
380 pid_t ourtid = gettid();
381 int i;
382 for (i=0 ; i<cur->parents.count ; i++) {
383 MutexInfo* parent = cur->parents.list[i];
384 if (parent->owner == ourtid) {
385 LOGW("--- pthread_mutex_t at %p\n", parent->mutex);
386 if (sPthreadDebugLevel >= CAPTURE_CALLSTACK) {
387 log_backtrace(parent->stackTrace, parent->stackDepth);
388 }
389 cur = parent;
390 break;
391 }
392 }
393
394 LOGW("+++ Earlier, the following lock order (from last to first) was established\n");
395 return 0;
396 }
397
398 obj->historyMark = 1;
399
400 MutexInfoList* pList = &obj->children;
401 int result = 1;
402 int i;
403 for (i = pList->count-1; i >= 0; i--) {
404 MutexInfo* child = pList->list[i];
405 if (!traverseTree(child, obj)) {
406 LOGW("--- pthread_mutex_t at %p\n", obj->mutex);
407 if (sPthreadDebugLevel >= CAPTURE_CALLSTACK) {
408 int index = historyListHas(&obj->parents, objParent);
409 if ((size_t)index < (size_t)obj->stacks.count) {
410 log_backtrace(obj->stacks.stack[index].addrs, obj->stacks.stack[index].depth);
411 } else {
412 log_backtrace(obj->stackTrace, obj->stackDepth);
413 }
414 }
415 result = 0;
416 break;
417 }
418 }
419
420 obj->historyMark = 0;
421 return result;
422 }
423
424 /****************************************************************************/
425
mutex_lock_checked(MutexInfo * mrl,MutexInfo * object)426 static void mutex_lock_checked(MutexInfo* mrl, MutexInfo* object)
427 {
428 pid_t tid = gettid();
429 if (object->owner == tid) {
430 object->lockCount++;
431 return;
432 }
433
434 object->owner = tid;
435 object->lockCount = 0;
436
437 if (sPthreadDebugLevel >= CAPTURE_CALLSTACK) {
438 // always record the call stack when acquiring a lock.
439 // it's not efficient, but is useful during diagnostics
440 object->stackDepth = get_backtrace(object->stackTrace, STACK_TRACE_DEPTH);
441 }
442
443 // no other locks held in this thread -- no deadlock possible!
444 if (mrl == NULL)
445 return;
446
447 // check if the lock we're trying to acquire is a direct descendant of
448 // the most recently locked mutex in this thread, in which case we're
449 // in a good situation -- no deadlock possible
450 if (historyListHas(&mrl->children, object) >= 0)
451 return;
452
453 pthread_mutex_lock_unchecked(&sDbgLock);
454
455 linkParentToChild(mrl, object);
456 if (!traverseTree(object, mrl)) {
457 backtrace_shutdown();
458 LOGW("%s\n", kEndBanner);
459 unlinkParentFromChild(mrl, object);
460 // reenable pthread debugging for this thread
461 sPthreadDebugDisabledThread = -1;
462 } else {
463 // record the call stack for this link
464 // NOTE: the call stack is added at the same index
465 // as mrl in object->parents[]
466 // ie: object->parents.count == object->stacks.count, which is
467 // also the index.
468 if (sPthreadDebugLevel >= CAPTURE_CALLSTACK) {
469 callstackListAdd(&object->stacks,
470 object->stackDepth, object->stackTrace);
471 }
472 }
473
474 pthread_mutex_unlock_unchecked(&sDbgLock);
475 }
476
mutex_unlock_checked(MutexInfo * object)477 static void mutex_unlock_checked(MutexInfo* object)
478 {
479 pid_t tid = gettid();
480 if (object->owner == tid) {
481 if (object->lockCount == 0) {
482 object->owner = 0;
483 } else {
484 object->lockCount--;
485 }
486 }
487 }
488
489
490 // =============================================================================
491 // Hash Table functions
492 // =============================================================================
493
494 /****************************************************************************/
495
496 #define HASHTABLE_SIZE 256
497
498 typedef struct HashEntry HashEntry;
499 struct HashEntry {
500 size_t slot;
501 HashEntry* prev;
502 HashEntry* next;
503 void* data;
504 };
505
506 typedef struct HashTable HashTable;
507 struct HashTable {
508 HashEntry* slots[HASHTABLE_SIZE];
509 };
510
511 static HashTable sMutexMap;
512 static HashTable sThreadMap;
513
514 /****************************************************************************/
515
get_hashcode(void const * key,size_t keySize)516 static uint32_t get_hashcode(void const * key, size_t keySize)
517 {
518 uint32_t h = keySize;
519 char const* data = (char const*)key;
520 size_t i;
521 for (i = 0; i < keySize; i++) {
522 h = h * 31 + *data;
523 data++;
524 }
525 return (uint32_t)h;
526 }
527
get_index(uint32_t h)528 static size_t get_index(uint32_t h)
529 {
530 // We apply this secondary hashing discovered by Doug Lea to defend
531 // against bad hashes.
532 h += ~(h << 9);
533 h ^= (((unsigned int) h) >> 14);
534 h += (h << 4);
535 h ^= (((unsigned int) h) >> 10);
536 return (size_t)h & (HASHTABLE_SIZE - 1);
537 }
538
539 /****************************************************************************/
540
hashmap_init(HashTable * table)541 static void hashmap_init(HashTable* table) {
542 memset(table, 0, sizeof(HashTable));
543 }
544
hashmap_removeEntry(HashTable * table,HashEntry * entry)545 static void hashmap_removeEntry(HashTable* table, HashEntry* entry)
546 {
547 HashEntry* prev = entry->prev;
548 HashEntry* next = entry->next;
549 if (prev != NULL) entry->prev->next = next;
550 if (next != NULL) entry->next->prev = prev;
551 if (prev == NULL) {
552 // we are the head of the list. set the head to be next
553 table->slots[entry->slot] = entry->next;
554 }
555 }
556
hashmap_lookup(HashTable * table,void const * key,size_t ksize,int (* equals)(void const * data,void const * key))557 static HashEntry* hashmap_lookup(HashTable* table,
558 void const* key, size_t ksize,
559 int (*equals)(void const* data, void const* key))
560 {
561 const uint32_t hash = get_hashcode(key, ksize);
562 const size_t slot = get_index(hash);
563
564 HashEntry* entry = table->slots[slot];
565 while (entry) {
566 if (equals(entry->data, key)) {
567 break;
568 }
569 entry = entry->next;
570 }
571
572 if (entry == NULL) {
573 // create a new entry
574 entry = DbgAllocLocked<HashEntry>();
575 entry->data = NULL;
576 entry->slot = slot;
577 entry->prev = NULL;
578 entry->next = table->slots[slot];
579 if (entry->next != NULL) {
580 entry->next->prev = entry;
581 }
582 table->slots[slot] = entry;
583 }
584 return entry;
585 }
586
587 /****************************************************************************/
588
MutexInfo_equals(void const * data,void const * key)589 static int MutexInfo_equals(void const* data, void const* key) {
590 return ((MutexInfo const *)data)->mutex == *(pthread_mutex_t **)key;
591 }
592
get_mutex_info(pthread_mutex_t * mutex)593 static MutexInfo* get_mutex_info(pthread_mutex_t *mutex)
594 {
595 pthread_mutex_lock_unchecked(&sDbgLock);
596
597 HashEntry* entry = hashmap_lookup(&sMutexMap,
598 &mutex, sizeof(mutex),
599 &MutexInfo_equals);
600 if (entry->data == NULL) {
601 MutexInfo* mutex_info = DbgAllocLocked<MutexInfo>();
602 entry->data = mutex_info;
603 initMutexInfo(mutex_info, mutex);
604 }
605
606 pthread_mutex_unlock_unchecked(&sDbgLock);
607
608 return (MutexInfo *)entry->data;
609 }
610
611 /****************************************************************************/
612
ThreadInfo_equals(void const * data,void const * key)613 static int ThreadInfo_equals(void const* data, void const* key) {
614 return ((ThreadInfo const *)data)->pid == *(pid_t *)key;
615 }
616
get_thread_info(pid_t pid)617 static ThreadInfo* get_thread_info(pid_t pid)
618 {
619 pthread_mutex_lock_unchecked(&sDbgLock);
620
621 HashEntry* entry = hashmap_lookup(&sThreadMap,
622 &pid, sizeof(pid),
623 &ThreadInfo_equals);
624 if (entry->data == NULL) {
625 ThreadInfo* thread_info = DbgAllocLocked<ThreadInfo>();
626 entry->data = thread_info;
627 initThreadInfo(thread_info, pid);
628 }
629
630 pthread_mutex_unlock_unchecked(&sDbgLock);
631
632 return (ThreadInfo *)entry->data;
633 }
634
push_most_recently_locked(MutexInfo * mrl)635 static void push_most_recently_locked(MutexInfo* mrl) {
636 ThreadInfo* tinfo = get_thread_info(gettid());
637 mrl->next = NULL;
638 mrl->prev = tinfo->mrl;
639 tinfo->mrl = mrl;
640 }
641
remove_most_recently_locked(MutexInfo * mrl)642 static void remove_most_recently_locked(MutexInfo* mrl) {
643 ThreadInfo* tinfo = get_thread_info(gettid());
644 if (mrl->next) {
645 (mrl->next)->prev = mrl->prev;
646 }
647 if (mrl->prev) {
648 (mrl->prev)->next = mrl->next;
649 }
650 if (tinfo->mrl == mrl) {
651 tinfo->mrl = mrl->next;
652 }
653 }
654
get_most_recently_locked()655 static MutexInfo* get_most_recently_locked() {
656 ThreadInfo* tinfo = get_thread_info(gettid());
657 return tinfo->mrl;
658 }
659
660 /****************************************************************************/
661
662 /* pthread_debug_init() is called from libc_init_dynamic() just
663 * after system properties have been initialized
664 */
665
pthread_debug_init()666 extern "C" __LIBC_HIDDEN__ void pthread_debug_init() {
667 char env[PROP_VALUE_MAX];
668 if (__system_property_get("debug.libc.pthread", env)) {
669 int level = atoi(env);
670 if (level) {
671 LOGI("pthread deadlock detection level %d enabled for pid %d (%s)",
672 level, getpid(), __progname);
673 hashmap_init(&sMutexMap);
674 sPthreadDebugLevel = level;
675 }
676 }
677 }
678
679 /*
680 * See if we were allowed to grab the lock at this time. We do it
681 * *after* acquiring the lock, rather than before, so that we can
682 * freely update the MutexInfo struct. This seems counter-intuitive,
683 * but our goal is deadlock *prediction* not deadlock *prevention*.
684 * (If we actually deadlock, the situation is easy to diagnose from
685 * a thread dump, so there's no point making a special effort to do
686 * the checks before the lock is held.)
687 */
688
pthread_debug_mutex_lock_check(pthread_mutex_t * mutex)689 extern "C" __LIBC_HIDDEN__ void pthread_debug_mutex_lock_check(pthread_mutex_t *mutex)
690 {
691 if (sPthreadDebugLevel == 0) return;
692 // prediction disabled for this thread
693 if (sPthreadDebugDisabledThread == gettid())
694 return;
695 MutexInfo* object = get_mutex_info(mutex);
696 MutexInfo* mrl = get_most_recently_locked();
697 mutex_lock_checked(mrl, object);
698 push_most_recently_locked(object);
699 }
700
701 /*
702 * pthread_debug_mutex_unlock_check() must be called with the mutex
703 * still held (ie: before calling the real unlock)
704 */
705
pthread_debug_mutex_unlock_check(pthread_mutex_t * mutex)706 extern "C" __LIBC_HIDDEN__ void pthread_debug_mutex_unlock_check(pthread_mutex_t *mutex)
707 {
708 if (sPthreadDebugLevel == 0) return;
709 // prediction disabled for this thread
710 if (sPthreadDebugDisabledThread == gettid())
711 return;
712 MutexInfo* object = get_mutex_info(mutex);
713 remove_most_recently_locked(object);
714 mutex_unlock_checked(object);
715 }
716