1 // Copyright 2022 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/core/lib/event_engine/forkable.h"
16
17 #include <grpc/support/port_platform.h>
18
19 #include "absl/log/check.h"
20
21 #ifdef GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK
22 #include <pthread.h>
23 #endif
24
25 #include <algorithm>
26 #include <utility>
27 #include <vector>
28
29 #include "src/core/config/config_vars.h"
30 #include "src/core/lib/debug/trace.h"
31
32 namespace grpc_event_engine {
33 namespace experimental {
34
35 namespace {
IsForkEnabled()36 bool IsForkEnabled() {
37 static bool enabled = grpc_core::ConfigVars::Get().EnableForkSupport();
38 return enabled;
39 }
40 } // namespace
41
RegisterForkable(std::shared_ptr<Forkable> forkable,GRPC_UNUSED void (* prepare)(void),GRPC_UNUSED void (* parent)(void),GRPC_UNUSED void (* child)(void))42 void ObjectGroupForkHandler::RegisterForkable(
43 std::shared_ptr<Forkable> forkable, GRPC_UNUSED void (*prepare)(void),
44 GRPC_UNUSED void (*parent)(void), GRPC_UNUSED void (*child)(void)) {
45 if (IsForkEnabled()) {
46 CHECK(!is_forking_);
47 forkables_.emplace_back(forkable);
48 #ifdef GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK
49 if (!std::exchange(registered_, true)) {
50 pthread_atfork(prepare, parent, child);
51 }
52 #endif // GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK
53 }
54 }
55
Prefork()56 void ObjectGroupForkHandler::Prefork() {
57 if (IsForkEnabled()) {
58 CHECK(!std::exchange(is_forking_, true));
59 GRPC_TRACE_LOG(fork, INFO) << "PrepareFork";
60 for (auto it = forkables_.begin(); it != forkables_.end();) {
61 auto shared = it->lock();
62 if (shared) {
63 shared->PrepareFork();
64 ++it;
65 } else {
66 it = forkables_.erase(it);
67 }
68 }
69 }
70 }
71
PostforkParent()72 void ObjectGroupForkHandler::PostforkParent() {
73 if (IsForkEnabled()) {
74 CHECK(is_forking_);
75 GRPC_TRACE_LOG(fork, INFO) << "PostforkParent";
76 for (auto it = forkables_.begin(); it != forkables_.end();) {
77 auto shared = it->lock();
78 if (shared) {
79 shared->PostforkParent();
80 ++it;
81 } else {
82 it = forkables_.erase(it);
83 }
84 }
85 is_forking_ = false;
86 }
87 }
88
PostforkChild()89 void ObjectGroupForkHandler::PostforkChild() {
90 if (IsForkEnabled()) {
91 CHECK(is_forking_);
92 GRPC_TRACE_LOG(fork, INFO) << "PostforkChild";
93 for (auto it = forkables_.begin(); it != forkables_.end();) {
94 auto shared = it->lock();
95 if (shared) {
96 shared->PostforkChild();
97 ++it;
98 } else {
99 it = forkables_.erase(it);
100 }
101 }
102 is_forking_ = false;
103 }
104 }
105
106 } // namespace experimental
107 } // namespace grpc_event_engine
108