10b57cec5SDimitry Andric //===-- sanitizer_thread_registry.h -----------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file is shared between sanitizer tools.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric // General thread bookkeeping functionality.
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #ifndef SANITIZER_THREAD_REGISTRY_H
150b57cec5SDimitry Andric #define SANITIZER_THREAD_REGISTRY_H
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric #include "sanitizer_common.h"
18349cc55cSDimitry Andric #include "sanitizer_dense_map.h"
190b57cec5SDimitry Andric #include "sanitizer_list.h"
200b57cec5SDimitry Andric #include "sanitizer_mutex.h"
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric namespace __sanitizer {
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric enum ThreadStatus {
250b57cec5SDimitry Andric   ThreadStatusInvalid,   // Non-existent thread, data is invalid.
260b57cec5SDimitry Andric   ThreadStatusCreated,   // Created but not yet running.
270b57cec5SDimitry Andric   ThreadStatusRunning,   // The thread is currently running.
280b57cec5SDimitry Andric   ThreadStatusFinished,  // Joinable thread is finished but not yet joined.
290b57cec5SDimitry Andric   ThreadStatusDead       // Joined, but some info is still available.
300b57cec5SDimitry Andric };
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric enum class ThreadType {
330b57cec5SDimitry Andric   Regular, // Normal thread
340b57cec5SDimitry Andric   Worker,  // macOS Grand Central Dispatch (GCD) worker thread
350b57cec5SDimitry Andric   Fiber,   // Fiber
360b57cec5SDimitry Andric };
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric // Generic thread context. Specific sanitizer tools may inherit from it.
390b57cec5SDimitry Andric // If thread is dead, context may optionally be reused for a new thread.
400b57cec5SDimitry Andric class ThreadContextBase {
410b57cec5SDimitry Andric  public:
420b57cec5SDimitry Andric   explicit ThreadContextBase(u32 tid);
430b57cec5SDimitry Andric   const u32 tid;  // Thread ID. Main thread should have tid = 0.
440b57cec5SDimitry Andric   u64 unique_id;  // Unique thread ID.
450b57cec5SDimitry Andric   u32 reuse_count;  // Number of times this tid was reused.
460b57cec5SDimitry Andric   tid_t os_id;     // PID (used for reporting).
470b57cec5SDimitry Andric   uptr user_id;   // Some opaque user thread id (e.g. pthread_t).
480b57cec5SDimitry Andric   char name[64];  // As annotated by user.
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric   ThreadStatus status;
510b57cec5SDimitry Andric   bool detached;
520b57cec5SDimitry Andric   ThreadType thread_type;
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric   u32 parent_tid;
550b57cec5SDimitry Andric   ThreadContextBase *next;  // For storing thread contexts in a list.
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric   atomic_uint32_t thread_destroyed; // To address race of Joined vs Finished
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric   void SetName(const char *new_name);
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric   void SetDead();
620b57cec5SDimitry Andric   void SetJoined(void *arg);
630b57cec5SDimitry Andric   void SetFinished();
640b57cec5SDimitry Andric   void SetStarted(tid_t _os_id, ThreadType _thread_type, void *arg);
650b57cec5SDimitry Andric   void SetCreated(uptr _user_id, u64 _unique_id, bool _detached,
660b57cec5SDimitry Andric                   u32 _parent_tid, void *arg);
670b57cec5SDimitry Andric   void Reset();
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric   void SetDestroyed();
700b57cec5SDimitry Andric   bool GetDestroyed();
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric   // The following methods may be overriden by subclasses.
730b57cec5SDimitry Andric   // Some of them take opaque arg that may be optionally be used
740b57cec5SDimitry Andric   // by subclasses.
OnDead()750b57cec5SDimitry Andric   virtual void OnDead() {}
OnJoined(void * arg)760b57cec5SDimitry Andric   virtual void OnJoined(void *arg) {}
OnFinished()770b57cec5SDimitry Andric   virtual void OnFinished() {}
OnStarted(void * arg)780b57cec5SDimitry Andric   virtual void OnStarted(void *arg) {}
OnCreated(void * arg)790b57cec5SDimitry Andric   virtual void OnCreated(void *arg) {}
OnReset()800b57cec5SDimitry Andric   virtual void OnReset() {}
OnDetached(void * arg)810b57cec5SDimitry Andric   virtual void OnDetached(void *arg) {}
82e8d8bef9SDimitry Andric 
83e8d8bef9SDimitry Andric  protected:
84e8d8bef9SDimitry Andric   ~ThreadContextBase();
850b57cec5SDimitry Andric };
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric typedef ThreadContextBase* (*ThreadContextFactory)(u32 tid);
880b57cec5SDimitry Andric 
8904eeddc0SDimitry Andric class SANITIZER_MUTEX ThreadRegistry {
900b57cec5SDimitry Andric  public:
91fe6060f1SDimitry Andric   ThreadRegistry(ThreadContextFactory factory);
920b57cec5SDimitry Andric   ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
93fe6060f1SDimitry Andric                  u32 thread_quarantine_size, u32 max_reuse);
940b57cec5SDimitry Andric   void GetNumberOfThreads(uptr *total = nullptr, uptr *running = nullptr,
950b57cec5SDimitry Andric                           uptr *alive = nullptr);
960b57cec5SDimitry Andric   uptr GetMaxAliveThreads();
970b57cec5SDimitry Andric 
Lock()9804eeddc0SDimitry Andric   void Lock() SANITIZER_ACQUIRE() { mtx_.Lock(); }
CheckLocked()9904eeddc0SDimitry Andric   void CheckLocked() const SANITIZER_CHECK_LOCKED() { mtx_.CheckLocked(); }
Unlock()10004eeddc0SDimitry Andric   void Unlock() SANITIZER_RELEASE() { mtx_.Unlock(); }
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric   // Should be guarded by ThreadRegistryLock.
GetThreadLocked(u32 tid)1030b57cec5SDimitry Andric   ThreadContextBase *GetThreadLocked(u32 tid) {
104fe6060f1SDimitry Andric     return threads_.empty() ? nullptr : threads_[tid];
1050b57cec5SDimitry Andric   }
1060b57cec5SDimitry Andric 
NumThreadsLocked()1070eae32dcSDimitry Andric   u32 NumThreadsLocked() const { return threads_.size(); }
1080eae32dcSDimitry Andric 
1090b57cec5SDimitry Andric   u32 CreateThread(uptr user_id, bool detached, u32 parent_tid, void *arg);
1100b57cec5SDimitry Andric 
1110b57cec5SDimitry Andric   typedef void (*ThreadCallback)(ThreadContextBase *tctx, void *arg);
1120b57cec5SDimitry Andric   // Invokes callback with a specified arg for each thread context.
1130b57cec5SDimitry Andric   // Should be guarded by ThreadRegistryLock.
1140b57cec5SDimitry Andric   void RunCallbackForEachThreadLocked(ThreadCallback cb, void *arg);
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric   typedef bool (*FindThreadCallback)(ThreadContextBase *tctx, void *arg);
117fe6060f1SDimitry Andric   // Finds a thread using the provided callback. Returns kInvalidTid if no
1180b57cec5SDimitry Andric   // thread is found.
1190b57cec5SDimitry Andric   u32 FindThread(FindThreadCallback cb, void *arg);
1200b57cec5SDimitry Andric   // Should be guarded by ThreadRegistryLock. Return 0 if no thread
1210b57cec5SDimitry Andric   // is found.
1220b57cec5SDimitry Andric   ThreadContextBase *FindThreadContextLocked(FindThreadCallback cb,
1230b57cec5SDimitry Andric                                              void *arg);
1240b57cec5SDimitry Andric   ThreadContextBase *FindThreadContextByOsIDLocked(tid_t os_id);
1250b57cec5SDimitry Andric 
1260b57cec5SDimitry Andric   void SetThreadName(u32 tid, const char *name);
1270b57cec5SDimitry Andric   void SetThreadNameByUserId(uptr user_id, const char *name);
1280b57cec5SDimitry Andric   void DetachThread(u32 tid, void *arg);
1290b57cec5SDimitry Andric   void JoinThread(u32 tid, void *arg);
130fe6060f1SDimitry Andric   // Finishes thread and returns previous status.
131fe6060f1SDimitry Andric   ThreadStatus FinishThread(u32 tid);
1320b57cec5SDimitry Andric   void StartThread(u32 tid, tid_t os_id, ThreadType thread_type, void *arg);
133349cc55cSDimitry Andric   u32 ConsumeThreadUserId(uptr user_id);
1340b57cec5SDimitry Andric   void SetThreadUserId(u32 tid, uptr user_id);
1350b57cec5SDimitry Andric 
1360eae32dcSDimitry Andric   // OnFork must be called in the child process after fork to purge old
1370eae32dcSDimitry Andric   // threads that don't exist anymore (except for the current thread tid).
1380eae32dcSDimitry Andric   // Returns number of alive threads before fork.
1390eae32dcSDimitry Andric   u32 OnFork(u32 tid);
1400eae32dcSDimitry Andric 
1410b57cec5SDimitry Andric  private:
1420b57cec5SDimitry Andric   const ThreadContextFactory context_factory_;
1430b57cec5SDimitry Andric   const u32 max_threads_;
1440b57cec5SDimitry Andric   const u32 thread_quarantine_size_;
1450b57cec5SDimitry Andric   const u32 max_reuse_;
1460b57cec5SDimitry Andric 
147349cc55cSDimitry Andric   Mutex mtx_;
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric   u64 total_threads_;   // Total number of created threads. May be greater than
1500b57cec5SDimitry Andric                         // max_threads_ if contexts were reused.
1510b57cec5SDimitry Andric   uptr alive_threads_;  // Created or running.
1520b57cec5SDimitry Andric   uptr max_alive_threads_;
1530b57cec5SDimitry Andric   uptr running_threads_;
1540b57cec5SDimitry Andric 
155fe6060f1SDimitry Andric   InternalMmapVector<ThreadContextBase *> threads_;
1560b57cec5SDimitry Andric   IntrusiveList<ThreadContextBase> dead_threads_;
1570b57cec5SDimitry Andric   IntrusiveList<ThreadContextBase> invalid_threads_;
158349cc55cSDimitry Andric   DenseMap<uptr, Tid> live_;
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric   void QuarantinePush(ThreadContextBase *tctx);
1610b57cec5SDimitry Andric   ThreadContextBase *QuarantinePop();
1620b57cec5SDimitry Andric };
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric typedef GenericScopedLock<ThreadRegistry> ThreadRegistryLock;
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric } // namespace __sanitizer
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric #endif // SANITIZER_THREAD_REGISTRY_H
169