1 //===-- sanitizer_thread_registry.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 shared between sanitizer tools.
10 //
11 // General thread bookkeeping functionality.
12 //===----------------------------------------------------------------------===//
13 
14 #include "sanitizer_thread_registry.h"
15 
16 namespace __sanitizer {
17 
18 ThreadContextBase::ThreadContextBase(u32 tid)
19     : tid(tid), unique_id(0), reuse_count(), os_id(0), user_id(0),
20       status(ThreadStatusInvalid), detached(false),
21       thread_type(ThreadType::Regular), parent_tid(0), next(0) {
22   name[0] = '\0';
23   atomic_store(&thread_destroyed, 0, memory_order_release);
24 }
25 
26 ThreadContextBase::~ThreadContextBase() {
27   // ThreadContextBase should never be deleted.
28   CHECK(0);
29 }
30 
31 void ThreadContextBase::SetName(const char *new_name) {
32   name[0] = '\0';
33   if (new_name) {
34     internal_strncpy(name, new_name, sizeof(name));
35     name[sizeof(name) - 1] = '\0';
36   }
37 }
38 
39 void ThreadContextBase::SetDead() {
40   CHECK(status == ThreadStatusRunning ||
41         status == ThreadStatusFinished);
42   status = ThreadStatusDead;
43   user_id = 0;
44   OnDead();
45 }
46 
47 void ThreadContextBase::SetDestroyed() {
48   atomic_store(&thread_destroyed, 1, memory_order_release);
49 }
50 
51 bool ThreadContextBase::GetDestroyed() {
52   return !!atomic_load(&thread_destroyed, memory_order_acquire);
53 }
54 
55 void ThreadContextBase::SetJoined(void *arg) {
56   // FIXME(dvyukov): print message and continue (it's user error).
57   CHECK_EQ(false, detached);
58   CHECK_EQ(ThreadStatusFinished, status);
59   status = ThreadStatusDead;
60   user_id = 0;
61   OnJoined(arg);
62 }
63 
64 void ThreadContextBase::SetFinished() {
65   // ThreadRegistry::FinishThread calls here in ThreadStatusCreated state
66   // for a thread that never actually started.  In that case the thread
67   // should go to ThreadStatusFinished regardless of whether it was created
68   // as detached.
69   if (!detached || status == ThreadStatusCreated) status = ThreadStatusFinished;
70   OnFinished();
71 }
72 
73 void ThreadContextBase::SetStarted(tid_t _os_id, ThreadType _thread_type,
74                                    void *arg) {
75   status = ThreadStatusRunning;
76   os_id = _os_id;
77   thread_type = _thread_type;
78   OnStarted(arg);
79 }
80 
81 void ThreadContextBase::SetCreated(uptr _user_id, u64 _unique_id,
82                                    bool _detached, u32 _parent_tid, void *arg) {
83   status = ThreadStatusCreated;
84   user_id = _user_id;
85   unique_id = _unique_id;
86   detached = _detached;
87   // Parent tid makes no sense for the main thread.
88   if (tid != kMainTid)
89     parent_tid = _parent_tid;
90   OnCreated(arg);
91 }
92 
93 void ThreadContextBase::Reset() {
94   status = ThreadStatusInvalid;
95   SetName(0);
96   atomic_store(&thread_destroyed, 0, memory_order_release);
97   OnReset();
98 }
99 
100 // ThreadRegistry implementation.
101 
102 ThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
103                                u32 thread_quarantine_size, u32 max_reuse)
104     : context_factory_(factory),
105       max_threads_(max_threads),
106       thread_quarantine_size_(thread_quarantine_size),
107       max_reuse_(max_reuse),
108       mtx_(),
109       n_contexts_(0),
110       total_threads_(0),
111       alive_threads_(0),
112       max_alive_threads_(0),
113       running_threads_(0) {
114   threads_ = (ThreadContextBase **)MmapOrDie(max_threads_ * sizeof(threads_[0]),
115                                              "ThreadRegistry");
116   dead_threads_.clear();
117   invalid_threads_.clear();
118 }
119 
120 void ThreadRegistry::GetNumberOfThreads(uptr *total, uptr *running,
121                                         uptr *alive) {
122   BlockingMutexLock l(&mtx_);
123   if (total) *total = n_contexts_;
124   if (running) *running = running_threads_;
125   if (alive) *alive = alive_threads_;
126 }
127 
128 uptr ThreadRegistry::GetMaxAliveThreads() {
129   BlockingMutexLock l(&mtx_);
130   return max_alive_threads_;
131 }
132 
133 u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid,
134                                  void *arg) {
135   BlockingMutexLock l(&mtx_);
136   u32 tid = kInvalidTid;
137   ThreadContextBase *tctx = QuarantinePop();
138   if (tctx) {
139     tid = tctx->tid;
140   } else if (n_contexts_ < max_threads_) {
141     // Allocate new thread context and tid.
142     tid = n_contexts_++;
143     tctx = context_factory_(tid);
144     threads_[tid] = tctx;
145   } else {
146 #if !SANITIZER_GO
147     Report("%s: Thread limit (%u threads) exceeded. Dying.\n",
148            SanitizerToolName, max_threads_);
149 #else
150     Printf("race: limit on %u simultaneously alive goroutines is exceeded,"
151         " dying\n", max_threads_);
152 #endif
153     Die();
154   }
155   CHECK_NE(tctx, 0);
156   CHECK_NE(tid, kInvalidTid);
157   CHECK_LT(tid, max_threads_);
158   CHECK_EQ(tctx->status, ThreadStatusInvalid);
159   alive_threads_++;
160   if (max_alive_threads_ < alive_threads_) {
161     max_alive_threads_++;
162     CHECK_EQ(alive_threads_, max_alive_threads_);
163   }
164   tctx->SetCreated(user_id, total_threads_++, detached,
165                    parent_tid, arg);
166   return tid;
167 }
168 
169 void ThreadRegistry::RunCallbackForEachThreadLocked(ThreadCallback cb,
170                                                     void *arg) {
171   CheckLocked();
172   for (u32 tid = 0; tid < n_contexts_; tid++) {
173     ThreadContextBase *tctx = threads_[tid];
174     if (tctx == 0)
175       continue;
176     cb(tctx, arg);
177   }
178 }
179 
180 u32 ThreadRegistry::FindThread(FindThreadCallback cb, void *arg) {
181   BlockingMutexLock l(&mtx_);
182   for (u32 tid = 0; tid < n_contexts_; tid++) {
183     ThreadContextBase *tctx = threads_[tid];
184     if (tctx != 0 && cb(tctx, arg))
185       return tctx->tid;
186   }
187   return kInvalidTid;
188 }
189 
190 ThreadContextBase *
191 ThreadRegistry::FindThreadContextLocked(FindThreadCallback cb, void *arg) {
192   CheckLocked();
193   for (u32 tid = 0; tid < n_contexts_; tid++) {
194     ThreadContextBase *tctx = threads_[tid];
195     if (tctx != 0 && cb(tctx, arg))
196       return tctx;
197   }
198   return 0;
199 }
200 
201 static bool FindThreadContextByOsIdCallback(ThreadContextBase *tctx,
202                                             void *arg) {
203   return (tctx->os_id == (uptr)arg && tctx->status != ThreadStatusInvalid &&
204       tctx->status != ThreadStatusDead);
205 }
206 
207 ThreadContextBase *ThreadRegistry::FindThreadContextByOsIDLocked(tid_t os_id) {
208   return FindThreadContextLocked(FindThreadContextByOsIdCallback,
209                                  (void *)os_id);
210 }
211 
212 void ThreadRegistry::SetThreadName(u32 tid, const char *name) {
213   BlockingMutexLock l(&mtx_);
214   CHECK_LT(tid, n_contexts_);
215   ThreadContextBase *tctx = threads_[tid];
216   CHECK_NE(tctx, 0);
217   CHECK_EQ(SANITIZER_FUCHSIA ? ThreadStatusCreated : ThreadStatusRunning,
218            tctx->status);
219   tctx->SetName(name);
220 }
221 
222 void ThreadRegistry::SetThreadNameByUserId(uptr user_id, const char *name) {
223   BlockingMutexLock l(&mtx_);
224   for (u32 tid = 0; tid < n_contexts_; tid++) {
225     ThreadContextBase *tctx = threads_[tid];
226     if (tctx != 0 && tctx->user_id == user_id &&
227         tctx->status != ThreadStatusInvalid) {
228       tctx->SetName(name);
229       return;
230     }
231   }
232 }
233 
234 void ThreadRegistry::DetachThread(u32 tid, void *arg) {
235   BlockingMutexLock l(&mtx_);
236   CHECK_LT(tid, n_contexts_);
237   ThreadContextBase *tctx = threads_[tid];
238   CHECK_NE(tctx, 0);
239   if (tctx->status == ThreadStatusInvalid) {
240     Report("%s: Detach of non-existent thread\n", SanitizerToolName);
241     return;
242   }
243   tctx->OnDetached(arg);
244   if (tctx->status == ThreadStatusFinished) {
245     tctx->SetDead();
246     QuarantinePush(tctx);
247   } else {
248     tctx->detached = true;
249   }
250 }
251 
252 void ThreadRegistry::JoinThread(u32 tid, void *arg) {
253   bool destroyed = false;
254   do {
255     {
256       BlockingMutexLock l(&mtx_);
257       CHECK_LT(tid, n_contexts_);
258       ThreadContextBase *tctx = threads_[tid];
259       CHECK_NE(tctx, 0);
260       if (tctx->status == ThreadStatusInvalid) {
261         Report("%s: Join of non-existent thread\n", SanitizerToolName);
262         return;
263       }
264       if ((destroyed = tctx->GetDestroyed())) {
265         tctx->SetJoined(arg);
266         QuarantinePush(tctx);
267       }
268     }
269     if (!destroyed)
270       internal_sched_yield();
271   } while (!destroyed);
272 }
273 
274 // Normally this is called when the thread is about to exit.  If
275 // called in ThreadStatusCreated state, then this thread was never
276 // really started.  We just did CreateThread for a prospective new
277 // thread before trying to create it, and then failed to actually
278 // create it, and so never called StartThread.
279 ThreadStatus ThreadRegistry::FinishThread(u32 tid) {
280   BlockingMutexLock l(&mtx_);
281   CHECK_GT(alive_threads_, 0);
282   alive_threads_--;
283   CHECK_LT(tid, n_contexts_);
284   ThreadContextBase *tctx = threads_[tid];
285   CHECK_NE(tctx, 0);
286   bool dead = tctx->detached;
287   ThreadStatus prev_status = tctx->status;
288   if (tctx->status == ThreadStatusRunning) {
289     CHECK_GT(running_threads_, 0);
290     running_threads_--;
291   } else {
292     // The thread never really existed.
293     CHECK_EQ(tctx->status, ThreadStatusCreated);
294     dead = true;
295   }
296   tctx->SetFinished();
297   if (dead) {
298     tctx->SetDead();
299     QuarantinePush(tctx);
300   }
301   tctx->SetDestroyed();
302   return prev_status;
303 }
304 
305 void ThreadRegistry::StartThread(u32 tid, tid_t os_id, ThreadType thread_type,
306                                  void *arg) {
307   BlockingMutexLock l(&mtx_);
308   running_threads_++;
309   CHECK_LT(tid, n_contexts_);
310   ThreadContextBase *tctx = threads_[tid];
311   CHECK_NE(tctx, 0);
312   CHECK_EQ(ThreadStatusCreated, tctx->status);
313   tctx->SetStarted(os_id, thread_type, arg);
314 }
315 
316 void ThreadRegistry::QuarantinePush(ThreadContextBase *tctx) {
317   if (tctx->tid == 0)
318     return;  // Don't reuse the main thread.  It's a special snowflake.
319   dead_threads_.push_back(tctx);
320   if (dead_threads_.size() <= thread_quarantine_size_)
321     return;
322   tctx = dead_threads_.front();
323   dead_threads_.pop_front();
324   CHECK_EQ(tctx->status, ThreadStatusDead);
325   tctx->Reset();
326   tctx->reuse_count++;
327   if (max_reuse_ > 0 && tctx->reuse_count >= max_reuse_)
328     return;
329   invalid_threads_.push_back(tctx);
330 }
331 
332 ThreadContextBase *ThreadRegistry::QuarantinePop() {
333   if (invalid_threads_.size() == 0)
334     return 0;
335   ThreadContextBase *tctx = invalid_threads_.front();
336   invalid_threads_.pop_front();
337   return tctx;
338 }
339 
340 void ThreadRegistry::SetThreadUserId(u32 tid, uptr user_id) {
341   BlockingMutexLock l(&mtx_);
342   CHECK_LT(tid, n_contexts_);
343   ThreadContextBase *tctx = threads_[tid];
344   CHECK_NE(tctx, 0);
345   CHECK_NE(tctx->status, ThreadStatusInvalid);
346   CHECK_NE(tctx->status, ThreadStatusDead);
347   CHECK_EQ(tctx->user_id, 0);
348   tctx->user_id = user_id;
349 }
350 
351 }  // namespace __sanitizer
352