19c78d925SSiva Chandra Reddy //===--- Definitions of common thread items ---------------------*- C++ -*-===// 29c78d925SSiva Chandra Reddy // 39c78d925SSiva Chandra Reddy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 49c78d925SSiva Chandra Reddy // See https://llvm.org/LICENSE.txt for license information. 59c78d925SSiva Chandra Reddy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 69c78d925SSiva Chandra Reddy // 79c78d925SSiva Chandra Reddy //===----------------------------------------------------------------------===// 89c78d925SSiva Chandra Reddy 9ab3a9e72SSchrodinger ZHU Yifan #include "src/__support/threads/thread.h" 105ff3ff33SPetr Hosek #include "src/__support/macros/config.h" 11ab3a9e72SSchrodinger ZHU Yifan #include "src/__support/threads/mutex.h" 120071a795SSiva Chandra Reddy 134a738ee8SSiva Chandra Reddy #include "src/__support/CPP/array.h" 14c4a3d184SVlad Mishel #include "src/__support/CPP/mutex.h" // lock_guard 154a738ee8SSiva Chandra Reddy #include "src/__support/CPP/optional.h" 160071a795SSiva Chandra Reddy #include "src/__support/fixedvector.h" 17daeee567SSiva Chandra Reddy #include "src/__support/macros/attributes.h" 188dc42802SSiva Chandra Reddy 195ff3ff33SPetr Hosek namespace LIBC_NAMESPACE_DECL { 200071a795SSiva Chandra Reddy namespace { 210071a795SSiva Chandra Reddy 220071a795SSiva Chandra Reddy using AtExitCallback = void(void *); 230071a795SSiva Chandra Reddy 240071a795SSiva Chandra Reddy struct AtExitUnit { 250071a795SSiva Chandra Reddy AtExitCallback *callback = nullptr; 260071a795SSiva Chandra Reddy void *obj = nullptr; 270071a795SSiva Chandra Reddy constexpr AtExitUnit() = default; 280071a795SSiva Chandra Reddy constexpr AtExitUnit(AtExitCallback *cb, void *o) : callback(cb), obj(o) {} 290071a795SSiva Chandra Reddy }; 300071a795SSiva Chandra Reddy 314a738ee8SSiva Chandra Reddy constexpr size_t TSS_KEY_COUNT = 1024; 324a738ee8SSiva Chandra Reddy 334a738ee8SSiva Chandra Reddy struct TSSKeyUnit { 344a738ee8SSiva Chandra Reddy // Indicates whether is unit is active. Presence of a non-null dtor 354a738ee8SSiva Chandra Reddy // is not sufficient to indicate the same information as a TSS key can 364a738ee8SSiva Chandra Reddy // have a null destructor. 374a738ee8SSiva Chandra Reddy bool active = false; 384a738ee8SSiva Chandra Reddy 394a738ee8SSiva Chandra Reddy TSSDtor *dtor = nullptr; 404a738ee8SSiva Chandra Reddy 414a738ee8SSiva Chandra Reddy constexpr TSSKeyUnit() = default; 424a738ee8SSiva Chandra Reddy constexpr TSSKeyUnit(TSSDtor *d) : active(true), dtor(d) {} 434a738ee8SSiva Chandra Reddy 444a738ee8SSiva Chandra Reddy void reset() { 454a738ee8SSiva Chandra Reddy active = false; 464a738ee8SSiva Chandra Reddy dtor = nullptr; 474a738ee8SSiva Chandra Reddy } 484a738ee8SSiva Chandra Reddy }; 494a738ee8SSiva Chandra Reddy 504a738ee8SSiva Chandra Reddy class TSSKeyMgr { 514a738ee8SSiva Chandra Reddy Mutex mtx; 524a738ee8SSiva Chandra Reddy cpp::array<TSSKeyUnit, TSS_KEY_COUNT> units; 534a738ee8SSiva Chandra Reddy 544a738ee8SSiva Chandra Reddy public: 55142afde0SSchrodinger ZHU Yifan constexpr TSSKeyMgr() 56142afde0SSchrodinger ZHU Yifan : mtx(/*timed=*/false, /*recursive=*/false, /*robust=*/false, 57142afde0SSchrodinger ZHU Yifan /*pshared=*/false) {} 584a738ee8SSiva Chandra Reddy 594a738ee8SSiva Chandra Reddy cpp::optional<unsigned int> new_key(TSSDtor *dtor) { 60c4a3d184SVlad Mishel cpp::lock_guard lock(mtx); 61f0a3954eSMichael Jones for (unsigned int i = 0; i < TSS_KEY_COUNT; ++i) { 624a738ee8SSiva Chandra Reddy TSSKeyUnit &u = units[i]; 634a738ee8SSiva Chandra Reddy if (!u.active) { 644a738ee8SSiva Chandra Reddy u = {dtor}; 654a738ee8SSiva Chandra Reddy return i; 664a738ee8SSiva Chandra Reddy } 674a738ee8SSiva Chandra Reddy } 684a738ee8SSiva Chandra Reddy return cpp::optional<unsigned int>(); 694a738ee8SSiva Chandra Reddy } 704a738ee8SSiva Chandra Reddy 714a738ee8SSiva Chandra Reddy TSSDtor *get_dtor(unsigned int key) { 724a738ee8SSiva Chandra Reddy if (key >= TSS_KEY_COUNT) 734a738ee8SSiva Chandra Reddy return nullptr; 74c4a3d184SVlad Mishel cpp::lock_guard lock(mtx); 754a738ee8SSiva Chandra Reddy return units[key].dtor; 764a738ee8SSiva Chandra Reddy } 774a738ee8SSiva Chandra Reddy 784a738ee8SSiva Chandra Reddy bool remove_key(unsigned int key) { 794a738ee8SSiva Chandra Reddy if (key >= TSS_KEY_COUNT) 804a738ee8SSiva Chandra Reddy return false; 81c4a3d184SVlad Mishel cpp::lock_guard lock(mtx); 824a738ee8SSiva Chandra Reddy units[key].reset(); 834a738ee8SSiva Chandra Reddy return true; 844a738ee8SSiva Chandra Reddy } 854a738ee8SSiva Chandra Reddy 864a738ee8SSiva Chandra Reddy bool is_valid_key(unsigned int key) { 87c4a3d184SVlad Mishel cpp::lock_guard lock(mtx); 884a738ee8SSiva Chandra Reddy return units[key].active; 894a738ee8SSiva Chandra Reddy } 904a738ee8SSiva Chandra Reddy }; 914a738ee8SSiva Chandra Reddy 924a738ee8SSiva Chandra Reddy TSSKeyMgr tss_key_mgr; 934a738ee8SSiva Chandra Reddy 944a738ee8SSiva Chandra Reddy struct TSSValueUnit { 954a738ee8SSiva Chandra Reddy bool active = false; 964a738ee8SSiva Chandra Reddy void *payload = nullptr; 974a738ee8SSiva Chandra Reddy TSSDtor *dtor = nullptr; 984a738ee8SSiva Chandra Reddy 994a738ee8SSiva Chandra Reddy constexpr TSSValueUnit() = default; 1004a738ee8SSiva Chandra Reddy constexpr TSSValueUnit(void *p, TSSDtor *d) 1014a738ee8SSiva Chandra Reddy : active(true), payload(p), dtor(d) {} 1024a738ee8SSiva Chandra Reddy }; 1034a738ee8SSiva Chandra Reddy 104daeee567SSiva Chandra Reddy static LIBC_THREAD_LOCAL cpp::array<TSSValueUnit, TSS_KEY_COUNT> tss_values; 1054a738ee8SSiva Chandra Reddy 1060071a795SSiva Chandra Reddy } // anonymous namespace 1070071a795SSiva Chandra Reddy 1080071a795SSiva Chandra Reddy class ThreadAtExitCallbackMgr { 1090071a795SSiva Chandra Reddy Mutex mtx; 1100071a795SSiva Chandra Reddy // TODO: Use a BlockStore when compiled for production. 1110071a795SSiva Chandra Reddy FixedVector<AtExitUnit, 1024> callback_list; 1120071a795SSiva Chandra Reddy 1130071a795SSiva Chandra Reddy public: 114142afde0SSchrodinger ZHU Yifan constexpr ThreadAtExitCallbackMgr() 115142afde0SSchrodinger ZHU Yifan : mtx(/*timed=*/false, /*recursive=*/false, /*robust=*/false, 116142afde0SSchrodinger ZHU Yifan /*pshared=*/false) {} 1170071a795SSiva Chandra Reddy 1180071a795SSiva Chandra Reddy int add_callback(AtExitCallback *callback, void *obj) { 119c4a3d184SVlad Mishel cpp::lock_guard lock(mtx); 120*b30f9d74SAlexey Samsonov if (callback_list.push_back({callback, obj})) 121*b30f9d74SAlexey Samsonov return 0; 122*b30f9d74SAlexey Samsonov return -1; 1230071a795SSiva Chandra Reddy } 1240071a795SSiva Chandra Reddy 1250071a795SSiva Chandra Reddy void call() { 1260071a795SSiva Chandra Reddy mtx.lock(); 1270071a795SSiva Chandra Reddy while (!callback_list.empty()) { 1280071a795SSiva Chandra Reddy auto atexit_unit = callback_list.back(); 1290071a795SSiva Chandra Reddy callback_list.pop_back(); 1300071a795SSiva Chandra Reddy mtx.unlock(); 1310071a795SSiva Chandra Reddy atexit_unit.callback(atexit_unit.obj); 1320071a795SSiva Chandra Reddy mtx.lock(); 1330071a795SSiva Chandra Reddy } 1340071a795SSiva Chandra Reddy } 1350071a795SSiva Chandra Reddy }; 1360071a795SSiva Chandra Reddy 137daeee567SSiva Chandra Reddy static LIBC_THREAD_LOCAL ThreadAtExitCallbackMgr atexit_callback_mgr; 1380071a795SSiva Chandra Reddy 1390071a795SSiva Chandra Reddy // The function __cxa_thread_atexit is provided by C++ runtimes like libcxxabi. 1400071a795SSiva Chandra Reddy // It is used by thread local object runtime to register destructor calls. To 1410071a795SSiva Chandra Reddy // actually register destructor call with the threading library, it calls 1420071a795SSiva Chandra Reddy // __cxa_thread_atexit_impl, which is to be provided by the threading library. 1430071a795SSiva Chandra Reddy // The semantics are very similar to the __cxa_atexit function except for the 1440071a795SSiva Chandra Reddy // fact that the registered callback is thread specific. 1450071a795SSiva Chandra Reddy extern "C" int __cxa_thread_atexit_impl(AtExitCallback *callback, void *obj, 1460071a795SSiva Chandra Reddy void *) { 1470071a795SSiva Chandra Reddy return atexit_callback_mgr.add_callback(callback, obj); 1480071a795SSiva Chandra Reddy } 1490071a795SSiva Chandra Reddy 1500071a795SSiva Chandra Reddy namespace internal { 1510071a795SSiva Chandra Reddy 1520071a795SSiva Chandra Reddy ThreadAtExitCallbackMgr *get_thread_atexit_callback_mgr() { 1530071a795SSiva Chandra Reddy return &atexit_callback_mgr; 1540071a795SSiva Chandra Reddy } 1550071a795SSiva Chandra Reddy 1560071a795SSiva Chandra Reddy void call_atexit_callbacks(ThreadAttributes *attrib) { 1570071a795SSiva Chandra Reddy attrib->atexit_callback_mgr->call(); 1584a738ee8SSiva Chandra Reddy for (size_t i = 0; i < TSS_KEY_COUNT; ++i) { 1594a738ee8SSiva Chandra Reddy TSSValueUnit &unit = tss_values[i]; 1606f1a9ed0SNoah Goldstein // Both dtor and value need to nonnull to call dtor 1616f1a9ed0SNoah Goldstein if (unit.dtor != nullptr && unit.payload != nullptr) 1624a738ee8SSiva Chandra Reddy unit.dtor(unit.payload); 1634a738ee8SSiva Chandra Reddy } 1640071a795SSiva Chandra Reddy } 1650071a795SSiva Chandra Reddy 1660071a795SSiva Chandra Reddy } // namespace internal 1670071a795SSiva Chandra Reddy 1684a738ee8SSiva Chandra Reddy cpp::optional<unsigned int> new_tss_key(TSSDtor *dtor) { 1694a738ee8SSiva Chandra Reddy return tss_key_mgr.new_key(dtor); 1704a738ee8SSiva Chandra Reddy } 1714a738ee8SSiva Chandra Reddy 1724a738ee8SSiva Chandra Reddy bool tss_key_delete(unsigned int key) { return tss_key_mgr.remove_key(key); } 1734a738ee8SSiva Chandra Reddy 1744a738ee8SSiva Chandra Reddy bool set_tss_value(unsigned int key, void *val) { 1754a738ee8SSiva Chandra Reddy if (!tss_key_mgr.is_valid_key(key)) 1764a738ee8SSiva Chandra Reddy return false; 1774a738ee8SSiva Chandra Reddy tss_values[key] = {val, tss_key_mgr.get_dtor(key)}; 1784a738ee8SSiva Chandra Reddy return true; 1794a738ee8SSiva Chandra Reddy } 1804a738ee8SSiva Chandra Reddy 1814a738ee8SSiva Chandra Reddy void *get_tss_value(unsigned int key) { 1824a738ee8SSiva Chandra Reddy if (key >= TSS_KEY_COUNT) 1834a738ee8SSiva Chandra Reddy return nullptr; 1844a738ee8SSiva Chandra Reddy 1854a738ee8SSiva Chandra Reddy auto &u = tss_values[key]; 1864a738ee8SSiva Chandra Reddy if (!u.active) 1874a738ee8SSiva Chandra Reddy return nullptr; 1884a738ee8SSiva Chandra Reddy return u.payload; 1894a738ee8SSiva Chandra Reddy } 1904a738ee8SSiva Chandra Reddy 1915ff3ff33SPetr Hosek } // namespace LIBC_NAMESPACE_DECL 192