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