#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