From 88cc63ef739d83277b492e881be72e9069fcb1fe Mon Sep 17 00:00:00 2001 From: Andy Getzendanner Date: Thu, 25 May 2023 11:32:01 -0700 Subject: Implement a better GetTID on Apple platforms, and a better fallback too. The fallback isn't totally portable, even within POSIX, but we can special case any future platforms where it's not just like this change does for Apple. PiperOrigin-RevId: 535324103 Change-Id: Ib628925c4946b6c112373678fe37e9bb44259090 --- absl/base/internal/sysinfo.cc | 84 +++++++------------------------------------ 1 file changed, 13 insertions(+), 71 deletions(-) diff --git a/absl/base/internal/sysinfo.cc b/absl/base/internal/sysinfo.cc index 8429fb90..ed203355 100644 --- a/absl/base/internal/sysinfo.cc +++ b/absl/base/internal/sysinfo.cc @@ -414,82 +414,24 @@ pid_t GetTID() { return tid; } -#else +#elif defined(__APPLE__) -// Fallback implementation of GetTID using pthread_getspecific. -ABSL_CONST_INIT static once_flag tid_once; -ABSL_CONST_INIT static pthread_key_t tid_key; -ABSL_CONST_INIT static absl::base_internal::SpinLock tid_lock( - absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY); - -// We set a bit per thread in this array to indicate that an ID is in -// use. ID 0 is unused because it is the default value returned by -// pthread_getspecific(). -ABSL_CONST_INIT static std::vector *tid_array - ABSL_GUARDED_BY(tid_lock) = nullptr; -static constexpr int kBitsPerWord = 32; // tid_array is uint32_t. - -// Returns the TID to tid_array. -static void FreeTID(void *v) { - intptr_t tid = reinterpret_cast(v); - intptr_t word = tid / kBitsPerWord; - uint32_t mask = ~(1u << (tid % kBitsPerWord)); - absl::base_internal::SpinLockHolder lock(&tid_lock); - assert(0 <= word && static_cast(word) < tid_array->size()); - (*tid_array)[static_cast(word)] &= mask; +pid_t GetTID() { + uint64_t tid; + // `nullptr` here implies this thread. This only fails if the specified + // thread is invalid or the pointer-to-tid is null, so we needn't worry about + // it. + pthread_threadid_np(nullptr, &tid); + return static_cast(tid); } -static void InitGetTID() { - if (pthread_key_create(&tid_key, FreeTID) != 0) { - // The logging system calls GetTID() so it can't be used here. - perror("pthread_key_create failed"); - abort(); - } - - // Initialize tid_array. - absl::base_internal::SpinLockHolder lock(&tid_lock); - tid_array = new std::vector(1); - (*tid_array)[0] = 1; // ID 0 is never-allocated. -} +#else -// Return a per-thread small integer ID from pthread's thread-specific data. +// Fallback implementation of `GetTID` using `pthread_self`. pid_t GetTID() { - absl::call_once(tid_once, InitGetTID); - - intptr_t tid = reinterpret_cast(pthread_getspecific(tid_key)); - if (tid != 0) { - return static_cast(tid); - } - - int bit; // tid_array[word] = 1u << bit; - size_t word; - { - // Search for the first unused ID. - absl::base_internal::SpinLockHolder lock(&tid_lock); - // First search for a word in the array that is not all ones. - word = 0; - while (word < tid_array->size() && ~(*tid_array)[word] == 0) { - ++word; - } - if (word == tid_array->size()) { - tid_array->push_back(0); // No space left, add kBitsPerWord more IDs. - } - // Search for a zero bit in the word. - bit = 0; - while (bit < kBitsPerWord && (((*tid_array)[word] >> bit) & 1) != 0) { - ++bit; - } - tid = - static_cast((word * kBitsPerWord) + static_cast(bit)); - (*tid_array)[word] |= 1u << bit; // Mark the TID as allocated. - } - - if (pthread_setspecific(tid_key, reinterpret_cast(tid)) != 0) { - perror("pthread_setspecific failed"); - abort(); - } - - return static_cast(tid); + // `pthread_t` need not be arithmetic per POSIX; platforms where it isn't + // should be handled above. + return static_cast(pthread_self()); } #endif -- cgit v1.2.3