xref: /openbsd-src/gnu/llvm/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h (revision 810390e339a5425391477d5d41c78d7cab2424ac)
13cab2bb3Spatrick //===-- sanitizer_thread_registry.h -----------------------------*- C++ -*-===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file is shared between sanitizer tools.
103cab2bb3Spatrick //
113cab2bb3Spatrick // General thread bookkeeping functionality.
123cab2bb3Spatrick //===----------------------------------------------------------------------===//
133cab2bb3Spatrick 
143cab2bb3Spatrick #ifndef SANITIZER_THREAD_REGISTRY_H
153cab2bb3Spatrick #define SANITIZER_THREAD_REGISTRY_H
163cab2bb3Spatrick 
173cab2bb3Spatrick #include "sanitizer_common.h"
18*810390e3Srobert #include "sanitizer_dense_map.h"
193cab2bb3Spatrick #include "sanitizer_list.h"
203cab2bb3Spatrick #include "sanitizer_mutex.h"
213cab2bb3Spatrick 
223cab2bb3Spatrick namespace __sanitizer {
233cab2bb3Spatrick 
243cab2bb3Spatrick enum ThreadStatus {
253cab2bb3Spatrick   ThreadStatusInvalid,   // Non-existent thread, data is invalid.
263cab2bb3Spatrick   ThreadStatusCreated,   // Created but not yet running.
273cab2bb3Spatrick   ThreadStatusRunning,   // The thread is currently running.
283cab2bb3Spatrick   ThreadStatusFinished,  // Joinable thread is finished but not yet joined.
293cab2bb3Spatrick   ThreadStatusDead       // Joined, but some info is still available.
303cab2bb3Spatrick };
313cab2bb3Spatrick 
323cab2bb3Spatrick enum class ThreadType {
333cab2bb3Spatrick   Regular, // Normal thread
343cab2bb3Spatrick   Worker,  // macOS Grand Central Dispatch (GCD) worker thread
353cab2bb3Spatrick   Fiber,   // Fiber
363cab2bb3Spatrick };
373cab2bb3Spatrick 
383cab2bb3Spatrick // Generic thread context. Specific sanitizer tools may inherit from it.
393cab2bb3Spatrick // If thread is dead, context may optionally be reused for a new thread.
403cab2bb3Spatrick class ThreadContextBase {
413cab2bb3Spatrick  public:
423cab2bb3Spatrick   explicit ThreadContextBase(u32 tid);
433cab2bb3Spatrick   const u32 tid;  // Thread ID. Main thread should have tid = 0.
443cab2bb3Spatrick   u64 unique_id;  // Unique thread ID.
453cab2bb3Spatrick   u32 reuse_count;  // Number of times this tid was reused.
463cab2bb3Spatrick   tid_t os_id;     // PID (used for reporting).
473cab2bb3Spatrick   uptr user_id;   // Some opaque user thread id (e.g. pthread_t).
483cab2bb3Spatrick   char name[64];  // As annotated by user.
493cab2bb3Spatrick 
503cab2bb3Spatrick   ThreadStatus status;
513cab2bb3Spatrick   bool detached;
523cab2bb3Spatrick   ThreadType thread_type;
533cab2bb3Spatrick 
543cab2bb3Spatrick   u32 parent_tid;
553cab2bb3Spatrick   ThreadContextBase *next;  // For storing thread contexts in a list.
563cab2bb3Spatrick 
573cab2bb3Spatrick   atomic_uint32_t thread_destroyed; // To address race of Joined vs Finished
583cab2bb3Spatrick 
593cab2bb3Spatrick   void SetName(const char *new_name);
603cab2bb3Spatrick 
613cab2bb3Spatrick   void SetDead();
623cab2bb3Spatrick   void SetJoined(void *arg);
633cab2bb3Spatrick   void SetFinished();
643cab2bb3Spatrick   void SetStarted(tid_t _os_id, ThreadType _thread_type, void *arg);
653cab2bb3Spatrick   void SetCreated(uptr _user_id, u64 _unique_id, bool _detached,
663cab2bb3Spatrick                   u32 _parent_tid, void *arg);
673cab2bb3Spatrick   void Reset();
683cab2bb3Spatrick 
693cab2bb3Spatrick   void SetDestroyed();
703cab2bb3Spatrick   bool GetDestroyed();
713cab2bb3Spatrick 
723cab2bb3Spatrick   // The following methods may be overriden by subclasses.
733cab2bb3Spatrick   // Some of them take opaque arg that may be optionally be used
743cab2bb3Spatrick   // by subclasses.
OnDead()753cab2bb3Spatrick   virtual void OnDead() {}
OnJoined(void * arg)763cab2bb3Spatrick   virtual void OnJoined(void *arg) {}
OnFinished()773cab2bb3Spatrick   virtual void OnFinished() {}
OnStarted(void * arg)783cab2bb3Spatrick   virtual void OnStarted(void *arg) {}
OnCreated(void * arg)793cab2bb3Spatrick   virtual void OnCreated(void *arg) {}
OnReset()803cab2bb3Spatrick   virtual void OnReset() {}
OnDetached(void * arg)813cab2bb3Spatrick   virtual void OnDetached(void *arg) {}
82d89ec533Spatrick 
83d89ec533Spatrick  protected:
84d89ec533Spatrick   ~ThreadContextBase();
853cab2bb3Spatrick };
863cab2bb3Spatrick 
873cab2bb3Spatrick typedef ThreadContextBase* (*ThreadContextFactory)(u32 tid);
883cab2bb3Spatrick 
89*810390e3Srobert class SANITIZER_MUTEX ThreadRegistry {
903cab2bb3Spatrick  public:
91d89ec533Spatrick   ThreadRegistry(ThreadContextFactory factory);
923cab2bb3Spatrick   ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
93d89ec533Spatrick                  u32 thread_quarantine_size, u32 max_reuse);
943cab2bb3Spatrick   void GetNumberOfThreads(uptr *total = nullptr, uptr *running = nullptr,
953cab2bb3Spatrick                           uptr *alive = nullptr);
963cab2bb3Spatrick   uptr GetMaxAliveThreads();
973cab2bb3Spatrick 
Lock()98*810390e3Srobert   void Lock() SANITIZER_ACQUIRE() { mtx_.Lock(); }
CheckLocked()99*810390e3Srobert   void CheckLocked() const SANITIZER_CHECK_LOCKED() { mtx_.CheckLocked(); }
Unlock()100*810390e3Srobert   void Unlock() SANITIZER_RELEASE() { mtx_.Unlock(); }
1013cab2bb3Spatrick 
1023cab2bb3Spatrick   // Should be guarded by ThreadRegistryLock.
GetThreadLocked(u32 tid)1033cab2bb3Spatrick   ThreadContextBase *GetThreadLocked(u32 tid) {
104d89ec533Spatrick     return threads_.empty() ? nullptr : threads_[tid];
1053cab2bb3Spatrick   }
1063cab2bb3Spatrick 
NumThreadsLocked()107*810390e3Srobert   u32 NumThreadsLocked() const { return threads_.size(); }
108*810390e3Srobert 
1093cab2bb3Spatrick   u32 CreateThread(uptr user_id, bool detached, u32 parent_tid, void *arg);
1103cab2bb3Spatrick 
1113cab2bb3Spatrick   typedef void (*ThreadCallback)(ThreadContextBase *tctx, void *arg);
1123cab2bb3Spatrick   // Invokes callback with a specified arg for each thread context.
1133cab2bb3Spatrick   // Should be guarded by ThreadRegistryLock.
1143cab2bb3Spatrick   void RunCallbackForEachThreadLocked(ThreadCallback cb, void *arg);
1153cab2bb3Spatrick 
1163cab2bb3Spatrick   typedef bool (*FindThreadCallback)(ThreadContextBase *tctx, void *arg);
117d89ec533Spatrick   // Finds a thread using the provided callback. Returns kInvalidTid if no
1183cab2bb3Spatrick   // thread is found.
1193cab2bb3Spatrick   u32 FindThread(FindThreadCallback cb, void *arg);
1203cab2bb3Spatrick   // Should be guarded by ThreadRegistryLock. Return 0 if no thread
1213cab2bb3Spatrick   // is found.
1223cab2bb3Spatrick   ThreadContextBase *FindThreadContextLocked(FindThreadCallback cb,
1233cab2bb3Spatrick                                              void *arg);
1243cab2bb3Spatrick   ThreadContextBase *FindThreadContextByOsIDLocked(tid_t os_id);
1253cab2bb3Spatrick 
1263cab2bb3Spatrick   void SetThreadName(u32 tid, const char *name);
1273cab2bb3Spatrick   void SetThreadNameByUserId(uptr user_id, const char *name);
1283cab2bb3Spatrick   void DetachThread(u32 tid, void *arg);
1293cab2bb3Spatrick   void JoinThread(u32 tid, void *arg);
130d89ec533Spatrick   // Finishes thread and returns previous status.
131d89ec533Spatrick   ThreadStatus FinishThread(u32 tid);
1323cab2bb3Spatrick   void StartThread(u32 tid, tid_t os_id, ThreadType thread_type, void *arg);
133*810390e3Srobert   u32 ConsumeThreadUserId(uptr user_id);
1343cab2bb3Spatrick   void SetThreadUserId(u32 tid, uptr user_id);
1353cab2bb3Spatrick 
136*810390e3Srobert   // OnFork must be called in the child process after fork to purge old
137*810390e3Srobert   // threads that don't exist anymore (except for the current thread tid).
138*810390e3Srobert   // Returns number of alive threads before fork.
139*810390e3Srobert   u32 OnFork(u32 tid);
140*810390e3Srobert 
1413cab2bb3Spatrick  private:
1423cab2bb3Spatrick   const ThreadContextFactory context_factory_;
1433cab2bb3Spatrick   const u32 max_threads_;
1443cab2bb3Spatrick   const u32 thread_quarantine_size_;
1453cab2bb3Spatrick   const u32 max_reuse_;
1463cab2bb3Spatrick 
147*810390e3Srobert   Mutex mtx_;
1483cab2bb3Spatrick 
1493cab2bb3Spatrick   u64 total_threads_;   // Total number of created threads. May be greater than
1503cab2bb3Spatrick                         // max_threads_ if contexts were reused.
1513cab2bb3Spatrick   uptr alive_threads_;  // Created or running.
1523cab2bb3Spatrick   uptr max_alive_threads_;
1533cab2bb3Spatrick   uptr running_threads_;
1543cab2bb3Spatrick 
155d89ec533Spatrick   InternalMmapVector<ThreadContextBase *> threads_;
1563cab2bb3Spatrick   IntrusiveList<ThreadContextBase> dead_threads_;
1573cab2bb3Spatrick   IntrusiveList<ThreadContextBase> invalid_threads_;
158*810390e3Srobert   DenseMap<uptr, Tid> live_;
1593cab2bb3Spatrick 
1603cab2bb3Spatrick   void QuarantinePush(ThreadContextBase *tctx);
1613cab2bb3Spatrick   ThreadContextBase *QuarantinePop();
1623cab2bb3Spatrick };
1633cab2bb3Spatrick 
1643cab2bb3Spatrick typedef GenericScopedLock<ThreadRegistry> ThreadRegistryLock;
1653cab2bb3Spatrick 
1663cab2bb3Spatrick } // namespace __sanitizer
1673cab2bb3Spatrick 
1683cab2bb3Spatrick #endif // SANITIZER_THREAD_REGISTRY_H
169