| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #include <stdint.h> |
|
|
| #include <new> |
|
|
| |
| #include "absl/base/internal/low_level_alloc.h" |
| #include "absl/synchronization/internal/waiter.h" |
| #ifndef ABSL_LOW_LEVEL_ALLOC_MISSING |
|
|
| #include <string.h> |
|
|
| #include "absl/base/attributes.h" |
| #include "absl/base/internal/spinlock.h" |
| #include "absl/base/internal/thread_identity.h" |
| #include "absl/synchronization/internal/per_thread_sem.h" |
|
|
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace synchronization_internal { |
|
|
| |
| |
| ABSL_CONST_INIT static base_internal::SpinLock freelist_lock( |
| absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY); |
| ABSL_CONST_INIT static base_internal::ThreadIdentity* thread_identity_freelist; |
|
|
| |
| |
| static void ReclaimThreadIdentity(void* v) { |
| base_internal::ThreadIdentity* identity = |
| static_cast<base_internal::ThreadIdentity*>(v); |
|
|
| |
| |
| if (identity->per_thread_synch.all_locks != nullptr) { |
| base_internal::LowLevelAlloc::Free(identity->per_thread_synch.all_locks); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| base_internal::ClearCurrentThreadIdentity(); |
| { |
| base_internal::SpinLockHolder l(&freelist_lock); |
| identity->next = thread_identity_freelist; |
| thread_identity_freelist = identity; |
| } |
| } |
|
|
| |
| |
| static intptr_t RoundUp(intptr_t addr, intptr_t align) { |
| return (addr + align - 1) & ~(align - 1); |
| } |
|
|
| void OneTimeInitThreadIdentity(base_internal::ThreadIdentity* identity) { |
| PerThreadSem::Init(identity); |
| identity->ticker.store(0, std::memory_order_relaxed); |
| identity->wait_start.store(0, std::memory_order_relaxed); |
| identity->is_idle.store(false, std::memory_order_relaxed); |
| } |
|
|
| static void ResetThreadIdentityBetweenReuse( |
| base_internal::ThreadIdentity* identity) { |
| base_internal::PerThreadSynch* pts = &identity->per_thread_synch; |
| pts->next = nullptr; |
| pts->skip = nullptr; |
| pts->may_skip = false; |
| pts->waitp = nullptr; |
| pts->suppress_fatal_errors = false; |
| pts->readers = 0; |
| pts->priority = 0; |
| pts->next_priority_read_cycles = 0; |
| pts->state.store(base_internal::PerThreadSynch::State::kAvailable, |
| std::memory_order_relaxed); |
| pts->maybe_unlocking = false; |
| pts->wake = false; |
| pts->cond_waiter = false; |
| pts->all_locks = nullptr; |
| identity->blocked_count_ptr = nullptr; |
| identity->ticker.store(0, std::memory_order_relaxed); |
| identity->wait_start.store(0, std::memory_order_relaxed); |
| identity->is_idle.store(false, std::memory_order_relaxed); |
| identity->next = nullptr; |
| } |
|
|
| static base_internal::ThreadIdentity* NewThreadIdentity() { |
| base_internal::ThreadIdentity* identity = nullptr; |
|
|
| { |
| |
| base_internal::SpinLockHolder l(&freelist_lock); |
| if (thread_identity_freelist) { |
| identity = thread_identity_freelist; |
| thread_identity_freelist = thread_identity_freelist->next; |
| } |
| } |
|
|
| if (identity == nullptr) { |
| |
| |
| |
| void* allocation = base_internal::LowLevelAlloc::Alloc( |
| sizeof(*identity) + base_internal::PerThreadSynch::kAlignment - 1); |
| |
| identity = reinterpret_cast<base_internal::ThreadIdentity*>( |
| RoundUp(reinterpret_cast<intptr_t>(allocation), |
| base_internal::PerThreadSynch::kAlignment)); |
| OneTimeInitThreadIdentity(identity); |
| } |
| ResetThreadIdentityBetweenReuse(identity); |
|
|
| return identity; |
| } |
|
|
| |
| |
| |
| base_internal::ThreadIdentity* CreateThreadIdentity() { |
| base_internal::ThreadIdentity* identity = NewThreadIdentity(); |
| |
| base_internal::SetCurrentThreadIdentity(identity, ReclaimThreadIdentity); |
| return identity; |
| } |
|
|
| } |
| ABSL_NAMESPACE_END |
| } |
|
|
| #endif |
|
|