1251034Sed//===-- sanitizer_thread_registry.h -----------------------------*- C++ -*-===// 2251034Sed// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6251034Sed// 7251034Sed//===----------------------------------------------------------------------===// 8251034Sed// 9251034Sed// This file is shared between sanitizer tools. 10251034Sed// 11251034Sed// General thread bookkeeping functionality. 12251034Sed//===----------------------------------------------------------------------===// 13251034Sed 14251034Sed#ifndef SANITIZER_THREAD_REGISTRY_H 15251034Sed#define SANITIZER_THREAD_REGISTRY_H 16251034Sed 17251034Sed#include "sanitizer_common.h" 18251034Sed#include "sanitizer_list.h" 19251034Sed#include "sanitizer_mutex.h" 20251034Sed 21251034Sednamespace __sanitizer { 22251034Sed 23251034Sedenum ThreadStatus { 24251034Sed ThreadStatusInvalid, // Non-existent thread, data is invalid. 25251034Sed ThreadStatusCreated, // Created but not yet running. 26251034Sed ThreadStatusRunning, // The thread is currently running. 27251034Sed ThreadStatusFinished, // Joinable thread is finished but not yet joined. 28251034Sed ThreadStatusDead // Joined, but some info is still available. 29251034Sed}; 30251034Sed 31353358Sdimenum class ThreadType { 32353358Sdim Regular, // Normal thread 33353358Sdim Worker, // macOS Grand Central Dispatch (GCD) worker thread 34353358Sdim Fiber, // Fiber 35353358Sdim}; 36353358Sdim 37251034Sed// Generic thread context. Specific sanitizer tools may inherit from it. 38251034Sed// If thread is dead, context may optionally be reused for a new thread. 39251034Sedclass ThreadContextBase { 40251034Sed public: 41251034Sed explicit ThreadContextBase(u32 tid); 42251034Sed ~ThreadContextBase(); // Should never be called. 43251034Sed 44251034Sed const u32 tid; // Thread ID. Main thread should have tid = 0. 45251034Sed u64 unique_id; // Unique thread ID. 46276789Sdim u32 reuse_count; // Number of times this tid was reused. 47321369Sdim tid_t os_id; // PID (used for reporting). 48251034Sed uptr user_id; // Some opaque user thread id (e.g. pthread_t). 49251034Sed char name[64]; // As annotated by user. 50251034Sed 51251034Sed ThreadStatus status; 52251034Sed bool detached; 53353358Sdim ThreadType thread_type; 54251034Sed 55251034Sed u32 parent_tid; 56251034Sed ThreadContextBase *next; // For storing thread contexts in a list. 57251034Sed 58327952Sdim atomic_uint32_t thread_destroyed; // To address race of Joined vs Finished 59327952Sdim 60251034Sed void SetName(const char *new_name); 61251034Sed 62251034Sed void SetDead(); 63251034Sed void SetJoined(void *arg); 64251034Sed void SetFinished(); 65353358Sdim void SetStarted(tid_t _os_id, ThreadType _thread_type, void *arg); 66251034Sed void SetCreated(uptr _user_id, u64 _unique_id, bool _detached, 67251034Sed u32 _parent_tid, void *arg); 68251034Sed void Reset(); 69251034Sed 70327952Sdim void SetDestroyed(); 71327952Sdim bool GetDestroyed(); 72327952Sdim 73251034Sed // The following methods may be overriden by subclasses. 74251034Sed // Some of them take opaque arg that may be optionally be used 75251034Sed // by subclasses. 76251034Sed virtual void OnDead() {} 77251034Sed virtual void OnJoined(void *arg) {} 78251034Sed virtual void OnFinished() {} 79251034Sed virtual void OnStarted(void *arg) {} 80251034Sed virtual void OnCreated(void *arg) {} 81251034Sed virtual void OnReset() {} 82276789Sdim virtual void OnDetached(void *arg) {} 83251034Sed}; 84251034Sed 85251034Sedtypedef ThreadContextBase* (*ThreadContextFactory)(u32 tid); 86251034Sed 87251034Sedclass ThreadRegistry { 88251034Sed public: 89251034Sed static const u32 kUnknownTid; 90251034Sed 91251034Sed ThreadRegistry(ThreadContextFactory factory, u32 max_threads, 92276789Sdim u32 thread_quarantine_size, u32 max_reuse = 0); 93296417Sdim void GetNumberOfThreads(uptr *total = nullptr, uptr *running = nullptr, 94296417Sdim uptr *alive = nullptr); 95251034Sed uptr GetMaxAliveThreads(); 96251034Sed 97251034Sed void Lock() { mtx_.Lock(); } 98251034Sed void CheckLocked() { mtx_.CheckLocked(); } 99251034Sed void Unlock() { mtx_.Unlock(); } 100251034Sed 101251034Sed // Should be guarded by ThreadRegistryLock. 102251034Sed ThreadContextBase *GetThreadLocked(u32 tid) { 103251034Sed DCHECK_LT(tid, n_contexts_); 104251034Sed return threads_[tid]; 105251034Sed } 106251034Sed 107251034Sed u32 CreateThread(uptr user_id, bool detached, u32 parent_tid, void *arg); 108251034Sed 109251034Sed typedef void (*ThreadCallback)(ThreadContextBase *tctx, void *arg); 110251034Sed // Invokes callback with a specified arg for each thread context. 111251034Sed // Should be guarded by ThreadRegistryLock. 112251034Sed void RunCallbackForEachThreadLocked(ThreadCallback cb, void *arg); 113251034Sed 114251034Sed typedef bool (*FindThreadCallback)(ThreadContextBase *tctx, void *arg); 115251034Sed // Finds a thread using the provided callback. Returns kUnknownTid if no 116251034Sed // thread is found. 117251034Sed u32 FindThread(FindThreadCallback cb, void *arg); 118251034Sed // Should be guarded by ThreadRegistryLock. Return 0 if no thread 119251034Sed // is found. 120251034Sed ThreadContextBase *FindThreadContextLocked(FindThreadCallback cb, 121251034Sed void *arg); 122321369Sdim ThreadContextBase *FindThreadContextByOsIDLocked(tid_t os_id); 123251034Sed 124251034Sed void SetThreadName(u32 tid, const char *name); 125274201Sdim void SetThreadNameByUserId(uptr user_id, const char *name); 126276789Sdim void DetachThread(u32 tid, void *arg); 127251034Sed void JoinThread(u32 tid, void *arg); 128251034Sed void FinishThread(u32 tid); 129353358Sdim void StartThread(u32 tid, tid_t os_id, ThreadType thread_type, void *arg); 130344779Sdim void SetThreadUserId(u32 tid, uptr user_id); 131251034Sed 132251034Sed private: 133251034Sed const ThreadContextFactory context_factory_; 134251034Sed const u32 max_threads_; 135251034Sed const u32 thread_quarantine_size_; 136276789Sdim const u32 max_reuse_; 137251034Sed 138251034Sed BlockingMutex mtx_; 139251034Sed 140251034Sed u32 n_contexts_; // Number of created thread contexts, 141251034Sed // at most max_threads_. 142251034Sed u64 total_threads_; // Total number of created threads. May be greater than 143251034Sed // max_threads_ if contexts were reused. 144251034Sed uptr alive_threads_; // Created or running. 145251034Sed uptr max_alive_threads_; 146251034Sed uptr running_threads_; 147251034Sed 148251034Sed ThreadContextBase **threads_; // Array of thread contexts is leaked. 149251034Sed IntrusiveList<ThreadContextBase> dead_threads_; 150251034Sed IntrusiveList<ThreadContextBase> invalid_threads_; 151251034Sed 152251034Sed void QuarantinePush(ThreadContextBase *tctx); 153251034Sed ThreadContextBase *QuarantinePop(); 154251034Sed}; 155251034Sed 156251034Sedtypedef GenericScopedLock<ThreadRegistry> ThreadRegistryLock; 157251034Sed 158296417Sdim} // namespace __sanitizer 159251034Sed 160296417Sdim#endif // SANITIZER_THREAD_REGISTRY_H 161