16d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov//===-- sanitizer_thread_registry.h -----------------------------*- C++ -*-===// 26d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov// 36d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov// The LLVM Compiler Infrastructure 46d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov// 56d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov// This file is distributed under the University of Illinois Open Source 66d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov// License. See LICENSE.TXT for details. 76d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov// 86d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov//===----------------------------------------------------------------------===// 96d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov// 106d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov// This file is shared between sanitizer tools. 116d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov// 126d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov// General thread bookkeeping functionality. 136d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov//===----------------------------------------------------------------------===// 146d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov 156d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov#ifndef SANITIZER_THREAD_REGISTRY_H 166d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov#define SANITIZER_THREAD_REGISTRY_H 176d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov 186d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov#include "sanitizer_common.h" 196d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov#include "sanitizer_list.h" 206d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov#include "sanitizer_mutex.h" 216d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov 226d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovnamespace __sanitizer { 236d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov 246d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovenum ThreadStatus { 256d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov ThreadStatusInvalid, // Non-existent thread, data is invalid. 266d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov ThreadStatusCreated, // Created but not yet running. 276d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov ThreadStatusRunning, // The thread is currently running. 286d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov ThreadStatusFinished, // Joinable thread is finished but not yet joined. 296d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov ThreadStatusDead // Joined, but some info is still available. 306d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}; 316d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov 326d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov// Generic thread context. Specific sanitizer tools may inherit from it. 336d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov// If thread is dead, context may optionally be reused for a new thread. 346d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovclass ThreadContextBase { 356d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov public: 366d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov explicit ThreadContextBase(u32 tid); 37e374e4ece521692173aad355420d03e1b2cd819aAlexey Samsonov ~ThreadContextBase(); // Should never be called. 386d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov 396d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov const u32 tid; // Thread ID. Main thread should have tid = 0. 406d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov u64 unique_id; // Unique thread ID. 412d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines u32 reuse_count; // Number of times this tid was reused. 426d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov uptr os_id; // PID (used for reporting). 436d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov uptr user_id; // Some opaque user thread id (e.g. pthread_t). 446d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov char name[64]; // As annotated by user. 456d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov 466d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov ThreadStatus status; 476d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov bool detached; 486d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov 496d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov u32 parent_tid; 506d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov ThreadContextBase *next; // For storing thread contexts in a list. 516d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov 526d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov void SetName(const char *new_name); 536d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov 546d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov void SetDead(); 556d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov void SetJoined(void *arg); 566d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov void SetFinished(); 576d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov void SetStarted(uptr _os_id, void *arg); 586d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov void SetCreated(uptr _user_id, u64 _unique_id, bool _detached, 596d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov u32 _parent_tid, void *arg); 60ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov void Reset(); 616d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov 626d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov // The following methods may be overriden by subclasses. 636d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov // Some of them take opaque arg that may be optionally be used 646d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov // by subclasses. 656d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov virtual void OnDead() {} 666d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov virtual void OnJoined(void *arg) {} 676d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov virtual void OnFinished() {} 686d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov virtual void OnStarted(void *arg) {} 696d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov virtual void OnCreated(void *arg) {} 70ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov virtual void OnReset() {} 716d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}; 726d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov 736d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovtypedef ThreadContextBase* (*ThreadContextFactory)(u32 tid); 746d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov 756d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovclass ThreadRegistry { 766d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov public: 77827d4ef8b76760ef8c58612d916b8f53081bf368Alexey Samsonov static const u32 kUnknownTid; 78827d4ef8b76760ef8c58612d916b8f53081bf368Alexey Samsonov 796d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov ThreadRegistry(ThreadContextFactory factory, u32 max_threads, 802d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines u32 thread_quarantine_size, u32 max_reuse = 0); 816d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov void GetNumberOfThreads(uptr *total = 0, uptr *running = 0, uptr *alive = 0); 826d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov uptr GetMaxAliveThreads(); 836d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov 846d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov void Lock() { mtx_.Lock(); } 856d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov void CheckLocked() { mtx_.CheckLocked(); } 866d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov void Unlock() { mtx_.Unlock(); } 876d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov 886d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov // Should be guarded by ThreadRegistryLock. 896d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov ThreadContextBase *GetThreadLocked(u32 tid) { 906d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov DCHECK_LT(tid, n_contexts_); 916d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov return threads_[tid]; 926d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov } 936d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov 946d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov u32 CreateThread(uptr user_id, bool detached, u32 parent_tid, void *arg); 956d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov 966d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov typedef void (*ThreadCallback)(ThreadContextBase *tctx, void *arg); 976d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov // Invokes callback with a specified arg for each thread context. 986d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov // Should be guarded by ThreadRegistryLock. 996d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov void RunCallbackForEachThreadLocked(ThreadCallback cb, void *arg); 1006d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov 1016d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov typedef bool (*FindThreadCallback)(ThreadContextBase *tctx, void *arg); 1026d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov // Finds a thread using the provided callback. Returns kUnknownTid if no 1036d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov // thread is found. 1046d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov u32 FindThread(FindThreadCallback cb, void *arg); 10598d3b40ec5cf06e46397492c21acc9d18e8c54abSergey Matveev // Should be guarded by ThreadRegistryLock. Return 0 if no thread 1066d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov // is found. 1076d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov ThreadContextBase *FindThreadContextLocked(FindThreadCallback cb, 1086d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov void *arg); 10998d3b40ec5cf06e46397492c21acc9d18e8c54abSergey Matveev ThreadContextBase *FindThreadContextByOsIDLocked(uptr os_id); 1106d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov 1116d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov void SetThreadName(u32 tid, const char *name); 1125cf2c460e96e593b1c772f1b02d3a217f4837fdcDmitry Vyukov void SetThreadNameByUserId(uptr user_id, const char *name); 1136d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov void DetachThread(u32 tid); 1146d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov void JoinThread(u32 tid, void *arg); 1156d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov void FinishThread(u32 tid); 1166d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov void StartThread(u32 tid, uptr os_id, void *arg); 117116c8029f506b074a8b9c83605b14ac4bf0259c6Alexey Samsonov 118116c8029f506b074a8b9c83605b14ac4bf0259c6Alexey Samsonov private: 119116c8029f506b074a8b9c83605b14ac4bf0259c6Alexey Samsonov const ThreadContextFactory context_factory_; 120116c8029f506b074a8b9c83605b14ac4bf0259c6Alexey Samsonov const u32 max_threads_; 121116c8029f506b074a8b9c83605b14ac4bf0259c6Alexey Samsonov const u32 thread_quarantine_size_; 1222d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines const u32 max_reuse_; 123116c8029f506b074a8b9c83605b14ac4bf0259c6Alexey Samsonov 124116c8029f506b074a8b9c83605b14ac4bf0259c6Alexey Samsonov BlockingMutex mtx_; 125116c8029f506b074a8b9c83605b14ac4bf0259c6Alexey Samsonov 126116c8029f506b074a8b9c83605b14ac4bf0259c6Alexey Samsonov u32 n_contexts_; // Number of created thread contexts, 127116c8029f506b074a8b9c83605b14ac4bf0259c6Alexey Samsonov // at most max_threads_. 128116c8029f506b074a8b9c83605b14ac4bf0259c6Alexey Samsonov u64 total_threads_; // Total number of created threads. May be greater than 129116c8029f506b074a8b9c83605b14ac4bf0259c6Alexey Samsonov // max_threads_ if contexts were reused. 130116c8029f506b074a8b9c83605b14ac4bf0259c6Alexey Samsonov uptr alive_threads_; // Created or running. 131116c8029f506b074a8b9c83605b14ac4bf0259c6Alexey Samsonov uptr max_alive_threads_; 132116c8029f506b074a8b9c83605b14ac4bf0259c6Alexey Samsonov uptr running_threads_; 133116c8029f506b074a8b9c83605b14ac4bf0259c6Alexey Samsonov 134116c8029f506b074a8b9c83605b14ac4bf0259c6Alexey Samsonov ThreadContextBase **threads_; // Array of thread contexts is leaked. 135116c8029f506b074a8b9c83605b14ac4bf0259c6Alexey Samsonov IntrusiveList<ThreadContextBase> dead_threads_; 136ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov IntrusiveList<ThreadContextBase> invalid_threads_; 137ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov 138ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov void QuarantinePush(ThreadContextBase *tctx); 139ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov ThreadContextBase *QuarantinePop(); 1406d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}; 1416d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov 1426d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovtypedef GenericScopedLock<ThreadRegistry> ThreadRegistryLock; 1436d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov 1446d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov} // namespace __sanitizer 1456d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov 1466d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov#endif // SANITIZER_THREAD_REGISTRY_H 1476d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov 148