tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

thread_identity.cc (6562B)


      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)
     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 void AllocateThreadIdentityKey(ThreadIdentityReclaimerFunction reclaimer) {
     47  pthread_key_create(&thread_identity_pthread_key, reclaimer);
     48  pthread_key_initialized.store(true, std::memory_order_release);
     49 }
     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                              ThreadIdentityReclaimerFunction reclaimer) {
     78  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 #if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
     83  // NOTE: Not async-safe.  But can be open-coded.
     84  absl::call_once(init_thread_identity_key_once, AllocateThreadIdentityKey,
     85                  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  sigset_t all_signals;
    103  sigset_t curr_signals;
    104  sigfillset(&all_signals);
    105  pthread_sigmask(SIG_SETMASK, &all_signals, &curr_signals);
    106  pthread_setspecific(thread_identity_pthread_key,
    107                      reinterpret_cast<void*>(identity));
    108  pthread_sigmask(SIG_SETMASK, &curr_signals, nullptr);
    109 #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 }
    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 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  assert(CurrentThreadIdentityIfPresent() == nullptr);
    147 #endif
    148 }
    149 
    150 #if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
    151 ThreadIdentity* CurrentThreadIdentityIfPresent() {
    152  bool initialized = pthread_key_initialized.load(std::memory_order_acquire);
    153  if (!initialized) {
    154    return nullptr;
    155  }
    156  return reinterpret_cast<ThreadIdentity*>(
    157      pthread_getspecific(thread_identity_pthread_key));
    158 }
    159 #endif
    160 
    161 }  // namespace base_internal
    162 ABSL_NAMESPACE_END
    163 }  // namespace absl