Coverage Report

Created: 2024-09-23 06:29

/src/abseil-cpp/absl/base/internal/thread_identity.cc
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
#include "absl/base/internal/thread_identity.h"
16
17
#if !defined(_WIN32) || defined(__MINGW32__)
18
#include <pthread.h>
19
#ifndef __wasi__
20
// WASI does not provide this header, either way we disable use
21
// of signals with it below.
22
#include <signal.h>
23
#endif
24
#endif
25
26
#include <atomic>
27
#include <cassert>
28
#include <memory>
29
30
#include "absl/base/attributes.h"
31
#include "absl/base/call_once.h"
32
#include "absl/base/internal/raw_logging.h"
33
#include "absl/base/internal/spinlock.h"
34
35
namespace absl {
36
ABSL_NAMESPACE_BEGIN
37
namespace base_internal {
38
39
#if ABSL_THREAD_IDENTITY_MODE != ABSL_THREAD_IDENTITY_MODE_USE_CPP11
40
namespace {
41
// Used to co-ordinate one-time creation of our pthread_key
42
absl::once_flag init_thread_identity_key_once;
43
pthread_key_t thread_identity_pthread_key;
44
std::atomic<bool> pthread_key_initialized(false);
45
46
2
void AllocateThreadIdentityKey(ThreadIdentityReclaimerFunction reclaimer) {
47
2
  pthread_key_create(&thread_identity_pthread_key, reclaimer);
48
2
  pthread_key_initialized.store(true, std::memory_order_release);
49
2
}
50
}  // namespace
51
#endif
52
53
#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \
54
    ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
55
// The actual TLS storage for a thread's currently associated ThreadIdentity.
56
// This is referenced by inline accessors in the header.
57
// "protected" visibility ensures that if multiple instances of Abseil code
58
// exist within a process (via dlopen() or similar), references to
59
// thread_identity_ptr from each instance of the code will refer to
60
// *different* instances of this ptr.
61
// Apple platforms have the visibility attribute, but issue a compile warning
62
// that protected visibility is unsupported.
63
ABSL_CONST_INIT  // Must come before __attribute__((visibility("protected")))
64
#if ABSL_HAVE_ATTRIBUTE(visibility) && !defined(__APPLE__)
65
    __attribute__((visibility("protected")))
66
#endif  // ABSL_HAVE_ATTRIBUTE(visibility) && !defined(__APPLE__)
67
#if ABSL_PER_THREAD_TLS
68
    // Prefer __thread to thread_local as benchmarks indicate it is a bit
69
    // faster.
70
    ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* thread_identity_ptr = nullptr;
71
#elif defined(ABSL_HAVE_THREAD_LOCAL)
72
    thread_local ThreadIdentity* thread_identity_ptr = nullptr;
73
#endif  // ABSL_PER_THREAD_TLS
74
#endif  // TLS or CPP11
75
76
void SetCurrentThreadIdentity(ThreadIdentity* identity,
77
2
                              ThreadIdentityReclaimerFunction reclaimer) {
78
2
  assert(CurrentThreadIdentityIfPresent() == nullptr);
79
  // Associate our destructor.
80
  // NOTE: This call to pthread_setspecific is currently the only immovable
81
  // barrier to CurrentThreadIdentity() always being async signal safe.
82
2
#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
83
  // NOTE: Not async-safe.  But can be open-coded.
84
2
  absl::call_once(init_thread_identity_key_once, AllocateThreadIdentityKey,
85
2
                  reclaimer);
86
87
#if defined(__wasi__) || defined(__EMSCRIPTEN__) || defined(__MINGW32__) || \
88
    defined(__hexagon__)
89
  // Emscripten, WASI and MinGW pthread implementations does not support
90
  // signals. See
91
  // https://kripken.github.io/emscripten-site/docs/porting/pthreads.html for
92
  // more information.
93
  pthread_setspecific(thread_identity_pthread_key,
94
                      reinterpret_cast<void*>(identity));
95
#else
96
  // We must mask signals around the call to setspecific as with current glibc,
97
  // a concurrent getspecific (needed for GetCurrentThreadIdentityIfPresent())
98
  // may zero our value.
99
  //
100
  // While not officially async-signal safe, getspecific within a signal handler
101
  // is otherwise OK.
102
2
  sigset_t all_signals;
103
2
  sigset_t curr_signals;
104
2
  sigfillset(&all_signals);
105
2
  pthread_sigmask(SIG_SETMASK, &all_signals, &curr_signals);
106
2
  pthread_setspecific(thread_identity_pthread_key,
107
2
                      reinterpret_cast<void*>(identity));
108
2
  pthread_sigmask(SIG_SETMASK, &curr_signals, nullptr);
109
2
#endif  // !__EMSCRIPTEN__ && !__MINGW32__
110
111
#elif ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS
112
  // NOTE: Not async-safe.  But can be open-coded.
113
  absl::call_once(init_thread_identity_key_once, AllocateThreadIdentityKey,
114
                  reclaimer);
115
  pthread_setspecific(thread_identity_pthread_key,
116
                      reinterpret_cast<void*>(identity));
117
  thread_identity_ptr = identity;
118
#elif ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
119
  thread_local std::unique_ptr<ThreadIdentity, ThreadIdentityReclaimerFunction>
120
      holder(identity, reclaimer);
121
  thread_identity_ptr = identity;
122
#else
123
#error Unimplemented ABSL_THREAD_IDENTITY_MODE
124
#endif
125
2
}
126
127
#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \
128
    ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
129
130
// Please see the comment on `CurrentThreadIdentityIfPresent` in
131
// thread_identity.h. When we cannot expose thread_local variables in
132
// headers, we opt for the correct-but-slower option of not inlining this
133
// function.
134
#ifndef ABSL_INTERNAL_INLINE_CURRENT_THREAD_IDENTITY_IF_PRESENT
135
ThreadIdentity* CurrentThreadIdentityIfPresent() { return thread_identity_ptr; }
136
#endif
137
#endif
138
139
0
void ClearCurrentThreadIdentity() {
140
#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \
141
    ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
142
  thread_identity_ptr = nullptr;
143
#elif ABSL_THREAD_IDENTITY_MODE == \
144
    ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
145
  // pthread_setspecific expected to clear value on destruction
146
0
  assert(CurrentThreadIdentityIfPresent() == nullptr);
147
0
#endif
148
0
}
149
150
#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
151
11.3M
ThreadIdentity* CurrentThreadIdentityIfPresent() {
152
11.3M
  bool initialized = pthread_key_initialized.load(std::memory_order_acquire);
153
11.3M
  if (!initialized) {
154
4
    return nullptr;
155
4
  }
156
11.3M
  return reinterpret_cast<ThreadIdentity*>(
157
11.3M
      pthread_getspecific(thread_identity_pthread_key));
158
11.3M
}
159
#endif
160
161
}  // namespace base_internal
162
ABSL_NAMESPACE_END
163
}  // namespace absl