#include "src/__support/threads/thread.h"
#include "src/__support/macros/config.h"
#include "src/__support/threads/mutex.h"
#include "src/__support/CPP/array.h"
#include "src/__support/CPP/mutex.h"
#include "src/__support/CPP/optional.h"
#include "src/__support/fixedvector.h"
#include "src/__support/macros/attributes.h"
namespace LIBC_NAMESPACE_DECL {
LIBC_THREAD_LOCAL Thread self;
namespace {
using AtExitCallback = void(void *);
struct AtExitUnit {
AtExitCallback *callback = nullptr;
void *obj = nullptr;
constexpr AtExitUnit() = default;
constexpr AtExitUnit(AtExitCallback *cb, void *o) : callback(cb), obj(o) {}
};
constexpr size_t TSS_KEY_COUNT = 1024;
struct TSSKeyUnit {
bool active = false;
TSSDtor *dtor = nullptr;
constexpr TSSKeyUnit() = default;
constexpr TSSKeyUnit(TSSDtor *d) : active(true), dtor(d) {}
void reset() {
active = false;
dtor = nullptr;
}
};
class TSSKeyMgr {
Mutex mtx;
cpp::array<TSSKeyUnit, TSS_KEY_COUNT> units;
public:
constexpr TSSKeyMgr()
: mtx(/*timed=*/false, false, false,
false) {}
cpp::optional<unsigned int> new_key(TSSDtor *dtor) {
cpp::lock_guard lock(mtx);
for (unsigned int i = 0; i < TSS_KEY_COUNT; ++i) {
TSSKeyUnit &u = units[i];
if (!u.active) {
u = {dtor};
return i;
}
}
return cpp::optional<unsigned int>();
}
TSSDtor *get_dtor(unsigned int key) {
if (key >= TSS_KEY_COUNT)
return nullptr;
cpp::lock_guard lock(mtx);
return units[key].dtor;
}
bool remove_key(unsigned int key) {
if (key >= TSS_KEY_COUNT)
return false;
cpp::lock_guard lock(mtx);
units[key].reset();
return true;
}
bool is_valid_key(unsigned int key) {
cpp::lock_guard lock(mtx);
return units[key].active;
}
};
TSSKeyMgr tss_key_mgr;
struct TSSValueUnit {
bool active = false;
void *payload = nullptr;
TSSDtor *dtor = nullptr;
constexpr TSSValueUnit() = default;
constexpr TSSValueUnit(void *p, TSSDtor *d)
: active(true), payload(p), dtor(d) {}
};
static LIBC_THREAD_LOCAL cpp::array<TSSValueUnit, TSS_KEY_COUNT> tss_values;
}
class ThreadAtExitCallbackMgr {
Mutex mtx;
FixedVector<AtExitUnit, 1024> callback_list;
public:
constexpr ThreadAtExitCallbackMgr()
: mtx(/*timed=*/false, false, false,
false) {}
int add_callback(AtExitCallback *callback, void *obj) {
cpp::lock_guard lock(mtx);
return callback_list.push_back({callback, obj});
}
void call() {
mtx.lock();
while (!callback_list.empty()) {
auto atexit_unit = callback_list.back();
callback_list.pop_back();
mtx.unlock();
atexit_unit.callback(atexit_unit.obj);
mtx.lock();
}
}
};
static LIBC_THREAD_LOCAL ThreadAtExitCallbackMgr atexit_callback_mgr;
extern "C" int __cxa_thread_atexit_impl(AtExitCallback *callback, void *obj,
void *) {
return atexit_callback_mgr.add_callback(callback, obj);
}
namespace internal {
ThreadAtExitCallbackMgr *get_thread_atexit_callback_mgr() {
return &atexit_callback_mgr;
}
void call_atexit_callbacks(ThreadAttributes *attrib) {
attrib->atexit_callback_mgr->call();
for (size_t i = 0; i < TSS_KEY_COUNT; ++i) {
TSSValueUnit &unit = tss_values[i];
if (unit.dtor != nullptr && unit.payload != nullptr)
unit.dtor(unit.payload);
}
}
}
cpp::optional<unsigned int> new_tss_key(TSSDtor *dtor) {
return tss_key_mgr.new_key(dtor);
}
bool tss_key_delete(unsigned int key) { return tss_key_mgr.remove_key(key); }
bool set_tss_value(unsigned int key, void *val) {
if (!tss_key_mgr.is_valid_key(key))
return false;
tss_values[key] = {val, tss_key_mgr.get_dtor(key)};
return true;
}
void *get_tss_value(unsigned int key) {
if (key >= TSS_KEY_COUNT)
return nullptr;
auto &u = tss_values[key];
if (!u.active)
return nullptr;
return u.payload;
}
}