summaryrefslogtreecommitdiff
path: root/libc/src/__support/threads/fork_callbacks.cpp
blob: 7ac4c485b1f07a799b785087cac5fb33eb74244d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
//===-- Implementation of at-fork callback helpers  -----------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "fork_callbacks.h"

#include "src/__support/threads/mutex.h"

#include <stddef.h> // For size_t

namespace __llvm_libc {

namespace {

struct ForkCallbackTriple {
  ForkCallback *prepare = nullptr;
  ForkCallback *parent = nullptr;
  ForkCallback *child = nullptr;
  constexpr ForkCallbackTriple() = default;
};

class AtForkCallbackManager {
  static constexpr size_t CALLBACK_SIZE = 32;
  // TODO: Replace this with block store when integration tests
  // can use allocators.
  ForkCallbackTriple list[CALLBACK_SIZE];
  Mutex mtx;
  size_t next_index;

public:
  constexpr AtForkCallbackManager() : mtx(false, false, false), next_index(0) {}

  bool register_triple(const ForkCallbackTriple &triple) {
    MutexLock lock(&mtx);
    if (next_index >= CALLBACK_SIZE)
      return false;
    list[next_index] = triple;
    ++next_index;
    return true;
  }

  void invoke_prepare() {
    MutexLock lock(&mtx);
    for (size_t i = 0; i < next_index; ++i) {
      auto prepare = list[i].prepare;
      if (prepare)
        prepare();
    }
  }

  void invoke_parent() {
    MutexLock lock(&mtx);
    for (size_t i = 0; i < next_index; ++i) {
      auto parent = list[i].parent;
      if (parent)
        parent();
    }
  }

  void invoke_child() {
    MutexLock lock(&mtx);
    for (size_t i = 0; i < next_index; ++i) {
      auto child = list[i].child;
      if (child)
        child();
    }
  }
};

AtForkCallbackManager cb_manager;

} // Anonymous namespace

bool register_atfork_callbacks(ForkCallback *prepare_cb,
                               ForkCallback *parent_cb,
                               ForkCallback *child_cb) {
  return cb_manager.register_triple({prepare_cb, parent_cb, child_cb});
}

void invoke_child_callbacks() { cb_manager.invoke_child(); }

void invoke_prepare_callbacks() { cb_manager.invoke_prepare(); }

void invoke_parent_callbacks() { cb_manager.invoke_parent(); }

} // namespace __llvm_libc