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