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