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({prepare_cb, parent_cb, 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