summaryrefslogtreecommitdiff
path: root/standalone/tsd_exclusive.h
diff options
context:
space:
mode:
Diffstat (limited to 'standalone/tsd_exclusive.h')
-rw-r--r--standalone/tsd_exclusive.h42
1 files changed, 34 insertions, 8 deletions
diff --git a/standalone/tsd_exclusive.h b/standalone/tsd_exclusive.h
index d49427b2005..23836742023 100644
--- a/standalone/tsd_exclusive.h
+++ b/standalone/tsd_exclusive.h
@@ -11,6 +11,8 @@
#include "tsd.h"
+#include "string_utils.h"
+
namespace scudo {
struct ThreadState {
@@ -25,7 +27,7 @@ struct ThreadState {
template <class Allocator> void teardownThread(void *Ptr);
template <class Allocator> struct TSDRegistryExT {
- void init(Allocator *Instance) {
+ void init(Allocator *Instance) REQUIRES(Mutex) {
DCHECK(!Initialized);
Instance->init();
CHECK_EQ(pthread_key_create(&PThreadKey, teardownThread<Allocator>), 0);
@@ -33,14 +35,14 @@ template <class Allocator> struct TSDRegistryExT {
Initialized = true;
}
- void initOnceMaybe(Allocator *Instance) {
+ void initOnceMaybe(Allocator *Instance) EXCLUDES(Mutex) {
ScopedLock L(Mutex);
if (LIKELY(Initialized))
return;
init(Instance); // Sets Initialized.
}
- void unmapTestOnly(Allocator *Instance) {
+ void unmapTestOnly(Allocator *Instance) EXCLUDES(Mutex) {
DCHECK(Instance);
if (reinterpret_cast<Allocator *>(pthread_getspecific(PThreadKey))) {
DCHECK_EQ(reinterpret_cast<Allocator *>(pthread_getspecific(PThreadKey)),
@@ -53,16 +55,32 @@ template <class Allocator> struct TSDRegistryExT {
FallbackTSD.commitBack(Instance);
FallbackTSD = {};
State = {};
+ ScopedLock L(Mutex);
Initialized = false;
}
+ void drainCaches(Allocator *Instance) {
+ // We don't have a way to iterate all thread local `ThreadTSD`s. Simply
+ // drain the `ThreadTSD` of current thread and `FallbackTSD`.
+ Instance->drainCache(&ThreadTSD);
+ FallbackTSD.lock();
+ Instance->drainCache(&FallbackTSD);
+ FallbackTSD.unlock();
+ }
+
ALWAYS_INLINE void initThreadMaybe(Allocator *Instance, bool MinimalInit) {
if (LIKELY(State.InitState != ThreadState::NotInitialized))
return;
initThread(Instance, MinimalInit);
}
- ALWAYS_INLINE TSD<Allocator> *getTSDAndLock(bool *UnlockRequired) {
+ // TODO(chiahungduan): Consider removing the argument `UnlockRequired` by
+ // embedding the logic into TSD or always locking the TSD. It will enable us
+ // to properly mark thread annotation here and adding proper runtime
+ // assertions in the member functions of TSD. For example, assert the lock is
+ // acquired before calling TSD::commitBack().
+ ALWAYS_INLINE TSD<Allocator> *
+ getTSDAndLock(bool *UnlockRequired) NO_THREAD_SAFETY_ANALYSIS {
if (LIKELY(State.InitState == ThreadState::Initialized &&
!atomic_load(&Disabled, memory_order_acquire))) {
*UnlockRequired = false;
@@ -75,13 +93,13 @@ template <class Allocator> struct TSDRegistryExT {
// To disable the exclusive TSD registry, we effectively lock the fallback TSD
// and force all threads to attempt to use it instead of their local one.
- void disable() {
+ void disable() NO_THREAD_SAFETY_ANALYSIS {
Mutex.lock();
FallbackTSD.lock();
atomic_store(&Disabled, 1U, memory_order_release);
}
- void enable() {
+ void enable() NO_THREAD_SAFETY_ANALYSIS {
atomic_store(&Disabled, 0U, memory_order_release);
FallbackTSD.unlock();
Mutex.unlock();
@@ -97,6 +115,13 @@ template <class Allocator> struct TSDRegistryExT {
bool getDisableMemInit() { return State.DisableMemInit; }
+ void getStats(ScopedString *Str) {
+ // We don't have a way to iterate all thread local `ThreadTSD`s. Instead of
+ // printing only self `ThreadTSD` which may mislead the usage, we just skip
+ // it.
+ Str->append("Exclusive TSD don't support iterating each TSD\n");
+ }
+
private:
// Using minimal initialization allows for global initialization while keeping
// the thread specific structure untouched. The fallback structure will be
@@ -113,7 +138,7 @@ private:
}
pthread_key_t PThreadKey = {};
- bool Initialized = false;
+ bool Initialized GUARDED_BY(Mutex) = false;
atomic_u8 Disabled = {};
TSD<Allocator> FallbackTSD;
HybridMutex Mutex;
@@ -128,7 +153,8 @@ thread_local TSD<Allocator> TSDRegistryExT<Allocator>::ThreadTSD;
template <class Allocator>
thread_local ThreadState TSDRegistryExT<Allocator>::State;
-template <class Allocator> void teardownThread(void *Ptr) {
+template <class Allocator>
+void teardownThread(void *Ptr) NO_THREAD_SAFETY_ANALYSIS {
typedef TSDRegistryExT<Allocator> TSDRegistryT;
Allocator *Instance = reinterpret_cast<Allocator *>(Ptr);
// The glibc POSIX thread-local-storage deallocation routine calls user