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