Commit 88cc63ef by Andy Getzendanner Committed by Copybara-Service

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
parent c154d20a
...@@ -414,82 +414,24 @@ pid_t GetTID() { ...@@ -414,82 +414,24 @@ pid_t GetTID() {
return tid; return tid;
} }
#else #elif defined(__APPLE__)
// Fallback implementation of GetTID using pthread_getspecific. pid_t GetTID() {
ABSL_CONST_INIT static once_flag tid_once; uint64_t tid;
ABSL_CONST_INIT static pthread_key_t tid_key; // `nullptr` here implies this thread. This only fails if the specified
ABSL_CONST_INIT static absl::base_internal::SpinLock tid_lock( // thread is invalid or the pointer-to-tid is null, so we needn't worry about
absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY); // it.
pthread_threadid_np(nullptr, &tid);
// We set a bit per thread in this array to indicate that an ID is in return static_cast<pid_t>(tid);
// use. ID 0 is unused because it is the default value returned by
// pthread_getspecific().
ABSL_CONST_INIT static std::vector<uint32_t> *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<intptr_t>(v);
intptr_t word = tid / kBitsPerWord;
uint32_t mask = ~(1u << (tid % kBitsPerWord));
absl::base_internal::SpinLockHolder lock(&tid_lock);
assert(0 <= word && static_cast<size_t>(word) < tid_array->size());
(*tid_array)[static_cast<size_t>(word)] &= mask;
} }
static void InitGetTID() { #else
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<uint32_t>(1);
(*tid_array)[0] = 1; // ID 0 is never-allocated.
}
// Return a per-thread small integer ID from pthread's thread-specific data. // Fallback implementation of `GetTID` using `pthread_self`.
pid_t GetTID() { pid_t GetTID() {
absl::call_once(tid_once, InitGetTID); // `pthread_t` need not be arithmetic per POSIX; platforms where it isn't
// should be handled above.
intptr_t tid = reinterpret_cast<intptr_t>(pthread_getspecific(tid_key)); return static_cast<pid_t>(pthread_self());
if (tid != 0) {
return static_cast<pid_t>(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<intptr_t>((word * kBitsPerWord) + static_cast<size_t>(bit));
(*tid_array)[word] |= 1u << bit; // Mark the TID as allocated.
}
if (pthread_setspecific(tid_key, reinterpret_cast<void *>(tid)) != 0) {
perror("pthread_setspecific failed");
abort();
}
return static_cast<pid_t>(tid);
} }
#endif #endif
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment