xref: /llvm-project/libc/src/stdlib/exit_handler.h (revision 508398021d094ecfe6cea937d619c77121990e0d)
139d38d66Saaryanshukla //===-- Implementation header for exit_handler ------------------*- C++ -*-===//
239d38d66Saaryanshukla //
339d38d66Saaryanshukla // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
439d38d66Saaryanshukla // See https://llvm.org/LICENSE.txt for license information.
539d38d66Saaryanshukla // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
639d38d66Saaryanshukla //
739d38d66Saaryanshukla //===----------------------------------------------------------------------===//
839d38d66Saaryanshukla 
939d38d66Saaryanshukla #ifndef LLVM_LIBC_SRC_STDLIB_EXIT_HANDLER_H
1039d38d66Saaryanshukla #define LLVM_LIBC_SRC_STDLIB_EXIT_HANDLER_H
1139d38d66Saaryanshukla 
1239d38d66Saaryanshukla #include "src/__support/CPP/mutex.h" // lock_guard
1339d38d66Saaryanshukla #include "src/__support/blockstore.h"
1439d38d66Saaryanshukla #include "src/__support/common.h"
1539d38d66Saaryanshukla #include "src/__support/fixedvector.h"
165ff3ff33SPetr Hosek #include "src/__support/macros/config.h"
1739d38d66Saaryanshukla #include "src/__support/threads/mutex.h"
1839d38d66Saaryanshukla 
195ff3ff33SPetr Hosek namespace LIBC_NAMESPACE_DECL {
2039d38d66Saaryanshukla 
2139d38d66Saaryanshukla using AtExitCallback = void(void *);
2239d38d66Saaryanshukla using StdCAtExitCallback = void(void);
2339d38d66Saaryanshukla constexpr size_t CALLBACK_LIST_SIZE_FOR_TESTS = 1024;
2439d38d66Saaryanshukla 
2539d38d66Saaryanshukla struct AtExitUnit {
2639d38d66Saaryanshukla   AtExitCallback *callback = nullptr;
2739d38d66Saaryanshukla   void *payload = nullptr;
2839d38d66Saaryanshukla   LIBC_INLINE constexpr AtExitUnit() = default;
2939d38d66Saaryanshukla   LIBC_INLINE constexpr AtExitUnit(AtExitCallback *c, void *p)
3039d38d66Saaryanshukla       : callback(c), payload(p) {}
3139d38d66Saaryanshukla };
3239d38d66Saaryanshukla 
3339d38d66Saaryanshukla #if defined(LIBC_TARGET_ARCH_IS_GPU)
3439d38d66Saaryanshukla using ExitCallbackList = FixedVector<AtExitUnit, 64>;
3539d38d66Saaryanshukla #elif defined(LIBC_COPT_PUBLIC_PACKAGING)
3639d38d66Saaryanshukla using ExitCallbackList = ReverseOrderBlockStore<AtExitUnit, 32>;
3739d38d66Saaryanshukla #else
3839d38d66Saaryanshukla using ExitCallbackList = FixedVector<AtExitUnit, CALLBACK_LIST_SIZE_FOR_TESTS>;
3939d38d66Saaryanshukla #endif
4039d38d66Saaryanshukla 
41aac3a2a2SJoseph Huber // This is handled by the 'atexit' implementation and shared by 'at_quick_exit'.
4239d38d66Saaryanshukla extern Mutex handler_list_mtx;
4339d38d66Saaryanshukla 
44aac3a2a2SJoseph Huber LIBC_INLINE void stdc_at_exit_func(void *payload) {
45aac3a2a2SJoseph Huber   reinterpret_cast<StdCAtExitCallback *>(payload)();
46aac3a2a2SJoseph Huber }
4739d38d66Saaryanshukla 
48aac3a2a2SJoseph Huber LIBC_INLINE void call_exit_callbacks(ExitCallbackList &callbacks) {
49aac3a2a2SJoseph Huber   handler_list_mtx.lock();
50aac3a2a2SJoseph Huber   while (!callbacks.empty()) {
51*50839802SAlexey Samsonov     AtExitUnit unit = callbacks.back();
52aac3a2a2SJoseph Huber     callbacks.pop_back();
53aac3a2a2SJoseph Huber     handler_list_mtx.unlock();
54aac3a2a2SJoseph Huber     unit.callback(unit.payload);
55aac3a2a2SJoseph Huber     handler_list_mtx.lock();
56aac3a2a2SJoseph Huber   }
57aac3a2a2SJoseph Huber   ExitCallbackList::destroy(&callbacks);
58aac3a2a2SJoseph Huber }
5939d38d66Saaryanshukla 
60aac3a2a2SJoseph Huber LIBC_INLINE int add_atexit_unit(ExitCallbackList &callbacks,
61aac3a2a2SJoseph Huber                                 const AtExitUnit &unit) {
62aac3a2a2SJoseph Huber   cpp::lock_guard lock(handler_list_mtx);
63aac3a2a2SJoseph Huber   if (callbacks.push_back(unit))
64aac3a2a2SJoseph Huber     return 0;
65aac3a2a2SJoseph Huber   return -1;
66aac3a2a2SJoseph Huber }
6739d38d66Saaryanshukla 
685ff3ff33SPetr Hosek } // namespace LIBC_NAMESPACE_DECL
6939d38d66Saaryanshukla 
7039d38d66Saaryanshukla #endif // LLVM_LIBC_SRC_STDLIB_EXIT_HANDLER_H
71