1 //===-- Implementation of atexit ------------------------------------------===//
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "src/stdlib/atexit.h"
10 #include "src/__support/CPP/vector.h"
11 #include "src/__support/common.h"
12 #include "src/threads/mtx_init.h"
13 #include "src/threads/mtx_lock.h"
14 #include "src/threads/mtx_unlock.h"
15 
16 namespace __llvm_libc {
17 
18 namespace {
19 
20 mtx_t lock;
21 // TODO need an easier way to use mtx_t internally, or use pthread_mutex_t
22 // with PTHREAD_MUTEX_INITIALIZER when it lands.
23 struct Init {
24   Init() { __llvm_libc::mtx_init(&lock, mtx_plain); }
25 } init;
26 
27 // TOOD should we make cpp::vector like llvm::SmallVector<T, N> where it will
28 // allocate at least N before needing dynamic allocation?
29 static cpp::vector<void (*)(void)> handlers;
30 
31 } // namespace
32 
33 namespace internal {
34 
35 void call_exit_handlers() {
36   __llvm_libc::mtx_lock(&lock);
37   // TODO: implement rbegin() + rend() for cpp::vector
38   for (int i = handlers.size() - 1; i >= 0; i--) {
39     __llvm_libc::mtx_unlock(&lock);
40     handlers[i]();
41     __llvm_libc::mtx_lock(&lock);
42   }
43 }
44 
45 } // namespace internal
46 
47 LLVM_LIBC_FUNCTION(int, atexit, (void (*function)())) {
48   __llvm_libc::mtx_lock(&lock);
49   handlers.push_back(function);
50   __llvm_libc::mtx_unlock(&lock);
51   return 0;
52 }
53 
54 } // namespace __llvm_libc
55