| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 The Crashpad Authors. All rights reserved. | |
| 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 #ifndef CRASHPAD_UTIL_TEST_MULTIPROCESS_H_ | |
| 16 #define CRASHPAD_UTIL_TEST_MULTIPROCESS_H_ | |
| 17 | |
| 18 #include <sys/types.h> | |
| 19 | |
| 20 #include "base/basictypes.h" | |
| 21 #include "build/build_config.h" | |
| 22 #include "util/file/file_io.h" | |
| 23 | |
| 24 namespace crashpad { | |
| 25 namespace test { | |
| 26 | |
| 27 namespace internal { | |
| 28 struct MultiprocessInfo; | |
| 29 }; | |
| 30 | |
| 31 //! \brief Manages a multiprocess test. | |
| 32 //! | |
| 33 //! These tests are `fork()`-based. The parent and child processes are able to | |
| 34 //! communicate via a pair of POSIX pipes. | |
| 35 //! | |
| 36 //! Subclasses are expected to implement the parent and child by overriding the | |
| 37 //! appropriate methods. | |
| 38 //! | |
| 39 //! On Windows, this class is only an internal implementation detail of | |
| 40 //! MultiprocessExec and all tests must use that class. | |
| 41 class Multiprocess { | |
| 42 public: | |
| 43 //! \brief The termination type for a child process. | |
| 44 enum TerminationReason : bool { | |
| 45 //! \brief The child terminated normally. | |
| 46 //! | |
| 47 //! A normal return happens when a test returns from RunChild(), or for | |
| 48 //! tests that `exec()`, returns from `main()`. This also happens for tests | |
| 49 //! that call `exit()` or `_exit()`. | |
| 50 kTerminationNormal = false, | |
| 51 | |
| 52 //! \brief The child terminated by signal. | |
| 53 //! | |
| 54 //! Signal termination happens as a result of a crash, a call to `abort()`, | |
| 55 //! assertion failure (including gtest assertions), etc. | |
| 56 kTerminationSignal, | |
| 57 }; | |
| 58 | |
| 59 Multiprocess(); | |
| 60 | |
| 61 //! \brief Runs the test. | |
| 62 //! | |
| 63 //! This method establishes the proper testing environment by calling | |
| 64 //! PreFork(), then calls `fork()`. In the parent process, it calls | |
| 65 //! RunParent(), and in the child process, it calls RunChild(). | |
| 66 //! | |
| 67 //! This method uses gtest assertions to validate the testing environment. If | |
| 68 //! the testing environment cannot be set up properly, it is possible that | |
| 69 //! MultiprocessParent() or MultiprocessChild() will not be called. In the | |
| 70 //! parent process, this method also waits for the child process to exit after | |
| 71 //! MultiprocessParent() returns, and verifies that it exited in accordance | |
| 72 //! with the expectations set by SetExpectedChildTermination(). | |
| 73 void Run(); | |
| 74 | |
| 75 //! \brief Sets the expected termination reason and code. | |
| 76 //! | |
| 77 //! The default expected termination reasaon is | |
| 78 //! TerminationReason::kTerminationNormal, and the default expected | |
| 79 //! termination code is `EXIT_SUCCESS` (`0`). | |
| 80 //! | |
| 81 //! \param[in] reason Whether to expect the child to terminate normally or | |
| 82 //! as a result of a signal. | |
| 83 //! \param[in] code If \a reason is TerminationReason::kTerminationNormal, | |
| 84 //! this is the expected exit status of the child. If \a reason is | |
| 85 //! TerminationReason::kTerminationSignal, this is the signal that is | |
| 86 //! expected to kill the child. | |
| 87 void SetExpectedChildTermination(TerminationReason reason, int code); | |
| 88 | |
| 89 protected: | |
| 90 ~Multiprocess(); | |
| 91 | |
| 92 //! \brief Establishes the proper testing environment prior to forking. | |
| 93 //! | |
| 94 //! Subclasses that solely implement a test should not need to override this | |
| 95 //! method. Subclasses that do not implement tests but instead implement | |
| 96 //! additional testing features on top of this class may override this method | |
| 97 //! provided that they call the superclass’ implementation first as follows: | |
| 98 //! | |
| 99 //! \code | |
| 100 //! void PreFork() override { | |
| 101 //! ASSERT_NO_FATAL_FAILURE(Multiprocess::PreFork()); | |
| 102 //! | |
| 103 //! // Place subclass-specific pre-fork code here. | |
| 104 //! } | |
| 105 //! \endcode | |
| 106 //! | |
| 107 //! Subclass implementations may signal failure by raising their own fatal | |
| 108 //! gtest assertions. | |
| 109 virtual void PreFork(); | |
| 110 | |
| 111 #if !defined(OS_WIN) | |
| 112 //! \brief Returns the child process’ process ID. | |
| 113 //! | |
| 114 //! This method may only be called by the parent process. | |
| 115 pid_t ChildPID() const; | |
| 116 #endif // !OS_WIN | |
| 117 | |
| 118 //! \brief Returns the read pipe’s file handle. | |
| 119 //! | |
| 120 //! This method may be called by either the parent or the child process. | |
| 121 //! Anything written to the write pipe in the partner process will appear | |
| 122 //! on this file handle in this process. | |
| 123 //! | |
| 124 //! It is an error to call this after CloseReadPipe() has been called. | |
| 125 //! | |
| 126 //! \return The read pipe’s file handle. | |
| 127 FileHandle ReadPipeHandle() const; | |
| 128 | |
| 129 //! \brief Returns the write pipe’s file handle. | |
| 130 //! | |
| 131 //! This method may be called by either the parent or the child process. | |
| 132 //! Anything written to this file handle in this process will appear on | |
| 133 //! the read pipe in the partner process. | |
| 134 //! | |
| 135 //! It is an error to call this after CloseWritePipe() has been called. | |
| 136 //! | |
| 137 //! \return The write pipe’s file handle. | |
| 138 FileHandle WritePipeHandle() const; | |
| 139 | |
| 140 //! \brief Closes the read pipe. | |
| 141 //! | |
| 142 //! This method may be called by either the parent or the child process. An | |
| 143 //! attempt to write to the write pipe in the partner process will fail with | |
| 144 //! `EPIPE` or `SIGPIPE`. ReadPipeHandle() must not be called after this. | |
| 145 void CloseReadPipe(); | |
| 146 | |
| 147 //! \brief Closes the write pipe. | |
| 148 //! | |
| 149 //! This method may be called by either the parent or the child process. An | |
| 150 //! attempt to read from the read pipe in the partner process will indicate | |
| 151 //! end-of-file. WritePipeHandle() must not be called after this. | |
| 152 void CloseWritePipe(); | |
| 153 | |
| 154 void set_info(internal::MultiprocessInfo* info) { info_ = info; } | |
| 155 internal::MultiprocessInfo* info() { return info_; } | |
| 156 | |
| 157 private: | |
| 158 //! \brief Runs the parent side of the test. | |
| 159 //! | |
| 160 //! This method establishes the parent’s environment and calls | |
| 161 //! MultiprocessParent(). | |
| 162 void RunParent(); | |
| 163 | |
| 164 //! \brief Runs the child side of the test. | |
| 165 //! | |
| 166 //! This method establishes the child’s environment, calls | |
| 167 //! MultiprocessChild(), and exits cleanly by calling `_exit(0)`. However, if | |
| 168 //! any failure (via fatal or nonfatal gtest assertion) is detected, the child | |
| 169 //! will exit with a failure status. | |
| 170 void RunChild(); | |
| 171 | |
| 172 //! \brief The subclass-provided parent routine. | |
| 173 //! | |
| 174 //! Test failures should be reported via gtest: `EXPECT_*()`, `ASSERT_*()`, | |
| 175 //! `FAIL()`, etc. | |
| 176 //! | |
| 177 //! This method must not use a `wait()`-family system call to wait for the | |
| 178 //! child process to exit, as this is handled by this class. | |
| 179 //! | |
| 180 //! Subclasses must implement this method to define how the parent operates. | |
| 181 virtual void MultiprocessParent() = 0; | |
| 182 | |
| 183 //! \brief The subclass-provided child routine. | |
| 184 //! | |
| 185 //! Test failures should be reported via gtest: `EXPECT_*()`, `ASSERT_*()`, | |
| 186 //! `FAIL()`, etc. | |
| 187 //! | |
| 188 //! Subclasses must implement this method to define how the child operates. | |
| 189 //! Subclasses may exit with a failure status by using `LOG(FATAL)`, | |
| 190 //! `abort()`, or similar. They may exit cleanly by returning from this method | |
| 191 //! or by calling `_exit(0)`. Under no circumstances may `exit()` be called | |
| 192 //! by the child without having the child process `exec()`. Use | |
| 193 //! MultiprocessExec if the child should call `exec()`. | |
| 194 virtual void MultiprocessChild() = 0; | |
| 195 | |
| 196 internal::MultiprocessInfo* info_; | |
| 197 int code_; | |
| 198 TerminationReason reason_; | |
| 199 | |
| 200 DISALLOW_COPY_AND_ASSIGN(Multiprocess); | |
| 201 }; | |
| 202 | |
| 203 } // namespace test | |
| 204 } // namespace crashpad | |
| 205 | |
| 206 #endif // CRASHPAD_UTIL_TEST_MULTIPROCESS_H_ | |
| OLD | NEW |