thread_identity.cc
Go to the documentation of this file.
00001 // Copyright 2017 The Abseil Authors.
00002 //
00003 // Licensed under the Apache License, Version 2.0 (the "License");
00004 // you may not use this file except in compliance with the License.
00005 // You may obtain a copy of the License at
00006 //
00007 //      https://www.apache.org/licenses/LICENSE-2.0
00008 //
00009 // Unless required by applicable law or agreed to in writing, software
00010 // distributed under the License is distributed on an "AS IS" BASIS,
00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 // See the License for the specific language governing permissions and
00013 // limitations under the License.
00014 
00015 #include "absl/base/internal/thread_identity.h"
00016 
00017 #ifndef _WIN32
00018 #include <pthread.h>
00019 #include <signal.h>
00020 #endif
00021 
00022 #include <atomic>
00023 #include <cassert>
00024 #include <memory>
00025 
00026 #include "absl/base/call_once.h"
00027 #include "absl/base/internal/raw_logging.h"
00028 #include "absl/base/internal/spinlock.h"
00029 
00030 namespace absl {
00031 namespace base_internal {
00032 
00033 #if ABSL_THREAD_IDENTITY_MODE != ABSL_THREAD_IDENTITY_MODE_USE_CPP11
00034 namespace {
00035 // Used to co-ordinate one-time creation of our pthread_key
00036 absl::once_flag init_thread_identity_key_once;
00037 pthread_key_t thread_identity_pthread_key;
00038 std::atomic<bool> pthread_key_initialized(false);
00039 
00040 void AllocateThreadIdentityKey(ThreadIdentityReclaimerFunction reclaimer) {
00041   pthread_key_create(&thread_identity_pthread_key, reclaimer);
00042   pthread_key_initialized.store(true, std::memory_order_release);
00043 }
00044 }  // namespace
00045 #endif
00046 
00047 #if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \
00048     ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
00049 // The actual TLS storage for a thread's currently associated ThreadIdentity.
00050 // This is referenced by inline accessors in the header.
00051 // "protected" visibility ensures that if multiple instances of Abseil code
00052 // exist within a process (via dlopen() or similar), references to
00053 // thread_identity_ptr from each instance of the code will refer to
00054 // *different* instances of this ptr.
00055 #ifdef __GNUC__
00056 __attribute__((visibility("protected")))
00057 #endif  // __GNUC__
00058   ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* thread_identity_ptr;
00059 #endif  // TLS or CPP11
00060 
00061 void SetCurrentThreadIdentity(
00062     ThreadIdentity* identity, ThreadIdentityReclaimerFunction reclaimer) {
00063   assert(CurrentThreadIdentityIfPresent() == nullptr);
00064   // Associate our destructor.
00065   // NOTE: This call to pthread_setspecific is currently the only immovable
00066   // barrier to CurrentThreadIdentity() always being async signal safe.
00067 #if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
00068   // NOTE: Not async-safe.  But can be open-coded.
00069   absl::call_once(init_thread_identity_key_once, AllocateThreadIdentityKey,
00070                   reclaimer);
00071 
00072 #ifdef __EMSCRIPTEN__
00073   // Emscripten PThread implementation does not support signals.
00074   // See https://kripken.github.io/emscripten-site/docs/porting/pthreads.html
00075   // for more information.
00076   pthread_setspecific(thread_identity_pthread_key,
00077                       reinterpret_cast<void*>(identity));
00078 #else
00079   // We must mask signals around the call to setspecific as with current glibc,
00080   // a concurrent getspecific (needed for GetCurrentThreadIdentityIfPresent())
00081   // may zero our value.
00082   //
00083   // While not officially async-signal safe, getspecific within a signal handler
00084   // is otherwise OK.
00085   sigset_t all_signals;
00086   sigset_t curr_signals;
00087   sigfillset(&all_signals);
00088   pthread_sigmask(SIG_SETMASK, &all_signals, &curr_signals);
00089   pthread_setspecific(thread_identity_pthread_key,
00090                       reinterpret_cast<void*>(identity));
00091   pthread_sigmask(SIG_SETMASK, &curr_signals, nullptr);
00092 #endif  // !__EMSCRIPTEN__
00093 
00094 #elif ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS
00095   // NOTE: Not async-safe.  But can be open-coded.
00096   absl::call_once(init_thread_identity_key_once, AllocateThreadIdentityKey,
00097                   reclaimer);
00098   pthread_setspecific(thread_identity_pthread_key,
00099                       reinterpret_cast<void*>(identity));
00100   thread_identity_ptr = identity;
00101 #elif ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
00102   thread_local std::unique_ptr<ThreadIdentity, ThreadIdentityReclaimerFunction>
00103       holder(identity, reclaimer);
00104   thread_identity_ptr = identity;
00105 #else
00106 #error Unimplemented ABSL_THREAD_IDENTITY_MODE
00107 #endif
00108 }
00109 
00110 void ClearCurrentThreadIdentity() {
00111 #if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \
00112     ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
00113   thread_identity_ptr = nullptr;
00114 #elif ABSL_THREAD_IDENTITY_MODE == \
00115       ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
00116   // pthread_setspecific expected to clear value on destruction
00117   assert(CurrentThreadIdentityIfPresent() == nullptr);
00118 #endif
00119 }
00120 
00121 #if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
00122 ThreadIdentity* CurrentThreadIdentityIfPresent() {
00123   bool initialized = pthread_key_initialized.load(std::memory_order_acquire);
00124   if (!initialized) {
00125     return nullptr;
00126   }
00127   return reinterpret_cast<ThreadIdentity*>(
00128       pthread_getspecific(thread_identity_pthread_key));
00129 }
00130 #endif
00131 
00132 }  // namespace base_internal
00133 }  // namespace absl


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:42:15