sanitizer_thread_registry.h revision ce85e03620f64ce7e4cd0598f2e93090f52a9e99
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//===-- sanitizer_thread_registry.h -----------------------------*- C++ -*-===//
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//                     The LLVM Compiler Infrastructure
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
5a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// This file is distributed under the University of Illinois Open Source
6a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// License. See LICENSE.TXT for details.
70529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch//
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//===----------------------------------------------------------------------===//
9a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)//
10558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// This file is shared between sanitizer tools.
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)//
12ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// General thread bookkeeping functionality.
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//===----------------------------------------------------------------------===//
140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
15558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#ifndef SANITIZER_THREAD_REGISTRY_H
16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#define SANITIZER_THREAD_REGISTRY_H
17558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
18ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "sanitizer_common.h"
195e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "sanitizer_list.h"
200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "sanitizer_mutex.h"
21a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochnamespace __sanitizer {
23558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
24558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochenum ThreadStatus {
25558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  ThreadStatusInvalid,   // Non-existent thread, data is invalid.
260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  ThreadStatusCreated,   // Created but not yet running.
27558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  ThreadStatusRunning,   // The thread is currently running.
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ThreadStatusFinished,  // Joinable thread is finished but not yet joined.
295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ThreadStatusDead       // Joined, but some info is still available.
30558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch};
310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Generic thread context. Specific sanitizer tools may inherit from it.
33a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// If thread is dead, context may optionally be reused for a new thread.
34a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)class ThreadContextBase {
350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch public:
360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  explicit ThreadContextBase(u32 tid);
37ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#ifndef SANITIZER_GO  // Go does not have libstdc++
38ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  virtual
39cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#endif
40cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ~ThreadContextBase();
410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
42cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const u32 tid;  // Thread ID. Main thread should have tid = 0.
430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  u64 unique_id;  // Unique thread ID.
44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  uptr os_id;     // PID (used for reporting).
45116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  uptr user_id;   // Some opaque user thread id (e.g. pthread_t).
46116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  char name[64];  // As annotated by user.
47116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
48116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ThreadStatus status;
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  bool detached;
50116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  int reuse_count;
51116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
52116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  u32 parent_tid;
530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  ThreadContextBase *next;  // For storing thread contexts in a list.
54ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
55ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  void SetName(const char *new_name);
56ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
57ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  void SetDead();
58ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  void SetJoined(void *arg);
59ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  void SetFinished();
60ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  void SetStarted(uptr _os_id, void *arg);
61ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  void SetCreated(uptr _user_id, u64 _unique_id, bool _detached,
62ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                  u32 _parent_tid, void *arg);
63ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  void Reset();
64ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // The following methods may be overriden by subclasses.
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Some of them take opaque arg that may be optionally be used
67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // by subclasses.
68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual void OnDead() {}
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnJoined(void *arg) {}
70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual void OnFinished() {}
71558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  virtual void OnStarted(void *arg) {}
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void OnCreated(void *arg) {}
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void OnReset() {}
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
75868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
76ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochtypedef ThreadContextBase* (*ThreadContextFactory)(u32 tid);
77a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
78a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)class ThreadRegistry {
7958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) public:
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const u32 kUnknownTid;
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
82558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
83558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                 u32 thread_quarantine_size);
84558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  void GetNumberOfThreads(uptr *total = 0, uptr *running = 0, uptr *alive = 0);
85a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  uptr GetMaxAliveThreads();
86a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
87a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void Lock() { mtx_.Lock(); }
88a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void CheckLocked() { mtx_.CheckLocked(); }
89a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void Unlock() { mtx_.Unlock(); }
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Should be guarded by ThreadRegistryLock.
92a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  ThreadContextBase *GetThreadLocked(u32 tid) {
93a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    DCHECK_LT(tid, n_contexts_);
94a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return threads_[tid];
95a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
96a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
97a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  u32 CreateThread(uptr user_id, bool detached, u32 parent_tid, void *arg);
98a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
99a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  typedef void (*ThreadCallback)(ThreadContextBase *tctx, void *arg);
100a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Invokes callback with a specified arg for each thread context.
101a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Should be guarded by ThreadRegistryLock.
102a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void RunCallbackForEachThreadLocked(ThreadCallback cb, void *arg);
103a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
1040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  typedef bool (*FindThreadCallback)(ThreadContextBase *tctx, void *arg);
1050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Finds a thread using the provided callback. Returns kUnknownTid if no
1060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // thread is found.
1070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  u32 FindThread(FindThreadCallback cb, void *arg);
108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Should be guarded by ThreadRegistryLock. Returns 0 if no thread
109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // is found.
110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ThreadContextBase *FindThreadContextLocked(FindThreadCallback cb,
111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                             void *arg);
1120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void SetThreadName(u32 tid, const char *name);
114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void DetachThread(u32 tid);
115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void JoinThread(u32 tid, void *arg);
116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void FinishThread(u32 tid);
1170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  void StartThread(u32 tid, uptr os_id, void *arg);
118116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
119116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch private:
120116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const ThreadContextFactory context_factory_;
121116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const u32 max_threads_;
122116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const u32 thread_quarantine_size_;
123116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
124116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  BlockingMutex mtx_;
1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  u32 n_contexts_;      // Number of created thread contexts,
1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                        // at most max_threads_.
1285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  u64 total_threads_;   // Total number of created threads. May be greater than
1295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                        // max_threads_ if contexts were reused.
1305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  uptr alive_threads_;  // Created or running.
131116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  uptr max_alive_threads_;
1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  uptr running_threads_;
133116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
134116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ThreadContextBase **threads_;  // Array of thread contexts is leaked.
135116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  IntrusiveList<ThreadContextBase> dead_threads_;
136116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  IntrusiveList<ThreadContextBase> invalid_threads_;
137116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
138116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  void QuarantinePush(ThreadContextBase *tctx);
139116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ThreadContextBase *QuarantinePop();
140116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch};
141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
142116680a4aac90f2aa7413d9095a592090648e557Ben Murdochtypedef GenericScopedLock<ThreadRegistry> ThreadRegistryLock;
143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}  // namespace __sanitizer
1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#endif  // SANITIZER_THREAD_REGISTRY_H
147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
148116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch