Sergey Matveev | 56f77a7 | 2013-05-20 10:57:53 +0000 | [diff] [blame] | 1 | //=-- lsan_thread.cc ------------------------------------------------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file is a part of LeakSanitizer. |
| 11 | // See lsan_thread.h for details. |
| 12 | // |
| 13 | //===----------------------------------------------------------------------===// |
| 14 | |
| 15 | #include "lsan_thread.h" |
| 16 | |
| 17 | #include "sanitizer_common/sanitizer_common.h" |
| 18 | #include "sanitizer_common/sanitizer_placement_new.h" |
| 19 | #include "sanitizer_common/sanitizer_thread_registry.h" |
| 20 | #include "lsan_allocator.h" |
| 21 | |
| 22 | namespace __lsan { |
| 23 | |
| 24 | const u32 kInvalidTid = (u32) -1; |
| 25 | |
| 26 | static ThreadRegistry *thread_registry; |
| 27 | static THREADLOCAL u32 current_thread_tid = kInvalidTid; |
| 28 | |
| 29 | static ThreadContextBase *CreateThreadContext(u32 tid) { |
| 30 | void *mem = MmapOrDie(sizeof(ThreadContext), "ThreadContext"); |
| 31 | return new(mem) ThreadContext(tid); |
| 32 | } |
| 33 | |
| 34 | static const uptr kMaxThreads = 1 << 13; |
| 35 | static const uptr kThreadQuarantineSize = 64; |
| 36 | |
| 37 | void InitializeThreadRegistry() { |
| 38 | static char thread_registry_placeholder[sizeof(ThreadRegistry)] ALIGNED(64); |
| 39 | thread_registry = new(thread_registry_placeholder) |
| 40 | ThreadRegistry(CreateThreadContext, kMaxThreads, kThreadQuarantineSize); |
| 41 | } |
| 42 | |
| 43 | u32 GetCurrentThread() { |
| 44 | return current_thread_tid; |
| 45 | } |
| 46 | |
| 47 | void SetCurrentThread(u32 tid) { |
| 48 | current_thread_tid = tid; |
| 49 | } |
| 50 | |
| 51 | ThreadContext::ThreadContext(int tid) |
| 52 | : ThreadContextBase(tid), |
| 53 | stack_begin_(0), |
| 54 | stack_end_(0), |
| 55 | cache_begin_(0), |
| 56 | cache_end_(0), |
| 57 | tls_begin_(0), |
| 58 | tls_end_(0) {} |
| 59 | |
| 60 | struct OnStartedArgs { |
| 61 | uptr stack_begin, stack_end, |
| 62 | cache_begin, cache_end, |
| 63 | tls_begin, tls_end; |
| 64 | }; |
| 65 | |
| 66 | void ThreadContext::OnStarted(void *arg) { |
| 67 | OnStartedArgs *args = reinterpret_cast<OnStartedArgs *>(arg); |
| 68 | stack_begin_ = args->stack_begin; |
| 69 | stack_end_ = args->stack_end; |
| 70 | tls_begin_ = args->tls_begin; |
| 71 | tls_end_ = args->tls_end; |
| 72 | cache_begin_ = args->cache_begin; |
| 73 | cache_end_ = args->cache_end; |
| 74 | } |
| 75 | |
| 76 | void ThreadContext::OnFinished() { |
| 77 | AllocatorThreadFinish(); |
| 78 | } |
| 79 | |
| 80 | u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached) { |
| 81 | return thread_registry->CreateThread(user_id, detached, parent_tid, |
| 82 | /* arg */ 0); |
| 83 | } |
| 84 | |
| 85 | void ThreadStart(u32 tid, uptr os_id) { |
| 86 | OnStartedArgs args; |
| 87 | uptr stack_size = 0; |
| 88 | uptr tls_size = 0; |
| 89 | GetThreadStackAndTls(tid == 0, &args.stack_begin, &stack_size, |
| 90 | &args.tls_begin, &tls_size); |
| 91 | args.stack_end = args.stack_begin + stack_size; |
| 92 | args.tls_end = args.tls_begin + tls_size; |
| 93 | GetAllocatorCacheRange(&args.cache_begin, &args.cache_end); |
| 94 | thread_registry->StartThread(tid, os_id, &args); |
| 95 | } |
| 96 | |
| 97 | void ThreadFinish() { |
| 98 | thread_registry->FinishThread(GetCurrentThread()); |
| 99 | } |
| 100 | |
| 101 | ThreadContext *CurrentThreadContext() { |
| 102 | if (!thread_registry) return 0; |
| 103 | if (GetCurrentThread() == kInvalidTid) |
| 104 | return 0; |
| 105 | // No lock needed when getting current thread. |
| 106 | return (ThreadContext *)thread_registry->GetThreadLocked(GetCurrentThread()); |
| 107 | } |
| 108 | |
Sergey Matveev | 56f77a7 | 2013-05-20 10:57:53 +0000 | [diff] [blame] | 109 | static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) { |
| 110 | uptr uid = (uptr)arg; |
| 111 | if (tctx->user_id == uid && tctx->status != ThreadStatusInvalid) { |
| 112 | return true; |
| 113 | } |
| 114 | return false; |
| 115 | } |
| 116 | |
| 117 | u32 ThreadTid(uptr uid) { |
| 118 | return thread_registry->FindThread(FindThreadByUid, (void*)uid); |
| 119 | } |
| 120 | |
| 121 | void ThreadJoin(u32 tid) { |
| 122 | CHECK_NE(tid, kInvalidTid); |
| 123 | thread_registry->JoinThread(tid, /* arg */0); |
| 124 | } |
| 125 | |
Sergey Matveev | c6ac98d | 2013-07-08 12:57:24 +0000 | [diff] [blame] | 126 | void EnsureMainThreadIDIsCorrect() { |
| 127 | if (GetCurrentThread() == 0) |
| 128 | CurrentThreadContext()->os_id = GetTid(); |
| 129 | } |
| 130 | |
Sergey Matveev | 56f77a7 | 2013-05-20 10:57:53 +0000 | [diff] [blame] | 131 | ///// Interface to the common LSan module. ///// |
| 132 | |
| 133 | bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end, |
| 134 | uptr *tls_begin, uptr *tls_end, |
| 135 | uptr *cache_begin, uptr *cache_end) { |
Sergey Matveev | 98d3b40 | 2013-05-27 10:35:51 +0000 | [diff] [blame] | 136 | ThreadContext *context = static_cast<ThreadContext *>( |
| 137 | thread_registry->FindThreadContextByOsIDLocked(os_id)); |
| 138 | if (!context) return false; |
Sergey Matveev | 56f77a7 | 2013-05-20 10:57:53 +0000 | [diff] [blame] | 139 | *stack_begin = context->stack_begin(); |
| 140 | *stack_end = context->stack_end(); |
| 141 | *tls_begin = context->tls_begin(); |
| 142 | *tls_end = context->tls_end(); |
| 143 | *cache_begin = context->cache_begin(); |
| 144 | *cache_end = context->cache_end(); |
| 145 | return true; |
| 146 | } |
| 147 | |
Sergey Matveev | c519335 | 2013-10-14 14:04:50 +0000 | [diff] [blame] | 148 | void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback, |
| 149 | void *arg) { |
| 150 | } |
| 151 | |
Sergey Matveev | 56f77a7 | 2013-05-20 10:57:53 +0000 | [diff] [blame] | 152 | void LockThreadRegistry() { |
| 153 | thread_registry->Lock(); |
| 154 | } |
| 155 | |
| 156 | void UnlockThreadRegistry() { |
| 157 | thread_registry->Unlock(); |
| 158 | } |
| 159 | |
| 160 | } // namespace __lsan |