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