aboutsummaryrefslogtreecommitdiffstats
path: root/util/system/atexit.cpp
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/system/atexit.cpp
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/system/atexit.cpp')
-rw-r--r--util/system/atexit.cpp136
1 files changed, 136 insertions, 0 deletions
diff --git a/util/system/atexit.cpp b/util/system/atexit.cpp
new file mode 100644
index 0000000000..74fb10b6b1
--- /dev/null
+++ b/util/system/atexit.cpp
@@ -0,0 +1,136 @@
+#include "atexit.h"
+#include "atomic.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 <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_(0)
+ {
+ }
+
+ inline void Finish() noexcept {
+ AtomicSet(FinishStarted_, 1);
+
+ 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 AtomicGet(FinishStarted_);
+ }
+
+ private:
+ TAdaptiveLock Lock_;
+ TAtomic FinishStarted_;
+ TDeque<TFunc> Store_;
+ TPriorityQueue<TFunc*, TVector<TFunc*>, TCmp> Items_;
+ };
+
+ static TAtomic atExitLock = 0;
+ static TAtExit* volatile atExitPtr = nullptr;
+ alignas(TAtExit) static char atExitMem[sizeof(TAtExit)];
+
+ static void OnExit() {
+ if (TAtExit* const atExit = AtomicGet(atExitPtr)) {
+ atExit->Finish();
+ atExit->~TAtExit();
+ AtomicSet(atExitPtr, nullptr);
+ }
+ }
+
+ static inline TAtExit* Instance() {
+ if (TAtExit* const atExit = AtomicGet(atExitPtr)) {
+ return atExit;
+ }
+ with_lock (atExitLock) {
+ if (TAtExit* const atExit = AtomicGet(atExitPtr)) {
+ return atExit;
+ }
+ atexit(OnExit);
+ TAtExit* const atExit = new (atExitMem) TAtExit;
+ AtomicSet(atExitPtr, atExit);
+ return atExit;
+ }
+ }
+}
+
+void ManualRunAtExitFinalizers() {
+ OnExit();
+}
+
+bool ExitStarted() {
+ if (TAtExit* const atExit = AtomicGet(atExitPtr)) {
+ 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);
+}