1 | //===-- Implementation of at-fork callback helpers -----------------------===// |
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 "fork_callbacks.h" |
10 | |
11 | #include "src/__support/CPP/mutex.h" // lock_guard |
12 | #include "src/__support/macros/config.h" |
13 | #include "src/__support/threads/mutex.h" |
14 | |
15 | #include <stddef.h> // For size_t |
16 | |
17 | namespace LIBC_NAMESPACE_DECL { |
18 | |
19 | namespace { |
20 | |
21 | struct ForkCallbackTriple { |
22 | ForkCallback *prepare = nullptr; |
23 | ForkCallback *parent = nullptr; |
24 | ForkCallback *child = nullptr; |
25 | constexpr ForkCallbackTriple() = default; |
26 | }; |
27 | |
28 | class AtForkCallbackManager { |
29 | static constexpr size_t CALLBACK_SIZE = 32; |
30 | // TODO: Replace this with block store when integration tests |
31 | // can use allocators. |
32 | ForkCallbackTriple list[CALLBACK_SIZE]; |
33 | Mutex mtx; |
34 | size_t next_index; |
35 | |
36 | public: |
37 | constexpr AtForkCallbackManager() |
38 | : mtx(/*timed=*/false, /*recursive=*/false, /*robust=*/false, |
39 | /*pshared=*/false), |
40 | next_index(0) {} |
41 | |
42 | bool register_triple(const ForkCallbackTriple &triple) { |
43 | cpp::lock_guard lock(mtx); |
44 | if (next_index >= CALLBACK_SIZE) |
45 | return false; |
46 | list[next_index] = triple; |
47 | ++next_index; |
48 | return true; |
49 | } |
50 | |
51 | void invoke_prepare() { |
52 | cpp::lock_guard lock(mtx); |
53 | for (size_t i = 0; i < next_index; ++i) { |
54 | auto prepare = list[i].prepare; |
55 | if (prepare) |
56 | prepare(); |
57 | } |
58 | } |
59 | |
60 | void invoke_parent() { |
61 | cpp::lock_guard lock(mtx); |
62 | for (size_t i = 0; i < next_index; ++i) { |
63 | auto parent = list[i].parent; |
64 | if (parent) |
65 | parent(); |
66 | } |
67 | } |
68 | |
69 | void invoke_child() { |
70 | cpp::lock_guard lock(mtx); |
71 | for (size_t i = 0; i < next_index; ++i) { |
72 | auto child = list[i].child; |
73 | if (child) |
74 | child(); |
75 | } |
76 | } |
77 | }; |
78 | |
79 | AtForkCallbackManager cb_manager; |
80 | |
81 | } // Anonymous namespace |
82 | |
83 | bool register_atfork_callbacks(ForkCallback *prepare_cb, |
84 | ForkCallback *parent_cb, |
85 | ForkCallback *child_cb) { |
86 | return cb_manager.register_triple(triple: {.prepare: prepare_cb, .parent: parent_cb, .child: child_cb}); |
87 | } |
88 | |
89 | void invoke_child_callbacks() { cb_manager.invoke_child(); } |
90 | |
91 | void invoke_prepare_callbacks() { cb_manager.invoke_prepare(); } |
92 | |
93 | void invoke_parent_callbacks() { cb_manager.invoke_parent(); } |
94 | |
95 | } // namespace LIBC_NAMESPACE_DECL |
96 | |