Use multiline attribute to check for IA2_STATE_MULTILINE.
[chromium-blink-merge.git] / sandbox / linux / services / scoped_process.cc
blob4433201ef453f6a03784760a459e06e75daf5f0f
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "sandbox/linux/services/scoped_process.h"
7 #include <fcntl.h>
8 #include <signal.h>
9 #include <sys/stat.h>
10 #include <sys/syscall.h>
11 #include <sys/types.h>
12 #include <sys/wait.h>
13 #include <unistd.h>
15 #include "base/basictypes.h"
16 #include "base/callback.h"
17 #include "base/logging.h"
18 #include "base/posix/eintr_wrapper.h"
19 #include "build/build_config.h"
20 #include "sandbox/linux/services/syscall_wrappers.h"
21 #include "sandbox/linux/services/thread_helpers.h"
23 namespace sandbox {
25 namespace {
27 const char kSynchronisationChar[] = "D";
29 void WaitForever() {
30 while(true) {
31 pause();
35 } // namespace
37 ScopedProcess::ScopedProcess(const base::Closure& child_callback)
38 : child_process_id_(-1), process_id_(getpid()) {
39 PCHECK(0 == pipe(pipe_fds_));
40 #if !defined(THREAD_SANITIZER)
41 // Make sure that we can safely fork().
42 CHECK(ThreadHelpers::IsSingleThreaded());
43 #endif
44 child_process_id_ = fork();
45 PCHECK(0 <= child_process_id_);
47 if (0 == child_process_id_) {
48 PCHECK(0 == IGNORE_EINTR(close(pipe_fds_[0])));
49 pipe_fds_[0] = -1;
50 child_callback.Run();
51 // Notify the parent that the closure has run.
52 CHECK_EQ(1, HANDLE_EINTR(write(pipe_fds_[1], kSynchronisationChar, 1)));
53 WaitForever();
54 NOTREACHED();
55 _exit(1);
58 PCHECK(0 == IGNORE_EINTR(close(pipe_fds_[1])));
59 pipe_fds_[1] = -1;
62 ScopedProcess::~ScopedProcess() {
63 CHECK(IsOriginalProcess());
64 if (child_process_id_ >= 0) {
65 PCHECK(0 == kill(child_process_id_, SIGKILL));
66 siginfo_t process_info;
68 PCHECK(0 == HANDLE_EINTR(
69 waitid(P_PID, child_process_id_, &process_info, WEXITED)));
71 if (pipe_fds_[0] >= 0) {
72 PCHECK(0 == IGNORE_EINTR(close(pipe_fds_[0])));
74 if (pipe_fds_[1] >= 0) {
75 PCHECK(0 == IGNORE_EINTR(close(pipe_fds_[1])));
79 int ScopedProcess::WaitForExit(bool* got_signaled) {
80 DCHECK(got_signaled);
81 CHECK(IsOriginalProcess());
82 siginfo_t process_info;
83 // WNOWAIT to make sure that the destructor can wait on the child.
84 int ret = HANDLE_EINTR(
85 waitid(P_PID, child_process_id_, &process_info, WEXITED | WNOWAIT));
86 PCHECK(0 == ret) << "Did something else wait on the child?";
88 if (process_info.si_code == CLD_EXITED) {
89 *got_signaled = false;
90 } else if (process_info.si_code == CLD_KILLED ||
91 process_info.si_code == CLD_DUMPED) {
92 *got_signaled = true;
93 } else {
94 CHECK(false) << "ScopedProcess needs to be extended for si_code "
95 << process_info.si_code;
97 return process_info.si_status;
100 bool ScopedProcess::WaitForClosureToRun() {
101 char c = 0;
102 int ret = HANDLE_EINTR(read(pipe_fds_[0], &c, 1));
103 PCHECK(ret >= 0);
104 if (0 == ret)
105 return false;
107 CHECK_EQ(c, kSynchronisationChar[0]);
108 return true;
111 // It would be problematic if after a fork(), another process would start using
112 // this object.
113 // This method allows to assert it is not happening.
114 bool ScopedProcess::IsOriginalProcess() {
115 // Make a direct syscall to bypass glibc caching of PIDs.
116 pid_t pid = sys_getpid();
117 return pid == process_id_;
120 } // namespace sandbox