123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- #include "atexit.h"
- #include "yassert.h"
- #include "spinlock.h"
- #include "thread.h"
- #include <util/generic/ylimits.h>
- #include <util/generic/utility.h>
- #include <util/generic/deque.h>
- #include <util/generic/queue.h>
- #include <atomic>
- #include <tuple>
- #include <cstdlib>
- namespace {
- class TAtExit {
- struct TFunc {
- TAtExitFunc Func;
- void* Ctx;
- size_t Priority;
- size_t Number;
- };
- struct TCmp {
- inline bool operator()(const TFunc* l, const TFunc* r) const noexcept {
- return std::tie(l->Priority, l->Number) < std::tie(r->Priority, r->Number);
- }
- };
- public:
- inline TAtExit() noexcept
- : FinishStarted_(false)
- {
- }
- inline void Finish() noexcept {
- FinishStarted_.store(true);
- if (ExitHandlersDisabled_.load()) {
- return;
- }
- auto guard = Guard(Lock_);
- while (Items_) {
- auto c = Items_.top();
- Y_ASSERT(c);
- Items_.pop();
- {
- auto unguard = Unguard(guard);
- try {
- c->Func(c->Ctx);
- } catch (...) {
- // ¯\_(ツ)_/¯
- }
- }
- }
- }
- inline void Register(TAtExitFunc func, void* ctx, size_t priority) {
- with_lock (Lock_) {
- Store_.push_back({func, ctx, priority, Store_.size()});
- Items_.push(&Store_.back());
- }
- }
- inline bool FinishStarted() const {
- return FinishStarted_.load();
- }
- inline void DisableExitHandlers() {
- ExitHandlersDisabled_.store(true);
- }
- private:
- TAdaptiveLock Lock_;
- std::atomic<bool> FinishStarted_;
- TDeque<TFunc> Store_;
- TPriorityQueue<TFunc*, TVector<TFunc*>, TCmp> Items_;
- std::atomic<bool> ExitHandlersDisabled_{false};
- };
- static TAdaptiveLock atExitLock;
- static std::atomic<TAtExit*> atExitPtr = nullptr;
- alignas(TAtExit) static char atExitMem[sizeof(TAtExit)];
- static void OnExit() {
- if (TAtExit* const atExit = atExitPtr.load()) {
- atExit->Finish();
- atExit->~TAtExit();
- atExitPtr.store(nullptr);
- }
- }
- static inline TAtExit* Instance() {
- if (TAtExit* const atExit = atExitPtr.load(std::memory_order_acquire)) {
- return atExit;
- }
- with_lock (atExitLock) {
- if (TAtExit* const atExit = atExitPtr.load()) {
- return atExit;
- }
- atexit(OnExit);
- TAtExit* const atExit = new (atExitMem) TAtExit;
- atExitPtr.store(atExit, std::memory_order_release);
- return atExit;
- }
- }
- } // namespace
- void ManualRunAtExitFinalizers() {
- OnExit();
- }
- bool ExitStarted() {
- if (TAtExit* const atExit = atExitPtr.load(std::memory_order_acquire)) {
- return atExit->FinishStarted();
- }
- return false;
- }
- void AtExit(TAtExitFunc func, void* ctx, size_t priority) {
- Instance()->Register(func, ctx, priority);
- }
- void AtExit(TAtExitFunc func, void* ctx) {
- AtExit(func, ctx, Max<size_t>());
- }
- static void TraditionalCloser(void* ctx) {
- reinterpret_cast<TTraditionalAtExitFunc>(ctx)();
- }
- void AtExit(TTraditionalAtExitFunc func) {
- AtExit(TraditionalCloser, reinterpret_cast<void*>(func));
- }
- void AtExit(TTraditionalAtExitFunc func, size_t priority) {
- AtExit(TraditionalCloser, reinterpret_cast<void*>(func), priority);
- }
- void DisableExitHandlers() {
- Instance()->DisableExitHandlers();
- }
|