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 <grpc/support/port_platform.h>
16
17 #include "src/core/lib/event_engine/forkable.h"
18
19 #include <grpc/support/log.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/lib/config/config_vars.h"
30
31 namespace grpc_event_engine {
32 namespace experimental {
33
34 grpc_core::TraceFlag grpc_trace_fork(false, "fork");
35
36 namespace {
IsForkEnabled()37 bool IsForkEnabled() {
38 static bool enabled = grpc_core::ConfigVars::Get().EnableForkSupport();
39 return enabled;
40 }
41 } // namespace
42
RegisterForkable(std::shared_ptr<Forkable> forkable,GRPC_UNUSED void (* prepare)(void),GRPC_UNUSED void (* parent)(void),GRPC_UNUSED void (* child)(void))43 void ObjectGroupForkHandler::RegisterForkable(
44 std::shared_ptr<Forkable> forkable, GRPC_UNUSED void (*prepare)(void),
45 GRPC_UNUSED void (*parent)(void), GRPC_UNUSED void (*child)(void)) {
46 if (IsForkEnabled()) {
47 GPR_ASSERT(!is_forking_);
48 forkables_.emplace_back(forkable);
49 #ifdef GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK
50 if (!std::exchange(registered_, true)) {
51 pthread_atfork(prepare, parent, child);
52 }
53 #endif // GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK
54 }
55 }
56
Prefork()57 void ObjectGroupForkHandler::Prefork() {
58 if (IsForkEnabled()) {
59 GPR_ASSERT(!std::exchange(is_forking_, true));
60 GRPC_FORK_TRACE_LOG_STRING("PrepareFork");
61 for (auto it = forkables_.begin(); it != forkables_.end();) {
62 auto shared = it->lock();
63 if (shared) {
64 shared->PrepareFork();
65 ++it;
66 } else {
67 it = forkables_.erase(it);
68 }
69 }
70 }
71 }
72
PostforkParent()73 void ObjectGroupForkHandler::PostforkParent() {
74 if (IsForkEnabled()) {
75 GPR_ASSERT(is_forking_);
76 GRPC_FORK_TRACE_LOG_STRING("PostforkParent");
77 for (auto it = forkables_.begin(); it != forkables_.end();) {
78 auto shared = it->lock();
79 if (shared) {
80 shared->PostforkParent();
81 ++it;
82 } else {
83 it = forkables_.erase(it);
84 }
85 }
86 is_forking_ = false;
87 }
88 }
89
PostforkChild()90 void ObjectGroupForkHandler::PostforkChild() {
91 if (IsForkEnabled()) {
92 GPR_ASSERT(is_forking_);
93 GRPC_FORK_TRACE_LOG_STRING("PostforkChild");
94 for (auto it = forkables_.begin(); it != forkables_.end();) {
95 auto shared = it->lock();
96 if (shared) {
97 shared->PostforkChild();
98 ++it;
99 } else {
100 it = forkables_.erase(it);
101 }
102 }
103 is_forking_ = false;
104 }
105 }
106
107 } // namespace experimental
108 } // namespace grpc_event_engine
109