Home | History | Annotate | Download | only in lsan
      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 
    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 
    126 void EnsureMainThreadIDIsCorrect() {
    127   if (GetCurrentThread() == 0)
    128     CurrentThreadContext()->os_id = GetTid();
    129 }
    130 
    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) {
    136   ThreadContext *context = static_cast<ThreadContext *>(
    137       thread_registry->FindThreadContextByOsIDLocked(os_id));
    138   if (!context) return false;
    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 
    148 void LockThreadRegistry() {
    149   thread_registry->Lock();
    150 }
    151 
    152 void UnlockThreadRegistry() {
    153   thread_registry->Unlock();
    154 }
    155 
    156 }  // namespace __lsan
    157