xref: /aosp_15_r20/external/grpc-grpc/test/core/event_engine/forkable_test.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
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 #ifdef GPR_POSIX_SUBPROCESS
20 #include <errno.h>
21 #include <stdlib.h>
22 #include <sys/wait.h>
23 #include <unistd.h>
24 #endif  // GPR_POSIX_SUBPROCESS
25 
26 #include <memory>
27 
28 #include "absl/types/optional.h"
29 #include "gtest/gtest.h"
30 
31 #include <grpc/support/log.h>
32 
33 #include "src/core/lib/config/config_vars.h"
34 #include "src/core/lib/gprpp/no_destruct.h"
35 
36 namespace {
37 using ::grpc_event_engine::experimental::Forkable;
38 using ::grpc_event_engine::experimental::ObjectGroupForkHandler;
39 
40 grpc_core::NoDestruct<ObjectGroupForkHandler> g_forkable_manager;
41 
42 class ForkCallbackMethods {
43  public:
Prefork()44   static void Prefork() { g_forkable_manager->Prefork(); }
PostforkParent()45   static void PostforkParent() { g_forkable_manager->PostforkParent(); }
PostforkChild()46   static void PostforkChild() { g_forkable_manager->PostforkChild(); }
47 };
48 }  // namespace
49 
50 class ForkableTest : public testing::Test {};
51 
52 #ifdef GPR_POSIX_SUBPROCESS
TEST_F(ForkableTest,BasicPthreadAtForkOperations)53 TEST_F(ForkableTest, BasicPthreadAtForkOperations) {
54   class SomeForkable : public Forkable {
55    public:
56     void PrepareFork() override { prepare_called_ = true; }
57     void PostforkParent() override { parent_called_ = true; }
58     void PostforkChild() override { child_called_ = true; }
59 
60     void CheckParent() {
61 #ifdef GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK
62       EXPECT_TRUE(prepare_called_);
63       EXPECT_TRUE(parent_called_);
64       EXPECT_FALSE(child_called_);
65 #else
66       EXPECT_FALSE(prepare_called_);
67       EXPECT_FALSE(parent_called_);
68       EXPECT_FALSE(child_called_);
69 #endif
70     }
71 
72     void CheckChild() {
73 #ifdef GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK
74       EXPECT_TRUE(prepare_called_);
75       EXPECT_FALSE(parent_called_);
76       EXPECT_TRUE(child_called_);
77 #else
78       EXPECT_FALSE(prepare_called_);
79       EXPECT_FALSE(parent_called_);
80       EXPECT_FALSE(child_called_);
81 #endif
82     }
83 
84    private:
85     bool prepare_called_ = false;
86     bool parent_called_ = false;
87     bool child_called_ = false;
88   };
89 
90   auto forkable = std::make_shared<SomeForkable>();
91   g_forkable_manager->RegisterForkable(forkable, ForkCallbackMethods::Prefork,
92                                        ForkCallbackMethods::PostforkParent,
93                                        ForkCallbackMethods::PostforkChild);
94   int child_pid = fork();
95   ASSERT_NE(child_pid, -1);
96   if (child_pid == 0) {
97     gpr_log(GPR_DEBUG, "I am child pid: %d", getpid());
98     forkable->CheckChild();
99     exit(testing::Test::HasFailure());
100   } else {
101     gpr_log(GPR_DEBUG, "I am parent pid: %d", getpid());
102     forkable->CheckParent();
103     int status;
104     gpr_log(GPR_DEBUG, "Waiting for child pid: %d", child_pid);
105     do {
106       // retry on EINTR, and fail otherwise
107       if (waitpid(child_pid, &status, 0) != -1) break;
108       ASSERT_EQ(errno, EINTR);
109     } while (true);
110     if (WIFEXITED(status)) {
111       ASSERT_EQ(WEXITSTATUS(status), 0);
112     } else {
113       // exited abnormally, fail and print the exit status
114       ASSERT_EQ(-99, status);
115     }
116   }
117 }
118 #endif  // GPR_POSIX_SUBPROCESS
119 
TEST_F(ForkableTest,NonPthreadManualForkOperations)120 TEST_F(ForkableTest, NonPthreadManualForkOperations) {
121   // Manually simulates a fork event for non-pthread-enabled environments
122 #ifdef GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK
123   // This platform does not need to exercise fork support manually.
124   GTEST_SKIP() << "Unnecessary test, this platform supports pthreads.";
125 #endif
126 
127   class SomeForkable : public Forkable {
128    public:
129     void PrepareFork() override { prepare_called_ = true; }
130     void PostforkParent() override { parent_called_ = true; }
131     void PostforkChild() override { child_called_ = true; }
132 
133     void AssertStates(bool prepare, bool parent, bool child) {
134       EXPECT_EQ(prepare_called_, prepare);
135       EXPECT_EQ(parent_called_, parent);
136       EXPECT_EQ(child_called_, child);
137     }
138 
139    private:
140     bool prepare_called_ = false;
141     bool parent_called_ = false;
142     bool child_called_ = false;
143   };
144 
145   ObjectGroupForkHandler forkable_manager;
146   class NoopForkCallbackMethods {
147    public:
148     static void Prefork() {}
149     static void PostforkParent() {}
150     static void PostforkChild() {}
151   };
152   auto forkable = std::make_shared<SomeForkable>();
153   forkable_manager.RegisterForkable(forkable, NoopForkCallbackMethods::Prefork,
154                                     NoopForkCallbackMethods::PostforkParent,
155                                     NoopForkCallbackMethods::PostforkChild);
156   forkable->AssertStates(/*prepare=*/false, /*parent=*/false, /*child=*/false);
157   forkable_manager.Prefork();
158   forkable->AssertStates(/*prepare=*/true, /*parent=*/false, /*child=*/false);
159   forkable_manager.PostforkParent();
160   forkable->AssertStates(/*prepare=*/true, /*parent=*/true, /*child=*/false);
161   forkable_manager.Prefork();
162   forkable_manager.PostforkChild();
163   forkable->AssertStates(/*prepare=*/true, /*parent=*/true, /*child=*/true);
164 }
165 
main(int argc,char ** argv)166 int main(int argc, char** argv) {
167   testing::InitGoogleTest(&argc, argv);
168   // Force enable fork support to allow testing the fork handler registry.
169   grpc_core::ConfigVars::Overrides config_overrides;
170   config_overrides.enable_fork_support = true;
171   grpc_core::ConfigVars::SetOverrides(config_overrides);
172   auto result = RUN_ALL_TESTS();
173   return result;
174 }
175