| Index: util/test/mac/mach_multiprocess.cc
|
| diff --git a/util/test/mac/mach_multiprocess.cc b/util/test/mac/mach_multiprocess.cc
|
| index c5e749cf48c2f7ef35797c15c27caa59e1ba8866..d78b86008559e05789c21b7456975723da31954f 100644
|
| --- a/util/test/mac/mach_multiprocess.cc
|
| +++ b/util/test/mac/mach_multiprocess.cc
|
| @@ -17,35 +17,22 @@
|
| #include <AvailabilityMacros.h>
|
| #include <bsm/libbsm.h>
|
| #include <servers/bootstrap.h>
|
| -#include <signal.h>
|
| -#include <stdlib.h>
|
| -#include <sys/wait.h>
|
|
|
| #include <string>
|
|
|
| #include "base/auto_reset.h"
|
| -#include "base/files/scoped_file.h"
|
| #include "base/logging.h"
|
| #include "base/mac/scoped_mach_port.h"
|
| #include "base/memory/scoped_ptr.h"
|
| #include "base/rand_util.h"
|
| -#include "base/strings/stringprintf.h"
|
| #include "gtest/gtest.h"
|
| #include "util/mach/bootstrap.h"
|
| +#include "util/misc/scoped_forbid_return.h"
|
| #include "util/test/errors.h"
|
| #include "util/test/mac/mach_errors.h"
|
|
|
| namespace {
|
|
|
| -class ScopedNotReached {
|
| - public:
|
| - ScopedNotReached() {}
|
| - ~ScopedNotReached() { abort(); }
|
| -
|
| - private:
|
| - DISALLOW_COPY_AND_ASSIGN(ScopedNotReached);
|
| -};
|
| -
|
| // The “hello” message contains a send right to the child process’ task port.
|
| struct SendHelloMessage : public mach_msg_base_t {
|
| mach_msg_port_descriptor_t port_descriptor;
|
| @@ -67,25 +54,11 @@ namespace internal {
|
| struct MachMultiprocessInfo {
|
| MachMultiprocessInfo()
|
| : service_name(),
|
| - pipe_c2p_read(-1),
|
| - pipe_c2p_write(-1),
|
| - pipe_p2c_read(-1),
|
| - pipe_p2c_write(-1),
|
| - child_pid(0),
|
| - read_pipe_fd(-1),
|
| - write_pipe_fd(-1),
|
| local_port(MACH_PORT_NULL),
|
| remote_port(MACH_PORT_NULL),
|
| child_task(MACH_PORT_NULL) {}
|
|
|
| std::string service_name;
|
| - base::ScopedFD pipe_c2p_read; // child to parent
|
| - base::ScopedFD pipe_c2p_write; // child to parent
|
| - base::ScopedFD pipe_p2c_read; // parent to child
|
| - base::ScopedFD pipe_p2c_write; // parent to child
|
| - pid_t child_pid; // valid only in parent
|
| - int read_pipe_fd; // pipe_c2p_read in parent, pipe_p2c_read in child
|
| - int write_pipe_fd; // pipe_p2c_write in parent, pipe_c2p_write in child
|
| base::mac::ScopedMachReceiveRight local_port;
|
| base::mac::ScopedMachSendRight remote_port;
|
| base::mac::ScopedMachSendRight child_task; // valid only in parent
|
| @@ -93,7 +66,7 @@ struct MachMultiprocessInfo {
|
|
|
| } // namespace internal
|
|
|
| -MachMultiprocess::MachMultiprocess() : info_(NULL) {
|
| +MachMultiprocess::MachMultiprocess() : Multiprocess(), info_(NULL) {
|
| }
|
|
|
| void MachMultiprocess::Run() {
|
| @@ -103,19 +76,17 @@ void MachMultiprocess::Run() {
|
| base::AutoReset<internal::MachMultiprocessInfo*> reset_info(&info_,
|
| info.get());
|
|
|
| - int pipe_fds_c2p[2];
|
| - int rv = pipe(pipe_fds_c2p);
|
| - ASSERT_EQ(0, rv) << ErrnoMessage("pipe");
|
| -
|
| - info_->pipe_c2p_read.reset(pipe_fds_c2p[0]);
|
| - info_->pipe_c2p_write.reset(pipe_fds_c2p[1]);
|
| + return Multiprocess::Run();
|
| +}
|
|
|
| - int pipe_fds_p2c[2];
|
| - rv = pipe(pipe_fds_p2c);
|
| - ASSERT_EQ(0, rv) << ErrnoMessage("pipe");
|
| +MachMultiprocess::~MachMultiprocess() {
|
| +}
|
|
|
| - info_->pipe_p2c_read.reset(pipe_fds_p2c[0]);
|
| - info_->pipe_p2c_write.reset(pipe_fds_p2c[1]);
|
| +void MachMultiprocess::PreFork() {
|
| + Multiprocess::PreFork();
|
| + if (testing::Test::HasFatalFailure()) {
|
| + return;
|
| + }
|
|
|
| // Set up the parent port and register it with the bootstrap server before
|
| // forking, so that it’s guaranteed to be there when the child attempts to
|
| @@ -131,65 +102,6 @@ void MachMultiprocess::Run() {
|
| ASSERT_EQ(BOOTSTRAP_SUCCESS, kr)
|
| << BootstrapErrorMessage(kr, "bootstrap_check_in");
|
| info_->local_port.reset(local_port);
|
| -
|
| - pid_t pid = fork();
|
| - ASSERT_GE(pid, 0) << ErrnoMessage("fork");
|
| -
|
| - if (pid > 0) {
|
| - info_->child_pid = pid;
|
| -
|
| - RunParent();
|
| -
|
| - // Waiting for the child happens here instead of in RunParent() because even
|
| - // if RunParent() returns early due to a gtest fatal assertion failure, the
|
| - // child should still be reaped.
|
| -
|
| - // This will make the parent hang up on the child as much as would be
|
| - // visible from the child’s perspective. The child’s side of the pipe will
|
| - // be broken, the child’s remote port will become a dead name, and an
|
| - // attempt by the child to look up the service will fail. If this weren’t
|
| - // done, the child might hang while waiting for a parent that has already
|
| - // triggered a fatal assertion failure to do something.
|
| - info.reset();
|
| - info_ = NULL;
|
| -
|
| - int status;
|
| - pid_t wait_pid = waitpid(pid, &status, 0);
|
| - ASSERT_EQ(pid, wait_pid) << ErrnoMessage("waitpid");
|
| - if (status != 0) {
|
| - std::string message;
|
| - if (WIFEXITED(status)) {
|
| - message = base::StringPrintf("Child exited with code %d",
|
| - WEXITSTATUS(status));
|
| - } else if (WIFSIGNALED(status)) {
|
| - message = base::StringPrintf("Child terminated by signal %d (%s) %s",
|
| - WTERMSIG(status),
|
| - strsignal(WTERMSIG(status)),
|
| - WCOREDUMP(status) ? " (core dumped)" : "");
|
| - }
|
| - ASSERT_EQ(0, status) << message;
|
| - }
|
| - } else {
|
| - RunChild();
|
| - }
|
| -}
|
| -
|
| -MachMultiprocess::~MachMultiprocess() {
|
| -}
|
| -
|
| -pid_t MachMultiprocess::ChildPID() const {
|
| - EXPECT_NE(0, info_->child_pid);
|
| - return info_->child_pid;
|
| -}
|
| -
|
| -int MachMultiprocess::ReadPipeFD() const {
|
| - EXPECT_NE(-1, info_->read_pipe_fd);
|
| - return info_->read_pipe_fd;
|
| -}
|
| -
|
| -int MachMultiprocess::WritePipeFD() const {
|
| - EXPECT_NE(-1, info_->write_pipe_fd);
|
| - return info_->write_pipe_fd;
|
| }
|
|
|
| mach_port_t MachMultiprocess::LocalPort() const {
|
| @@ -207,13 +119,7 @@ mach_port_t MachMultiprocess::ChildTask() const {
|
| return info_->child_task;
|
| }
|
|
|
| -void MachMultiprocess::RunParent() {
|
| - // The parent uses the read end of c2p and the write end of p2c.
|
| - info_->pipe_c2p_write.reset();
|
| - info_->read_pipe_fd = info_->pipe_c2p_read.get();
|
| - info_->pipe_p2c_read.reset();
|
| - info_->write_pipe_fd = info_->pipe_p2c_write.get();
|
| -
|
| +void MachMultiprocess::MultiprocessParent() {
|
| ReceiveHelloMessage message = {};
|
|
|
| kern_return_t kr =
|
| @@ -299,29 +205,18 @@ void MachMultiprocess::RunParent() {
|
| ASSERT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "pid_for_task");
|
| ASSERT_EQ(ChildPID(), mach_pid);
|
|
|
| - Parent();
|
| + MachMultiprocessParent();
|
|
|
| info_->remote_port.reset();
|
| info_->local_port.reset();
|
| -
|
| - info_->read_pipe_fd = -1;
|
| - info_->pipe_c2p_read.reset();
|
| - info_->write_pipe_fd = -1;
|
| - info_->pipe_p2c_write.reset();
|
| }
|
|
|
| -void MachMultiprocess::RunChild() {
|
| - ScopedNotReached must_not_leave_this_scope;
|
| +void MachMultiprocess::MultiprocessChild() {
|
| + ScopedForbidReturn forbid_return;;
|
|
|
| // local_port is not valid in the forked child process.
|
| ignore_result(info_->local_port.release());
|
|
|
| - // The child uses the write end of c2p and the read end of p2c.
|
| - info_->pipe_c2p_read.reset();
|
| - info_->write_pipe_fd = info_->pipe_c2p_write.get();
|
| - info_->pipe_p2c_write.reset();
|
| - info_->read_pipe_fd = info_->pipe_p2c_read.get();
|
| -
|
| mach_port_t local_port;
|
| kern_return_t kr = mach_port_allocate(
|
| mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &local_port);
|
| @@ -360,22 +255,17 @@ void MachMultiprocess::RunChild() {
|
| MACH_PORT_NULL);
|
| ASSERT_EQ(MACH_MSG_SUCCESS, kr) << MachErrorMessage(kr, "mach_msg");
|
|
|
| - Child();
|
| + MachMultiprocessChild();
|
|
|
| info_->remote_port.reset();
|
| info_->local_port.reset();
|
|
|
| - info_->write_pipe_fd = -1;
|
| - info_->pipe_c2p_write.reset();
|
| - info_->read_pipe_fd = -1;
|
| - info_->pipe_p2c_read.reset();
|
| -
|
| if (Test::HasFailure()) {
|
| - // Trigger the ScopedNotReached destructor.
|
| + // Trigger the ScopedForbidReturn destructor.
|
| return;
|
| }
|
|
|
| - exit(0);
|
| + forbid_return.Disarm();
|
| }
|
|
|
| } // namespace test
|
|
|