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"
10 #include <sys/syscall.h>
11 #include <sys/types.h>
15 #include "base/callback.h"
16 #include "base/logging.h"
17 #include "base/posix/eintr_wrapper.h"
18 #include "build/build_config.h"
19 #include "sandbox/linux/services/syscall_wrappers.h"
20 #include "sandbox/linux/services/thread_helpers.h"
26 const char kSynchronisationChar
[] = "D";
36 ScopedProcess::ScopedProcess(const base::Closure
& child_callback
)
37 : child_process_id_(-1), process_id_(getpid()) {
38 PCHECK(0 == pipe(pipe_fds_
));
39 #if !defined(THREAD_SANITIZER)
40 // Make sure that we can safely fork().
41 CHECK(ThreadHelpers::IsSingleThreaded());
43 child_process_id_
= fork();
44 PCHECK(0 <= child_process_id_
);
46 if (0 == child_process_id_
) {
47 PCHECK(0 == IGNORE_EINTR(close(pipe_fds_
[0])));
50 // Notify the parent that the closure has run.
51 CHECK_EQ(1, HANDLE_EINTR(write(pipe_fds_
[1], kSynchronisationChar
, 1)));
57 PCHECK(0 == IGNORE_EINTR(close(pipe_fds_
[1])));
61 ScopedProcess::~ScopedProcess() {
62 CHECK(IsOriginalProcess());
63 if (child_process_id_
>= 0) {
64 PCHECK(0 == kill(child_process_id_
, SIGKILL
));
65 siginfo_t process_info
;
67 PCHECK(0 == HANDLE_EINTR(
68 waitid(P_PID
, child_process_id_
, &process_info
, WEXITED
)));
70 if (pipe_fds_
[0] >= 0) {
71 PCHECK(0 == IGNORE_EINTR(close(pipe_fds_
[0])));
73 if (pipe_fds_
[1] >= 0) {
74 PCHECK(0 == IGNORE_EINTR(close(pipe_fds_
[1])));
78 int ScopedProcess::WaitForExit(bool* got_signaled
) {
80 CHECK(IsOriginalProcess());
81 siginfo_t process_info
;
82 // WNOWAIT to make sure that the destructor can wait on the child.
83 int ret
= HANDLE_EINTR(
84 waitid(P_PID
, child_process_id_
, &process_info
, WEXITED
| WNOWAIT
));
85 PCHECK(0 == ret
) << "Did something else wait on the child?";
87 if (process_info
.si_code
== CLD_EXITED
) {
88 *got_signaled
= false;
89 } else if (process_info
.si_code
== CLD_KILLED
||
90 process_info
.si_code
== CLD_DUMPED
) {
93 CHECK(false) << "ScopedProcess needs to be extended for si_code "
94 << process_info
.si_code
;
96 return process_info
.si_status
;
99 bool ScopedProcess::WaitForClosureToRun() {
101 int ret
= HANDLE_EINTR(read(pipe_fds_
[0], &c
, 1));
106 CHECK_EQ(c
, kSynchronisationChar
[0]);
110 // It would be problematic if after a fork(), another process would start using
112 // This method allows to assert it is not happening.
113 bool ScopedProcess::IsOriginalProcess() {
114 // Make a direct syscall to bypass glibc caching of PIDs.
115 pid_t pid
= sys_getpid();
116 return pid
== process_id_
;
119 } // namespace sandbox