Coverage Report

Created: 2023-09-25 06:27

/src/abseil-cpp/absl/base/internal/thread_identity.h
Line
Count
Source (jump to first uncovered line)
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
33
#include "absl/base/config.h"
34
#include "absl/base/internal/per_thread_tls.h"
35
#include "absl/base/optimization.h"
36
37
namespace absl {
38
ABSL_NAMESPACE_BEGIN
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
0
  ThreadIdentity* thread_identity() {
62
0
    return reinterpret_cast<ThreadIdentity*>(this);
63
0
  }
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.
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).
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 { kAvailable, kQueued };
108
  std::atomic<State> state;
109
110
  // The wait parameters of the current wait.  waitp is null if the
111
  // thread is not waiting. Transitions from null to non-null must
112
  // occur before the enqueue commit point (state = kQueued in
113
  // Enqueue() and CondVarEnqueue()). Transitions from non-null to
114
  // null must occur after the wait is finished (state = kAvailable in
115
  // Mutex::Block() and CondVar::WaitCommon()). This field may be
116
  // changed only by the thread that describes this PerThreadSynch.  A
117
  // special case is Fer(), which calls Enqueue() on another thread,
118
  // but with an identical SynchWaitParams pointer, thus leaving the
119
  // pointer unchanged.
120
  SynchWaitParams* waitp;
121
122
  intptr_t readers;  // Number of readers in mutex.
123
124
  // When priority will next be read (cycles).
125
  int64_t next_priority_read_cycles;
126
127
  // Locks held; used during deadlock detection.
128
  // Allocated in Synch_GetAllLocks() and freed in ReclaimThreadIdentity().
129
  SynchLocksHeld* all_locks;
130
};
131
132
// The instances of this class are allocated in NewThreadIdentity() with an
133
// alignment of PerThreadSynch::kAlignment.
134
//
135
// NOTE: The layout of fields in this structure is critical, please do not
136
//       add, remove, or modify the field placements without fully auditing the
137
//       layout.
138
struct ThreadIdentity {
139
  // Must be the first member.  The Mutex implementation requires that
140
  // the PerThreadSynch object associated with each thread is
141
  // PerThreadSynch::kAlignment aligned.  We provide this alignment on
142
  // ThreadIdentity itself.
143
  PerThreadSynch per_thread_synch;
144
145
  // Private: Reserved for absl::synchronization_internal::Waiter.
146
  struct WaiterState {
147
    alignas(void*) char data[256];
148
  } waiter_state;
149
150
  // Used by PerThreadSem::{Get,Set}ThreadBlockedCounter().
151
  std::atomic<int>* blocked_count_ptr;
152
153
  // The following variables are mostly read/written just by the
154
  // thread itself.  The only exception is that these are read by
155
  // a ticker thread as a hint.
156
  std::atomic<int> ticker;      // Tick counter, incremented once per second.
157
  std::atomic<int> wait_start;  // Ticker value when thread started waiting.
158
  std::atomic<bool> is_idle;    // Has thread become idle yet?
159
160
  ThreadIdentity* next;
161
};
162
163
// Returns the ThreadIdentity object representing the calling thread; guaranteed
164
// to be unique for its lifetime.  The returned object will remain valid for the
165
// program's lifetime; although it may be re-assigned to a subsequent thread.
166
// If one does not exist, return nullptr instead.
167
//
168
// Does not malloc(*), and is async-signal safe.
169
// [*] Technically pthread_setspecific() does malloc on first use; however this
170
// is handled internally within tcmalloc's initialization already. Note that
171
// darwin does *not* use tcmalloc, so this can catch you if using MallocHooks
172
// on Apple platforms. Whatever function is calling your MallocHooks will need
173
// to watch for recursion on Apple platforms.
174
//
175
// New ThreadIdentity objects can be constructed and associated with a thread
176
// by calling GetOrCreateCurrentThreadIdentity() in per-thread-sem.h.
177
ThreadIdentity* CurrentThreadIdentityIfPresent();
178
179
using ThreadIdentityReclaimerFunction = void (*)(void*);
180
181
// Sets the current thread identity to the given value.  'reclaimer' is a
182
// pointer to the global function for cleaning up instances on thread
183
// destruction.
184
void SetCurrentThreadIdentity(ThreadIdentity* identity,
185
                              ThreadIdentityReclaimerFunction reclaimer);
186
187
// Removes the currently associated ThreadIdentity from the running thread.
188
// This must be called from inside the ThreadIdentityReclaimerFunction, and only
189
// from that function.
190
void ClearCurrentThreadIdentity();
191
192
// May be chosen at compile time via: -DABSL_FORCE_THREAD_IDENTITY_MODE=<mode
193
// index>
194
#ifdef ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
195
#error ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC cannot be directly set
196
#else
197
#define ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC 0
198
#endif
199
200
#ifdef ABSL_THREAD_IDENTITY_MODE_USE_TLS
201
#error ABSL_THREAD_IDENTITY_MODE_USE_TLS cannot be directly set
202
#else
203
#define ABSL_THREAD_IDENTITY_MODE_USE_TLS 1
204
#endif
205
206
#ifdef ABSL_THREAD_IDENTITY_MODE_USE_CPP11
207
#error ABSL_THREAD_IDENTITY_MODE_USE_CPP11 cannot be directly set
208
#else
209
#define ABSL_THREAD_IDENTITY_MODE_USE_CPP11 2
210
#endif
211
212
#ifdef ABSL_THREAD_IDENTITY_MODE
213
#error ABSL_THREAD_IDENTITY_MODE cannot be directly set
214
#elif defined(ABSL_FORCE_THREAD_IDENTITY_MODE)
215
#define ABSL_THREAD_IDENTITY_MODE ABSL_FORCE_THREAD_IDENTITY_MODE
216
#elif defined(_WIN32) && !defined(__MINGW32__)
217
#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11
218
#elif defined(__APPLE__) && defined(ABSL_HAVE_THREAD_LOCAL)
219
#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11
220
#elif ABSL_PER_THREAD_TLS && defined(__GOOGLE_GRTE_VERSION__) && \
221
    (__GOOGLE_GRTE_VERSION__ >= 20140228L)
222
// Support for async-safe TLS was specifically added in GRTEv4.  It's not
223
// present in the upstream eglibc.
224
// Note:  Current default for production systems.
225
#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_TLS
226
#else
227
#define ABSL_THREAD_IDENTITY_MODE \
228
  ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
229
#endif
230
231
#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \
232
    ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
233
234
#if ABSL_PER_THREAD_TLS
235
ABSL_CONST_INIT extern ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity*
236
    thread_identity_ptr;
237
#elif defined(ABSL_HAVE_THREAD_LOCAL)
238
ABSL_CONST_INIT extern thread_local ThreadIdentity* thread_identity_ptr;
239
#else
240
#error Thread-local storage not detected on this platform
241
#endif
242
243
// thread_local variables cannot be in headers exposed by DLLs or in certain
244
// build configurations on Apple platforms. However, it is important for
245
// performance reasons in general that `CurrentThreadIdentityIfPresent` be
246
// inlined. In the other cases we opt to have the function not be inlined. Note
247
// that `CurrentThreadIdentityIfPresent` is declared above so we can exclude
248
// this entire inline definition.
249
#if !defined(__APPLE__) && !defined(ABSL_BUILD_DLL) && \
250
    !defined(ABSL_CONSUME_DLL)
251
#define ABSL_INTERNAL_INLINE_CURRENT_THREAD_IDENTITY_IF_PRESENT 1
252
#endif
253
254
#ifdef ABSL_INTERNAL_INLINE_CURRENT_THREAD_IDENTITY_IF_PRESENT
255
inline ThreadIdentity* CurrentThreadIdentityIfPresent() {
256
  return thread_identity_ptr;
257
}
258
#endif
259
260
#elif ABSL_THREAD_IDENTITY_MODE != \
261
    ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
262
#error Unknown ABSL_THREAD_IDENTITY_MODE
263
#endif
264
265
}  // namespace base_internal
266
ABSL_NAMESPACE_END
267
}  // namespace absl
268
269
#endif  // ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_