brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.2 KiB · 9618d78 Raw
194 lines · cpp
1//===--- Definitions of common thread items ---------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "src/__support/threads/thread.h"10#include "src/__support/macros/config.h"11#include "src/__support/threads/mutex.h"12 13#include "src/__support/CPP/array.h"14#include "src/__support/CPP/mutex.h" // lock_guard15#include "src/__support/CPP/optional.h"16#include "src/__support/fixedvector.h"17#include "src/__support/macros/attributes.h"18 19namespace LIBC_NAMESPACE_DECL {20namespace {21 22using AtExitCallback = void(void *);23 24struct AtExitUnit {25  AtExitCallback *callback = nullptr;26  void *obj = nullptr;27  constexpr AtExitUnit() = default;28  constexpr AtExitUnit(AtExitCallback *cb, void *o) : callback(cb), obj(o) {}29};30 31constexpr size_t TSS_KEY_COUNT = 1024;32 33struct TSSKeyUnit {34  // Indicates whether is unit is active. Presence of a non-null dtor35  // is not sufficient to indicate the same information as a TSS key can36  // have a null destructor.37  bool active = false;38 39  TSSDtor *dtor = nullptr;40 41  constexpr TSSKeyUnit() = default;42  constexpr TSSKeyUnit(TSSDtor *d) : active(true), dtor(d) {}43 44  void reset() {45    active = false;46    dtor = nullptr;47  }48};49 50class TSSKeyMgr {51  Mutex mtx;52  cpp::array<TSSKeyUnit, TSS_KEY_COUNT> units;53 54public:55  constexpr TSSKeyMgr()56      : mtx(/*timed=*/false, /*recursive=*/false, /*robust=*/false,57            /*pshared=*/false) {}58 59  cpp::optional<unsigned int> new_key(TSSDtor *dtor) {60    cpp::lock_guard lock(mtx);61    for (unsigned int i = 0; i < TSS_KEY_COUNT; ++i) {62      TSSKeyUnit &u = units[i];63      if (!u.active) {64        u = {dtor};65        return i;66      }67    }68    return cpp::optional<unsigned int>();69  }70 71  TSSDtor *get_dtor(unsigned int key) {72    if (key >= TSS_KEY_COUNT)73      return nullptr;74    cpp::lock_guard lock(mtx);75    return units[key].dtor;76  }77 78  bool remove_key(unsigned int key) {79    if (key >= TSS_KEY_COUNT)80      return false;81    cpp::lock_guard lock(mtx);82    units[key].reset();83    return true;84  }85 86  bool is_valid_key(unsigned int key) {87    cpp::lock_guard lock(mtx);88    return units[key].active;89  }90};91 92TSSKeyMgr tss_key_mgr;93 94struct TSSValueUnit {95  bool active = false;96  void *payload = nullptr;97  TSSDtor *dtor = nullptr;98 99  constexpr TSSValueUnit() = default;100  constexpr TSSValueUnit(void *p, TSSDtor *d)101      : active(true), payload(p), dtor(d) {}102};103 104static LIBC_THREAD_LOCAL cpp::array<TSSValueUnit, TSS_KEY_COUNT> tss_values;105 106} // anonymous namespace107 108class ThreadAtExitCallbackMgr {109  Mutex mtx;110  // TODO: Use a BlockStore when compiled for production.111  FixedVector<AtExitUnit, 1024> callback_list;112 113public:114  constexpr ThreadAtExitCallbackMgr()115      : mtx(/*timed=*/false, /*recursive=*/false, /*robust=*/false,116            /*pshared=*/false) {}117 118  int add_callback(AtExitCallback *callback, void *obj) {119    cpp::lock_guard lock(mtx);120    if (callback_list.push_back({callback, obj}))121      return 0;122    return -1;123  }124 125  void call() {126    mtx.lock();127    while (!callback_list.empty()) {128      auto atexit_unit = callback_list.back();129      callback_list.pop_back();130      mtx.unlock();131      atexit_unit.callback(atexit_unit.obj);132      mtx.lock();133    }134  }135};136 137static LIBC_THREAD_LOCAL ThreadAtExitCallbackMgr atexit_callback_mgr;138 139// The function __cxa_thread_atexit is provided by C++ runtimes like libcxxabi.140// It is used by thread local object runtime to register destructor calls. To141// actually register destructor call with the threading library, it calls142// __cxa_thread_atexit_impl, which is to be provided by the threading library.143// The semantics are very similar to the __cxa_atexit function except for the144// fact that the registered callback is thread specific.145extern "C" int __cxa_thread_atexit_impl(AtExitCallback *callback, void *obj,146                                        void *) {147  return atexit_callback_mgr.add_callback(callback, obj);148}149 150namespace internal {151 152ThreadAtExitCallbackMgr *get_thread_atexit_callback_mgr() {153  return &atexit_callback_mgr;154}155 156void call_atexit_callbacks(ThreadAttributes *attrib) {157  attrib->atexit_callback_mgr->call();158  for (size_t i = 0; i < TSS_KEY_COUNT; ++i) {159    TSSValueUnit &unit = tss_values[i];160    // Both dtor and value need to nonnull to call dtor161    if (unit.dtor != nullptr && unit.payload != nullptr)162      unit.dtor(unit.payload);163  }164}165 166extern "C" void __cxa_thread_finalize() { call_atexit_callbacks(self.attrib); }167 168} // namespace internal169 170cpp::optional<unsigned int> new_tss_key(TSSDtor *dtor) {171  return tss_key_mgr.new_key(dtor);172}173 174bool tss_key_delete(unsigned int key) { return tss_key_mgr.remove_key(key); }175 176bool set_tss_value(unsigned int key, void *val) {177  if (!tss_key_mgr.is_valid_key(key))178    return false;179  tss_values[key] = {val, tss_key_mgr.get_dtor(key)};180  return true;181}182 183void *get_tss_value(unsigned int key) {184  if (key >= TSS_KEY_COUNT)185    return nullptr;186 187  auto &u = tss_values[key];188  if (!u.active)189    return nullptr;190  return u.payload;191}192 193} // namespace LIBC_NAMESPACE_DECL194