Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 1 | // Copyright 2017 The Abseil Authors. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // https://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | // |
| 15 | // Each active thread has an ThreadIdentity that may represent the thread in |
| 16 | // various level interfaces. ThreadIdentity objects are never deallocated. |
| 17 | // When a thread terminates, its ThreadIdentity object may be reused for a |
| 18 | // thread created later. |
| 19 | |
| 20 | #ifndef ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_ |
| 21 | #define ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_ |
| 22 | |
| 23 | #ifndef _WIN32 |
| 24 | #include <pthread.h> |
| 25 | // Defines __GOOGLE_GRTE_VERSION__ (via glibc-specific features.h) when |
| 26 | // supported. |
| 27 | #include <unistd.h> |
| 28 | #endif |
| 29 | |
| 30 | #include <atomic> |
| 31 | #include <cstdint> |
| 32 | |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 33 | #include "absl/base/config.h" |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 34 | #include "absl/base/internal/per_thread_tls.h" |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 35 | #include "absl/base/optimization.h" |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 36 | |
| 37 | namespace absl { |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 38 | ABSL_NAMESPACE_BEGIN |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 39 | |
| 40 | struct SynchLocksHeld; |
| 41 | struct SynchWaitParams; |
| 42 | |
| 43 | namespace base_internal { |
| 44 | |
| 45 | class SpinLock; |
| 46 | struct ThreadIdentity; |
| 47 | |
| 48 | // Used by the implementation of absl::Mutex and absl::CondVar. |
| 49 | struct PerThreadSynch { |
| 50 | // The internal representation of absl::Mutex and absl::CondVar rely |
| 51 | // on the alignment of PerThreadSynch. Both store the address of the |
| 52 | // PerThreadSynch in the high-order bits of their internal state, |
| 53 | // which means the low kLowZeroBits of the address of PerThreadSynch |
| 54 | // must be zero. |
| 55 | static constexpr int kLowZeroBits = 8; |
| 56 | static constexpr int kAlignment = 1 << kLowZeroBits; |
| 57 | |
| 58 | // Returns the associated ThreadIdentity. |
| 59 | // This can be implemented as a cast because we guarantee |
| 60 | // PerThreadSynch is the first element of ThreadIdentity. |
| 61 | ThreadIdentity* thread_identity() { |
| 62 | return reinterpret_cast<ThreadIdentity*>(this); |
| 63 | } |
| 64 | |
| 65 | PerThreadSynch *next; // Circular waiter queue; initialized to 0. |
| 66 | PerThreadSynch *skip; // If non-zero, all entries in Mutex queue |
| 67 | // up to and including "skip" have same |
| 68 | // condition as this, and will be woken later |
| 69 | bool may_skip; // if false while on mutex queue, a mutex unlocker |
| 70 | // is using this PerThreadSynch as a terminator. Its |
| 71 | // skip field must not be filled in because the loop |
| 72 | // might then skip over the terminator. |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 73 | bool wake; // This thread is to be woken from a Mutex. |
| 74 | // If "x" is on a waiter list for a mutex, "x->cond_waiter" is true iff the |
| 75 | // waiter is waiting on the mutex as part of a CV Wait or Mutex Await. |
| 76 | // |
| 77 | // The value of "x->cond_waiter" is meaningless if "x" is not on a |
| 78 | // Mutex waiter list. |
| 79 | bool cond_waiter; |
| 80 | bool maybe_unlocking; // Valid at head of Mutex waiter queue; |
| 81 | // true if UnlockSlow could be searching |
| 82 | // for a waiter to wake. Used for an optimization |
| 83 | // in Enqueue(). true is always a valid value. |
| 84 | // Can be reset to false when the unlocker or any |
| 85 | // writer releases the lock, or a reader fully |
| 86 | // releases the lock. It may not be set to false |
| 87 | // by a reader that decrements the count to |
| 88 | // non-zero. protected by mutex spinlock |
| 89 | bool suppress_fatal_errors; // If true, try to proceed even in the face |
| 90 | // of broken invariants. This is used within |
| 91 | // fatal signal handlers to improve the |
| 92 | // chances of debug logging information being |
| 93 | // output successfully. |
| 94 | int priority; // Priority of thread (updated every so often). |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 95 | |
| 96 | // State values: |
| 97 | // kAvailable: This PerThreadSynch is available. |
| 98 | // kQueued: This PerThreadSynch is unavailable, it's currently queued on a |
| 99 | // Mutex or CondVar waistlist. |
| 100 | // |
| 101 | // Transitions from kQueued to kAvailable require a release |
| 102 | // barrier. This is needed as a waiter may use "state" to |
| 103 | // independently observe that it's no longer queued. |
| 104 | // |
| 105 | // Transitions from kAvailable to kQueued require no barrier, they |
| 106 | // are externally ordered by the Mutex. |
| 107 | enum State { |
| 108 | kAvailable, |
| 109 | kQueued |
| 110 | }; |
| 111 | std::atomic<State> state; |
| 112 | |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 113 | // The wait parameters of the current wait. waitp is null if the |
| 114 | // thread is not waiting. Transitions from null to non-null must |
| 115 | // occur before the enqueue commit point (state = kQueued in |
| 116 | // Enqueue() and CondVarEnqueue()). Transitions from non-null to |
| 117 | // null must occur after the wait is finished (state = kAvailable in |
| 118 | // Mutex::Block() and CondVar::WaitCommon()). This field may be |
| 119 | // changed only by the thread that describes this PerThreadSynch. A |
| 120 | // special case is Fer(), which calls Enqueue() on another thread, |
| 121 | // but with an identical SynchWaitParams pointer, thus leaving the |
| 122 | // pointer unchanged. |
| 123 | SynchWaitParams* waitp; |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 124 | |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 125 | intptr_t readers; // Number of readers in mutex. |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 126 | |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 127 | // When priority will next be read (cycles). |
| 128 | int64_t next_priority_read_cycles; |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 129 | |
| 130 | // Locks held; used during deadlock detection. |
| 131 | // Allocated in Synch_GetAllLocks() and freed in ReclaimThreadIdentity(). |
| 132 | SynchLocksHeld *all_locks; |
| 133 | }; |
| 134 | |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 135 | // The instances of this class are allocated in NewThreadIdentity() with an |
| 136 | // alignment of PerThreadSynch::kAlignment. |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 137 | struct ThreadIdentity { |
| 138 | // Must be the first member. The Mutex implementation requires that |
| 139 | // the PerThreadSynch object associated with each thread is |
| 140 | // PerThreadSynch::kAlignment aligned. We provide this alignment on |
| 141 | // ThreadIdentity itself. |
| 142 | PerThreadSynch per_thread_synch; |
| 143 | |
| 144 | // Private: Reserved for absl::synchronization_internal::Waiter. |
| 145 | struct WaiterState { |
| 146 | char data[128]; |
| 147 | } waiter_state; |
| 148 | |
| 149 | // Used by PerThreadSem::{Get,Set}ThreadBlockedCounter(). |
| 150 | std::atomic<int>* blocked_count_ptr; |
| 151 | |
| 152 | // The following variables are mostly read/written just by the |
| 153 | // thread itself. The only exception is that these are read by |
| 154 | // a ticker thread as a hint. |
| 155 | std::atomic<int> ticker; // Tick counter, incremented once per second. |
| 156 | std::atomic<int> wait_start; // Ticker value when thread started waiting. |
| 157 | std::atomic<bool> is_idle; // Has thread become idle yet? |
| 158 | |
| 159 | ThreadIdentity* next; |
| 160 | }; |
| 161 | |
| 162 | // Returns the ThreadIdentity object representing the calling thread; guaranteed |
| 163 | // to be unique for its lifetime. The returned object will remain valid for the |
| 164 | // program's lifetime; although it may be re-assigned to a subsequent thread. |
| 165 | // If one does not exist, return nullptr instead. |
| 166 | // |
| 167 | // Does not malloc(*), and is async-signal safe. |
| 168 | // [*] Technically pthread_setspecific() does malloc on first use; however this |
| 169 | // is handled internally within tcmalloc's initialization already. |
| 170 | // |
| 171 | // New ThreadIdentity objects can be constructed and associated with a thread |
| 172 | // by calling GetOrCreateCurrentThreadIdentity() in per-thread-sem.h. |
| 173 | ThreadIdentity* CurrentThreadIdentityIfPresent(); |
| 174 | |
| 175 | using ThreadIdentityReclaimerFunction = void (*)(void*); |
| 176 | |
| 177 | // Sets the current thread identity to the given value. 'reclaimer' is a |
| 178 | // pointer to the global function for cleaning up instances on thread |
| 179 | // destruction. |
| 180 | void SetCurrentThreadIdentity(ThreadIdentity* identity, |
| 181 | ThreadIdentityReclaimerFunction reclaimer); |
| 182 | |
| 183 | // Removes the currently associated ThreadIdentity from the running thread. |
| 184 | // This must be called from inside the ThreadIdentityReclaimerFunction, and only |
| 185 | // from that function. |
| 186 | void ClearCurrentThreadIdentity(); |
| 187 | |
| 188 | // May be chosen at compile time via: -DABSL_FORCE_THREAD_IDENTITY_MODE=<mode |
| 189 | // index> |
| 190 | #ifdef ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC |
| 191 | #error ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC cannot be direcly set |
| 192 | #else |
| 193 | #define ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC 0 |
| 194 | #endif |
| 195 | |
| 196 | #ifdef ABSL_THREAD_IDENTITY_MODE_USE_TLS |
| 197 | #error ABSL_THREAD_IDENTITY_MODE_USE_TLS cannot be direcly set |
| 198 | #else |
| 199 | #define ABSL_THREAD_IDENTITY_MODE_USE_TLS 1 |
| 200 | #endif |
| 201 | |
| 202 | #ifdef ABSL_THREAD_IDENTITY_MODE_USE_CPP11 |
| 203 | #error ABSL_THREAD_IDENTITY_MODE_USE_CPP11 cannot be direcly set |
| 204 | #else |
| 205 | #define ABSL_THREAD_IDENTITY_MODE_USE_CPP11 2 |
| 206 | #endif |
| 207 | |
| 208 | #ifdef ABSL_THREAD_IDENTITY_MODE |
| 209 | #error ABSL_THREAD_IDENTITY_MODE cannot be direcly set |
| 210 | #elif defined(ABSL_FORCE_THREAD_IDENTITY_MODE) |
| 211 | #define ABSL_THREAD_IDENTITY_MODE ABSL_FORCE_THREAD_IDENTITY_MODE |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 212 | #elif defined(_WIN32) && !defined(__MINGW32__) |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 213 | #define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11 |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 214 | #elif defined(__APPLE__) && defined(ABSL_HAVE_THREAD_LOCAL) |
| 215 | #define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11 |
| 216 | #elif ABSL_PER_THREAD_TLS && defined(__GOOGLE_GRTE_VERSION__) && \ |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 217 | (__GOOGLE_GRTE_VERSION__ >= 20140228L) |
| 218 | // Support for async-safe TLS was specifically added in GRTEv4. It's not |
| 219 | // present in the upstream eglibc. |
| 220 | // Note: Current default for production systems. |
| 221 | #define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_TLS |
| 222 | #else |
| 223 | #define ABSL_THREAD_IDENTITY_MODE \ |
| 224 | ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC |
| 225 | #endif |
| 226 | |
| 227 | #if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \ |
| 228 | ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11 |
| 229 | |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 230 | #if ABSL_PER_THREAD_TLS |
| 231 | ABSL_CONST_INIT extern ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* |
| 232 | thread_identity_ptr; |
| 233 | #elif defined(ABSL_HAVE_THREAD_LOCAL) |
| 234 | ABSL_CONST_INIT extern thread_local ThreadIdentity* thread_identity_ptr; |
| 235 | #else |
| 236 | #error Thread-local storage not detected on this platform |
| 237 | #endif |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 238 | |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 239 | // thread_local variables cannot be in headers exposed by DLLs. However, it is |
| 240 | // important for performance reasons in general that |
| 241 | // `CurrentThreadIdentityIfPresent` be inlined. This is not possible across a |
| 242 | // DLL boundary so, with DLLs, we opt to have the function not be inlined. Note |
| 243 | // that `CurrentThreadIdentityIfPresent` is declared above so we can exclude |
| 244 | // this entire inline definition when compiling as a DLL. |
| 245 | #if !defined(ABSL_BUILD_DLL) && !defined(ABSL_CONSUME_DLL) |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 246 | inline ThreadIdentity* CurrentThreadIdentityIfPresent() { |
| 247 | return thread_identity_ptr; |
| 248 | } |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 249 | #endif |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 250 | |
| 251 | #elif ABSL_THREAD_IDENTITY_MODE != \ |
| 252 | ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC |
| 253 | #error Unknown ABSL_THREAD_IDENTITY_MODE |
| 254 | #endif |
| 255 | |
| 256 | } // namespace base_internal |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 257 | ABSL_NAMESPACE_END |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 258 | } // namespace absl |
| 259 | |
| 260 | #endif // ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_ |