• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- sanitizer_thread_registry.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 shared between sanitizer tools.
11 //
12 // General thread bookkeeping functionality.
13 //===----------------------------------------------------------------------===//
14 
15 #include "sanitizer_thread_registry.h"
16 
17 namespace __sanitizer {
18 
ThreadContextBase(u32 tid)19 ThreadContextBase::ThreadContextBase(u32 tid)
20     : tid(tid), unique_id(0), os_id(0), user_id(0), status(ThreadStatusInvalid),
21       detached(false), reuse_count(0), parent_tid(0), next(0) {
22   name[0] = '\0';
23 }
24 
25 #ifndef SANITIZER_GO
~ThreadContextBase()26 ThreadContextBase::~ThreadContextBase() {
27   CHECK(0);
28 }
29 #endif
30 
SetName(const char * new_name)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 
SetDead()39 void ThreadContextBase::SetDead() {
40   CHECK(status == ThreadStatusRunning ||
41         status == ThreadStatusFinished);
42   status = ThreadStatusDead;
43   user_id = 0;
44   OnDead();
45 }
46 
SetJoined(void * arg)47 void ThreadContextBase::SetJoined(void *arg) {
48   // FIXME(dvyukov): print message and continue (it's user error).
49   CHECK_EQ(false, detached);
50   CHECK_EQ(ThreadStatusFinished, status);
51   status = ThreadStatusDead;
52   user_id = 0;
53   OnJoined(arg);
54 }
55 
SetFinished()56 void ThreadContextBase::SetFinished() {
57   if (!detached)
58     status = ThreadStatusFinished;
59   OnFinished();
60 }
61 
SetStarted(uptr _os_id,void * arg)62 void ThreadContextBase::SetStarted(uptr _os_id, void *arg) {
63   status = ThreadStatusRunning;
64   os_id = _os_id;
65   OnStarted(arg);
66 }
67 
SetCreated(uptr _user_id,u64 _unique_id,bool _detached,u32 _parent_tid,void * arg)68 void ThreadContextBase::SetCreated(uptr _user_id, u64 _unique_id,
69                                    bool _detached, u32 _parent_tid, void *arg) {
70   status = ThreadStatusCreated;
71   user_id = _user_id;
72   unique_id = _unique_id;
73   detached = _detached;
74   // Parent tid makes no sense for the main thread.
75   if (tid != 0)
76     parent_tid = _parent_tid;
77   OnCreated(arg);
78 }
79 
Reset(void * arg)80 void ThreadContextBase::Reset(void *arg) {
81   status = ThreadStatusInvalid;
82   reuse_count++;
83   SetName(0);
84   OnReset(arg);
85 }
86 
87 // ThreadRegistry implementation.
88 
89 const u32 ThreadRegistry::kUnknownTid = -1U;
90 
ThreadRegistry(ThreadContextFactory factory,u32 max_threads,u32 thread_quarantine_size)91 ThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
92                                u32 thread_quarantine_size)
93     : context_factory_(factory),
94       max_threads_(max_threads),
95       thread_quarantine_size_(thread_quarantine_size),
96       mtx_(),
97       n_contexts_(0),
98       total_threads_(0),
99       alive_threads_(0),
100       max_alive_threads_(0),
101       running_threads_(0) {
102   threads_ = (ThreadContextBase **)MmapOrDie(max_threads_ * sizeof(threads_[0]),
103                                              "ThreadRegistry");
104   dead_threads_.clear();
105 }
106 
GetNumberOfThreads(uptr * total,uptr * running,uptr * alive)107 void ThreadRegistry::GetNumberOfThreads(uptr *total, uptr *running,
108                                         uptr *alive) {
109   BlockingMutexLock l(&mtx_);
110   if (total) *total = n_contexts_;
111   if (running) *running = running_threads_;
112   if (alive) *alive = alive_threads_;
113 }
114 
GetMaxAliveThreads()115 uptr ThreadRegistry::GetMaxAliveThreads() {
116   BlockingMutexLock l(&mtx_);
117   return max_alive_threads_;
118 }
119 
CreateThread(uptr user_id,bool detached,u32 parent_tid,void * arg)120 u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid,
121                                  void *arg) {
122   BlockingMutexLock l(&mtx_);
123   u32 tid = kUnknownTid;
124   ThreadContextBase *tctx = 0;
125   if (dead_threads_.size() > thread_quarantine_size_ ||
126       n_contexts_ >= max_threads_) {
127     // Reusing old thread descriptor and tid.
128     if (dead_threads_.size() == 0) {
129       Report("%s: Thread limit (%u threads) exceeded. Dying.\n",
130              SanitizerToolName, max_threads_);
131       Die();
132     }
133     tctx = dead_threads_.front();
134     dead_threads_.pop_front();
135     CHECK_EQ(ThreadStatusDead, tctx->status);
136     tctx->Reset(arg);
137     tid = tctx->tid;
138   } else {
139     // Allocate new thread context and tid.
140     tid = n_contexts_++;
141     tctx = context_factory_(tid);
142     threads_[tid] = tctx;
143   }
144   CHECK_NE(tctx, 0);
145   CHECK_NE(tid, kUnknownTid);
146   CHECK_LT(tid, max_threads_);
147   CHECK_EQ(tctx->status, ThreadStatusInvalid);
148   alive_threads_++;
149   if (max_alive_threads_ < alive_threads_) {
150     max_alive_threads_++;
151     CHECK_EQ(alive_threads_, max_alive_threads_);
152   }
153   tctx->SetCreated(user_id, total_threads_++, detached,
154                    parent_tid, arg);
155   return tid;
156 }
157 
RunCallbackForEachThreadLocked(ThreadCallback cb,void * arg)158 void ThreadRegistry::RunCallbackForEachThreadLocked(ThreadCallback cb,
159                                                     void *arg) {
160   CheckLocked();
161   for (u32 tid = 0; tid < n_contexts_; tid++) {
162     ThreadContextBase *tctx = threads_[tid];
163     if (tctx == 0)
164       continue;
165     cb(tctx, arg);
166   }
167 }
168 
FindThread(FindThreadCallback cb,void * arg)169 u32 ThreadRegistry::FindThread(FindThreadCallback cb, void *arg) {
170   BlockingMutexLock l(&mtx_);
171   for (u32 tid = 0; tid < n_contexts_; tid++) {
172     ThreadContextBase *tctx = threads_[tid];
173     if (tctx != 0 && cb(tctx, arg))
174       return tctx->tid;
175   }
176   return kUnknownTid;
177 }
178 
179 ThreadContextBase *
FindThreadContextLocked(FindThreadCallback cb,void * arg)180 ThreadRegistry::FindThreadContextLocked(FindThreadCallback cb, void *arg) {
181   CheckLocked();
182   for (u32 tid = 0; tid < n_contexts_; tid++) {
183     ThreadContextBase *tctx = threads_[tid];
184     if (tctx != 0 && cb(tctx, arg))
185       return tctx;
186   }
187   return 0;
188 }
189 
SetThreadName(u32 tid,const char * name)190 void ThreadRegistry::SetThreadName(u32 tid, const char *name) {
191   BlockingMutexLock l(&mtx_);
192   CHECK_LT(tid, n_contexts_);
193   ThreadContextBase *tctx = threads_[tid];
194   CHECK_NE(tctx, 0);
195   CHECK_EQ(ThreadStatusRunning, tctx->status);
196   tctx->SetName(name);
197 }
198 
DetachThread(u32 tid)199 void ThreadRegistry::DetachThread(u32 tid) {
200   BlockingMutexLock l(&mtx_);
201   CHECK_LT(tid, n_contexts_);
202   ThreadContextBase *tctx = threads_[tid];
203   CHECK_NE(tctx, 0);
204   if (tctx->status == ThreadStatusInvalid) {
205     Report("%s: Detach of non-existent thread\n", SanitizerToolName);
206     return;
207   }
208   if (tctx->status == ThreadStatusFinished) {
209     tctx->SetDead();
210     dead_threads_.push_back(tctx);
211   } else {
212     tctx->detached = true;
213   }
214 }
215 
JoinThread(u32 tid,void * arg)216 void ThreadRegistry::JoinThread(u32 tid, void *arg) {
217   BlockingMutexLock l(&mtx_);
218   CHECK_LT(tid, n_contexts_);
219   ThreadContextBase *tctx = threads_[tid];
220   CHECK_NE(tctx, 0);
221   if (tctx->status == ThreadStatusInvalid) {
222     Report("%s: Join of non-existent thread\n", SanitizerToolName);
223     return;
224   }
225   tctx->SetJoined(arg);
226   dead_threads_.push_back(tctx);
227 }
228 
FinishThread(u32 tid)229 void ThreadRegistry::FinishThread(u32 tid) {
230   BlockingMutexLock l(&mtx_);
231   CHECK_GT(alive_threads_, 0);
232   alive_threads_--;
233   CHECK_GT(running_threads_, 0);
234   running_threads_--;
235   CHECK_LT(tid, n_contexts_);
236   ThreadContextBase *tctx = threads_[tid];
237   CHECK_NE(tctx, 0);
238   CHECK_EQ(ThreadStatusRunning, tctx->status);
239   tctx->SetFinished();
240   if (tctx->detached) {
241     tctx->SetDead();
242     dead_threads_.push_back(tctx);
243   }
244 }
245 
StartThread(u32 tid,uptr os_id,void * arg)246 void ThreadRegistry::StartThread(u32 tid, uptr os_id, void *arg) {
247   BlockingMutexLock l(&mtx_);
248   running_threads_++;
249   CHECK_LT(tid, n_contexts_);
250   ThreadContextBase *tctx = threads_[tid];
251   CHECK_NE(tctx, 0);
252   CHECK_EQ(ThreadStatusCreated, tctx->status);
253   tctx->SetStarted(os_id, arg);
254 }
255 
256 }  // namespace __sanitizer
257