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