Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1800)

Unified Diff: util/test/multiprocess.cc

Issue 506143002: Refactor MachMultiprocess (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « util/test/multiprocess.h ('k') | util/test/multiprocess_test.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: util/test/multiprocess.cc
diff --git a/util/test/multiprocess.cc b/util/test/multiprocess.cc
new file mode 100644
index 0000000000000000000000000000000000000000..34cbddc4de633a3c9c33665c3691447f3a0a7501
--- /dev/null
+++ b/util/test/multiprocess.cc
@@ -0,0 +1,180 @@
+// Copyright 2014 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "util/test/multiprocess.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/memory/scoped_ptr.h"
+#include "base/strings/stringprintf.h"
+#include "gtest/gtest.h"
+#include "util/misc/scoped_forbid_return.h"
+#include "util/test/errors.h"
+
+namespace crashpad {
+namespace test {
+
+using namespace testing;
+
+namespace internal {
+
+struct MultiprocessInfo {
+ MultiprocessInfo()
+ : pipe_c2p_read(-1),
+ pipe_c2p_write(-1),
+ pipe_p2c_read(-1),
+ pipe_p2c_write(-1),
+ child_pid(0) {}
+
+ 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
+};
+
+} // namespace internal
+
+Multiprocess::Multiprocess() : info_(NULL) {
+}
+
+void Multiprocess::Run() {
+ ASSERT_EQ(NULL, info_);
+ scoped_ptr<internal::MultiprocessInfo> info(new internal::MultiprocessInfo);
+ base::AutoReset<internal::MultiprocessInfo*> reset_info(&info_, info.get());
+
+ PreFork();
+ if (testing::Test::HasFatalFailure()) {
+ return;
+ }
+
+ 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();
+ }
+}
+
+Multiprocess::~Multiprocess() {
+}
+
+void Multiprocess::PreFork() {
+ 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]);
+
+ int pipe_fds_p2c[2];
+ rv = pipe(pipe_fds_p2c);
+ ASSERT_EQ(0, rv) << ErrnoMessage("pipe");
+
+ info_->pipe_p2c_read.reset(pipe_fds_p2c[0]);
+ info_->pipe_p2c_write.reset(pipe_fds_p2c[1]);
+}
+
+pid_t Multiprocess::ChildPID() const {
+ EXPECT_NE(0, info_->child_pid);
+ return info_->child_pid;
+}
+
+int Multiprocess::ReadPipeFD() const {
+ int fd = info_->child_pid ? info_->pipe_c2p_read.get()
+ : info_->pipe_p2c_read.get();
+ EXPECT_NE(-1, fd);
+ return fd;
+}
+
+int Multiprocess::WritePipeFD() const {
+ int fd = info_->child_pid ? info_->pipe_p2c_write.get()
+ : info_->pipe_c2p_write.get();
+ EXPECT_NE(-1, fd);
+ return fd;
+}
+
+void Multiprocess::RunParent() {
+ // The parent uses the read end of c2p and the write end of p2c.
+ info_->pipe_c2p_write.reset();
+ info_->pipe_p2c_read.reset();
+
+ MultiprocessParent();
+
+ info_->pipe_c2p_read.reset();
+ info_->pipe_p2c_write.reset();
+}
+
+void Multiprocess::RunChild() {
+ ScopedForbidReturn forbid_return;
+
+ // The child uses the write end of c2p and the read end of p2c.
+ info_->pipe_c2p_read.reset();
+ info_->pipe_p2c_write.reset();
+
+ MultiprocessChild();
+
+ info_->pipe_c2p_write.reset();
+ info_->pipe_p2c_read.reset();
+
+ if (Test::HasFailure()) {
+ // Trigger the ScopedForbidReturn destructor.
+ return;
+ }
+
+ exit(0);
+}
+
+} // namespace test
+} // namespace crashpad
« no previous file with comments | « util/test/multiprocess.h ('k') | util/test/multiprocess_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698