blob: 6d41fe6cd66c034a26ce80848af7bdc76051eabd [file] [log] [blame]
[email protected]927054d2012-01-21 01:48:251// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]3d5617e2008-08-27 14:36:192// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]05d4b0a2009-01-29 17:51:515#include <dirent.h>
[email protected]c7856632009-01-13 17:38:496#include <errno.h>
[email protected]05d4b0a2009-01-29 17:51:517#include <fcntl.h>
[email protected]8cf7cebd2009-01-05 19:53:308#include <signal.h>
[email protected]05d4b0a2009-01-29 17:51:519#include <stdlib.h>
[email protected]0d83c732008-12-02 16:50:4710#include <sys/resource.h>
11#include <sys/time.h>
[email protected]3d5617e2008-08-27 14:36:1912#include <sys/types.h>
[email protected]43bc28322008-12-05 01:57:2113#include <sys/wait.h>
[email protected]3d5617e2008-08-27 14:36:1914#include <unistd.h>
[email protected]05d4b0a2009-01-29 17:51:5115
[email protected]64146372012-04-05 11:38:3616#include <iterator>
[email protected]fa3097a6a52008-12-17 22:41:5017#include <limits>
[email protected]3f04f2b2009-04-30 19:40:0318#include <set>
[email protected]3d5617e2008-08-27 14:36:1919
[email protected]7ce58b22012-09-26 05:17:2520#include "base/allocator/type_profiler_control.h"
[email protected]5d91c9e2010-07-28 17:25:2821#include "base/command_line.h"
[email protected]cabe39c2010-02-02 02:28:1622#include "base/compiler_specific.h"
[email protected]72e243662011-06-11 00:46:1023#include "base/debug/debugger.h"
[email protected]58580352010-10-26 04:07:5024#include "base/debug/stack_trace.h"
[email protected]157c61b2009-05-01 21:37:3125#include "base/eintr_wrapper.h"
[email protected]955b7392011-03-09 00:49:2026#include "base/file_util.h"
[email protected]d88e17f2012-06-29 21:09:1427#include "base/files/dir_reader_posix.h"
[email protected]0d83c732008-12-02 16:50:4728#include "base/logging.h"
[email protected]3b63f8f42011-03-28 01:54:1529#include "base/memory/scoped_ptr.h"
[email protected]05d4b0a2009-01-29 17:51:5130#include "base/process_util.h"
[email protected]f1633932010-08-17 23:05:2831#include "base/stringprintf.h"
[email protected]44f9c952011-01-02 06:05:3932#include "base/synchronization/waitable_event.h"
[email protected]2f7a6ea2011-06-18 11:49:2733#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
[email protected]ce072a72010-12-31 20:02:1634#include "base/threading/platform_thread.h"
[email protected]34b99632011-01-01 01:01:0635#include "base/threading/thread_restrictions.h"
[email protected]3d5617e2008-08-27 14:36:1936
[email protected]927054d2012-01-21 01:48:2537#if defined(OS_CHROMEOS)
38#include <sys/ioctl.h>
39#endif
40
[email protected]af824362011-12-04 14:19:4141#if defined(OS_FREEBSD)
42#include <sys/event.h>
43#include <sys/ucontext.h>
44#endif
45
[email protected]c0028792010-01-12 00:39:1546#if defined(OS_MACOSX)
[email protected]ef73044e2010-03-11 15:25:5447#include <crt_externs.h>
[email protected]56f0f262011-02-24 17:14:3648#include <sys/event.h>
[email protected]ef73044e2010-03-11 15:25:5449#else
50extern char** environ;
[email protected]c0028792010-01-12 00:39:1551#endif
52
[email protected]aa660752008-11-14 03:39:4653namespace base {
[email protected]3d5617e2008-08-27 14:36:1954
[email protected]d6fc9fd2009-10-27 18:03:4755namespace {
56
[email protected]2e844ef8e2011-06-30 20:01:2757// Get the process's "environment" (i.e. the thing that setenv/getenv
58// work with).
59char** GetEnvironment() {
60#if defined(OS_MACOSX)
61 return *_NSGetEnviron();
62#else
63 return environ;
64#endif
65}
66
67// Set the process's "environment" (i.e. the thing that setenv/getenv
68// work with).
69void SetEnvironment(char** env) {
70#if defined(OS_MACOSX)
71 *_NSGetEnviron() = env;
72#else
73 environ = env;
74#endif
75}
76
[email protected]eaec38c2010-11-29 19:30:2377int WaitpidWithTimeout(ProcessHandle handle, int64 wait_milliseconds,
78 bool* success) {
[email protected]d6fc9fd2009-10-27 18:03:4779 // This POSIX version of this function only guarantees that we wait no less
[email protected]2d9bb0222010-04-02 08:24:0180 // than |wait_milliseconds| for the process to exit. The child process may
81 // exit sometime before the timeout has ended but we may still block for up
82 // to 256 milliseconds after the fact.
[email protected]d6fc9fd2009-10-27 18:03:4783 //
84 // waitpid() has no direct support on POSIX for specifying a timeout, you can
85 // either ask it to block indefinitely or return immediately (WNOHANG).
86 // When a child process terminates a SIGCHLD signal is sent to the parent.
87 // Catching this signal would involve installing a signal handler which may
88 // affect other parts of the application and would be difficult to debug.
89 //
90 // Our strategy is to call waitpid() once up front to check if the process
91 // has already exited, otherwise to loop for wait_milliseconds, sleeping for
[email protected]2d9bb0222010-04-02 08:24:0192 // at most 256 milliseconds each time using usleep() and then calling
93 // waitpid(). The amount of time we sleep starts out at 1 milliseconds, and
94 // we double it every 4 sleep cycles.
[email protected]d6fc9fd2009-10-27 18:03:4795 //
96 // usleep() is speced to exit if a signal is received for which a handler
97 // has been installed. This means that when a SIGCHLD is sent, it will exit
98 // depending on behavior external to this function.
99 //
[email protected]eaec38c2010-11-29 19:30:23100 // This function is used primarily for unit tests, if we want to use it in
101 // the application itself it would probably be best to examine other routes.
102 int status = -1;
103 pid_t ret_pid = HANDLE_EINTR(waitpid(handle, &status, WNOHANG));
[email protected]2d9bb0222010-04-02 08:24:01104 static const int64 kMaxSleepInMicroseconds = 1 << 18; // ~256 milliseconds.
105 int64 max_sleep_time_usecs = 1 << 10; // ~1 milliseconds.
[email protected]eaec38c2010-11-29 19:30:23106 int64 double_sleep_time = 0;
[email protected]d6fc9fd2009-10-27 18:03:47107
108 // If the process hasn't exited yet, then sleep and try again.
[email protected]2d9bb0222010-04-02 08:24:01109 Time wakeup_time = Time::Now() +
110 TimeDelta::FromMilliseconds(wait_milliseconds);
[email protected]d6fc9fd2009-10-27 18:03:47111 while (ret_pid == 0) {
112 Time now = Time::Now();
113 if (now > wakeup_time)
114 break;
115 // Guaranteed to be non-negative!
116 int64 sleep_time_usecs = (wakeup_time - now).InMicroseconds();
[email protected]2d9bb0222010-04-02 08:24:01117 // Sleep for a bit while we wait for the process to finish.
118 if (sleep_time_usecs > max_sleep_time_usecs)
119 sleep_time_usecs = max_sleep_time_usecs;
[email protected]d6fc9fd2009-10-27 18:03:47120
121 // usleep() will return 0 and set errno to EINTR on receipt of a signal
122 // such as SIGCHLD.
123 usleep(sleep_time_usecs);
[email protected]eaec38c2010-11-29 19:30:23124 ret_pid = HANDLE_EINTR(waitpid(handle, &status, WNOHANG));
[email protected]2d9bb0222010-04-02 08:24:01125
126 if ((max_sleep_time_usecs < kMaxSleepInMicroseconds) &&
127 (double_sleep_time++ % 4 == 0)) {
128 max_sleep_time_usecs *= 2;
129 }
[email protected]d6fc9fd2009-10-27 18:03:47130 }
131
[email protected]eaec38c2010-11-29 19:30:23132 if (success)
133 *success = (ret_pid != -1);
134
135 return status;
[email protected]d6fc9fd2009-10-27 18:03:47136}
137
[email protected]1e932112011-06-29 20:53:22138// Android has built-in crash handling.
139#if !defined(OS_ANDROID)
[email protected]7e3edc22010-11-22 22:31:00140void StackDumpSignalHandler(int signal, siginfo_t* info, ucontext_t* context) {
[email protected]72e243662011-06-11 00:46:10141 if (debug::BeingDebugged())
142 debug::BreakDebugger();
143
[email protected]a42d4632011-10-26 21:48:00144 DLOG(ERROR) << "Received signal " << signal;
[email protected]58580352010-10-26 04:07:50145 debug::StackTrace().PrintBacktrace();
[email protected]7e3edc22010-11-22 22:31:00146
147 // TODO(shess): Port to Linux.
148#if defined(OS_MACOSX)
149 // TODO(shess): Port to 64-bit.
150#if ARCH_CPU_32_BITS
151 char buf[1024];
152 size_t len;
153
154 // NOTE: Even |snprintf()| is not on the approved list for signal
155 // handlers, but buffered I/O is definitely not on the list due to
156 // potential for |malloc()|.
157 len = static_cast<size_t>(
158 snprintf(buf, sizeof(buf),
159 "ax: %x, bx: %x, cx: %x, dx: %x\n",
160 context->uc_mcontext->__ss.__eax,
161 context->uc_mcontext->__ss.__ebx,
162 context->uc_mcontext->__ss.__ecx,
163 context->uc_mcontext->__ss.__edx));
164 write(STDERR_FILENO, buf, std::min(len, sizeof(buf) - 1));
165
166 len = static_cast<size_t>(
167 snprintf(buf, sizeof(buf),
168 "di: %x, si: %x, bp: %x, sp: %x, ss: %x, flags: %x\n",
169 context->uc_mcontext->__ss.__edi,
170 context->uc_mcontext->__ss.__esi,
171 context->uc_mcontext->__ss.__ebp,
172 context->uc_mcontext->__ss.__esp,
173 context->uc_mcontext->__ss.__ss,
174 context->uc_mcontext->__ss.__eflags));
175 write(STDERR_FILENO, buf, std::min(len, sizeof(buf) - 1));
176
177 len = static_cast<size_t>(
178 snprintf(buf, sizeof(buf),
179 "ip: %x, cs: %x, ds: %x, es: %x, fs: %x, gs: %x\n",
180 context->uc_mcontext->__ss.__eip,
181 context->uc_mcontext->__ss.__cs,
182 context->uc_mcontext->__ss.__ds,
183 context->uc_mcontext->__ss.__es,
184 context->uc_mcontext->__ss.__fs,
185 context->uc_mcontext->__ss.__gs));
186 write(STDERR_FILENO, buf, std::min(len, sizeof(buf) - 1));
187#endif // ARCH_CPU_32_BITS
188#endif // defined(OS_MACOSX)
[email protected]d6fc9fd2009-10-27 18:03:47189 _exit(1);
190}
[email protected]1e932112011-06-29 20:53:22191#endif // !defined(OS_ANDROID)
[email protected]d6fc9fd2009-10-27 18:03:47192
[email protected]620a0032010-09-04 02:32:59193void ResetChildSignalHandlersToDefaults() {
194 // The previous signal handlers are likely to be meaningless in the child's
195 // context so we reset them to the defaults for now. http://crbug.com/44953
[email protected]b25e61d2011-08-23 09:02:01196 // These signal handlers are set up at least in browser_main_posix.cc:
197 // BrowserMainPartsPosix::PreEarlyInitialization and process_util_posix.cc:
198 // EnableInProcessStackDumping.
[email protected]620a0032010-09-04 02:32:59199 signal(SIGHUP, SIG_DFL);
200 signal(SIGINT, SIG_DFL);
[email protected]ff09a4f2011-04-08 13:42:04201 signal(SIGILL, SIG_DFL);
202 signal(SIGABRT, SIG_DFL);
203 signal(SIGFPE, SIG_DFL);
204 signal(SIGBUS, SIG_DFL);
205 signal(SIGSEGV, SIG_DFL);
206 signal(SIGSYS, SIG_DFL);
207 signal(SIGTERM, SIG_DFL);
[email protected]620a0032010-09-04 02:32:59208}
209
[email protected]fa289832010-03-19 20:30:30210} // anonymous namespace
[email protected]d6fc9fd2009-10-27 18:03:47211
[email protected]43cf3252009-04-01 09:19:37212ProcessId GetCurrentProcId() {
[email protected]3d5617e2008-08-27 14:36:19213 return getpid();
214}
215
[email protected]113ab132008-09-18 20:42:55216ProcessHandle GetCurrentProcessHandle() {
217 return GetCurrentProcId();
218}
219
[email protected]6c6cc802009-04-03 17:01:36220bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) {
[email protected]5986ed22009-02-06 00:19:17221 // On Posix platforms, process handles are the same as PIDs, so we
222 // don't need to do anything.
[email protected]6c6cc802009-04-03 17:01:36223 *handle = pid;
224 return true;
[email protected]5986ed22009-02-06 00:19:17225}
226
[email protected]5d438dbad2009-04-30 08:59:39227bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) {
228 // On POSIX permissions are checked for each operation on process,
229 // not when opening a "handle".
230 return OpenProcessHandle(pid, handle);
231}
232
[email protected]7d11f6d52010-10-12 21:44:23233bool OpenProcessHandleWithAccess(ProcessId pid,
234 uint32 access_flags,
235 ProcessHandle* handle) {
236 // On POSIX permissions are checked for each operation on process,
237 // not when opening a "handle".
238 return OpenProcessHandle(pid, handle);
239}
240
[email protected]5986ed22009-02-06 00:19:17241void CloseProcessHandle(ProcessHandle process) {
242 // See OpenProcessHandle, nothing to do.
243 return;
244}
245
[email protected]43cf3252009-04-01 09:19:37246ProcessId GetProcId(ProcessHandle process) {
[email protected]fadb8ea2008-08-27 15:36:37247 return process;
[email protected]3d5617e2008-08-27 14:36:19248}
[email protected]fadb8ea2008-08-27 15:36:37249
[email protected]8cf7cebd2009-01-05 19:53:30250// Attempts to kill the process identified by the given process
251// entry structure. Ignores specified exit_code; posix can't force that.
252// Returns true if this is successful, false otherwise.
[email protected]cd4fd152009-02-09 19:28:41253bool KillProcess(ProcessHandle process_id, int exit_code, bool wait) {
[email protected]9610ef242009-11-18 02:41:26254 DCHECK_GT(process_id, 1) << " tried to kill invalid process_id";
255 if (process_id <= 1)
[email protected]9fd697a2009-07-07 14:00:59256 return false;
[email protected]140a7cd2009-04-28 01:37:23257 bool result = kill(process_id, SIGTERM) == 0;
[email protected]140a7cd2009-04-28 01:37:23258 if (result && wait) {
[email protected]8cf7cebd2009-01-05 19:53:30259 int tries = 60;
[email protected]2f7a6ea2011-06-18 11:49:27260
261 if (RunningOnValgrind()) {
262 // Wait for some extra time when running under Valgrind since the child
263 // processes may take some time doing leak checking.
264 tries *= 2;
265 }
266
[email protected]2e58cbd2012-08-06 01:03:05267 unsigned sleep_ms = 4;
268
[email protected]8cf7cebd2009-01-05 19:53:30269 // The process may not end immediately due to pending I/O
[email protected]d24423742009-07-13 23:31:28270 bool exited = false;
[email protected]8cf7cebd2009-01-05 19:53:30271 while (tries-- > 0) {
[email protected]a4dc33f2009-10-20 15:09:55272 pid_t pid = HANDLE_EINTR(waitpid(process_id, NULL, WNOHANG));
[email protected]d24423742009-07-13 23:31:28273 if (pid == process_id) {
274 exited = true;
[email protected]8cf7cebd2009-01-05 19:53:30275 break;
[email protected]d24423742009-07-13 23:31:28276 }
[email protected]bf4878d2010-06-16 20:12:01277 if (pid == -1) {
278 if (errno == ECHILD) {
279 // The wait may fail with ECHILD if another process also waited for
280 // the same pid, causing the process state to get cleaned up.
281 exited = true;
282 break;
283 }
284 DPLOG(ERROR) << "Error waiting for process " << process_id;
285 }
[email protected]140a7cd2009-04-28 01:37:23286
[email protected]f2d2ec22010-08-13 15:13:04287 usleep(sleep_ms * 1000);
[email protected]2e58cbd2012-08-06 01:03:05288 const unsigned kMaxSleepMs = 1000;
[email protected]f2d2ec22010-08-13 15:13:04289 if (sleep_ms < kMaxSleepMs)
290 sleep_ms *= 2;
[email protected]8cf7cebd2009-01-05 19:53:30291 }
[email protected]140a7cd2009-04-28 01:37:23292
[email protected]443b80e2010-12-14 00:42:23293 // If we're waiting and the child hasn't died by now, force it
294 // with a SIGKILL.
[email protected]32cd5302009-11-20 19:30:59295 if (!exited)
[email protected]d24423742009-07-13 23:31:28296 result = kill(process_id, SIGKILL) == 0;
[email protected]8cf7cebd2009-01-05 19:53:30297 }
[email protected]140a7cd2009-04-28 01:37:23298
[email protected]32cd5302009-11-20 19:30:59299 if (!result)
300 DPLOG(ERROR) << "Unable to terminate process " << process_id;
[email protected]140a7cd2009-04-28 01:37:23301
[email protected]8cf7cebd2009-01-05 19:53:30302 return result;
303}
304
[email protected]61b93f88f2010-09-22 17:28:30305bool KillProcessGroup(ProcessHandle process_group_id) {
306 bool result = kill(-1 * process_group_id, SIGKILL) == 0;
307 if (!result)
[email protected]a42d4632011-10-26 21:48:00308 DPLOG(ERROR) << "Unable to terminate process group " << process_group_id;
[email protected]61b93f88f2010-09-22 17:28:30309 return result;
310}
311
[email protected]05d4b0a2009-01-29 17:51:51312// A class to handle auto-closing of DIR*'s.
313class ScopedDIRClose {
314 public:
315 inline void operator()(DIR* x) const {
316 if (x) {
317 closedir(x);
318 }
319 }
320};
321typedef scoped_ptr_malloc<DIR, ScopedDIRClose> ScopedDIR;
322
[email protected]aec92f832009-05-06 16:40:12323#if defined(OS_LINUX)
324 static const rlim_t kSystemDefaultMaxFds = 8192;
[email protected]ef73044e2010-03-11 15:25:54325 static const char kFDDir[] = "/proc/self/fd";
[email protected]aec92f832009-05-06 16:40:12326#elif defined(OS_MACOSX)
327 static const rlim_t kSystemDefaultMaxFds = 256;
[email protected]ef73044e2010-03-11 15:25:54328 static const char kFDDir[] = "/dev/fd";
[email protected]a1208912010-02-17 14:15:08329#elif defined(OS_SOLARIS)
330 static const rlim_t kSystemDefaultMaxFds = 8192;
[email protected]ef73044e2010-03-11 15:25:54331 static const char kFDDir[] = "/dev/fd";
[email protected]4a34ce02009-08-31 22:25:00332#elif defined(OS_FREEBSD)
333 static const rlim_t kSystemDefaultMaxFds = 8192;
[email protected]ef73044e2010-03-11 15:25:54334 static const char kFDDir[] = "/dev/fd";
[email protected]8d578822010-01-25 23:54:54335#elif defined(OS_OPENBSD)
336 static const rlim_t kSystemDefaultMaxFds = 256;
[email protected]ef73044e2010-03-11 15:25:54337 static const char kFDDir[] = "/dev/fd";
[email protected]1e932112011-06-29 20:53:22338#elif defined(OS_ANDROID)
339 static const rlim_t kSystemDefaultMaxFds = 1024;
340 static const char kFDDir[] = "/proc/self/fd";
[email protected]aec92f832009-05-06 16:40:12341#endif
[email protected]ef73044e2010-03-11 15:25:54342
343void CloseSuperfluousFds(const base::InjectiveMultimap& saved_mapping) {
344 // DANGER: no calls to malloc are allowed from now on:
345 // http://crbug.com/36678
[email protected]3f04f2b2009-04-30 19:40:03346
[email protected]aec92f832009-05-06 16:40:12347 // Get the maximum number of FDs possible.
348 struct rlimit nofile;
349 rlim_t max_fds;
350 if (getrlimit(RLIMIT_NOFILE, &nofile)) {
351 // getrlimit failed. Take a best guess.
352 max_fds = kSystemDefaultMaxFds;
[email protected]ff09a4f2011-04-08 13:42:04353 RAW_LOG(ERROR, "getrlimit(RLIMIT_NOFILE) failed");
[email protected]aec92f832009-05-06 16:40:12354 } else {
355 max_fds = nofile.rlim_cur;
356 }
357
358 if (max_fds > INT_MAX)
359 max_fds = INT_MAX;
360
[email protected]ef73044e2010-03-11 15:25:54361 DirReaderPosix fd_dir(kFDDir);
[email protected]3f04f2b2009-04-30 19:40:03362
[email protected]ef73044e2010-03-11 15:25:54363 if (!fd_dir.IsValid()) {
[email protected]aec92f832009-05-06 16:40:12364 // Fallback case: Try every possible fd.
365 for (rlim_t i = 0; i < max_fds; ++i) {
[email protected]3f04f2b2009-04-30 19:40:03366 const int fd = static_cast<int>(i);
[email protected]ef73044e2010-03-11 15:25:54367 if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO)
368 continue;
[email protected]40350b12010-03-30 17:29:27369 InjectiveMultimap::const_iterator j;
370 for (j = saved_mapping.begin(); j != saved_mapping.end(); j++) {
371 if (fd == j->dest)
[email protected]ef73044e2010-03-11 15:25:54372 break;
373 }
[email protected]40350b12010-03-30 17:29:27374 if (j != saved_mapping.end())
[email protected]3f04f2b2009-04-30 19:40:03375 continue;
376
[email protected]cabe39c2010-02-02 02:28:16377 // Since we're just trying to close anything we can find,
378 // ignore any error return values of close().
[email protected]ff09a4f2011-04-08 13:42:04379 ignore_result(HANDLE_EINTR(close(fd)));
[email protected]3f04f2b2009-04-30 19:40:03380 }
381 return;
382 }
383
[email protected]ef73044e2010-03-11 15:25:54384 const int dir_fd = fd_dir.fd();
385
386 for ( ; fd_dir.Next(); ) {
[email protected]3f04f2b2009-04-30 19:40:03387 // Skip . and .. entries.
[email protected]ef73044e2010-03-11 15:25:54388 if (fd_dir.name()[0] == '.')
[email protected]3f04f2b2009-04-30 19:40:03389 continue;
390
391 char *endptr;
392 errno = 0;
[email protected]ef73044e2010-03-11 15:25:54393 const long int fd = strtol(fd_dir.name(), &endptr, 10);
394 if (fd_dir.name()[0] == 0 || *endptr || fd < 0 || errno)
[email protected]3f04f2b2009-04-30 19:40:03395 continue;
[email protected]ef73044e2010-03-11 15:25:54396 if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO)
397 continue;
398 InjectiveMultimap::const_iterator i;
399 for (i = saved_mapping.begin(); i != saved_mapping.end(); i++) {
400 if (fd == i->dest)
401 break;
402 }
403 if (i != saved_mapping.end())
[email protected]3f04f2b2009-04-30 19:40:03404 continue;
[email protected]699de0b2009-06-07 23:03:08405 if (fd == dir_fd)
406 continue;
[email protected]3f04f2b2009-04-30 19:40:03407
[email protected]aec92f832009-05-06 16:40:12408 // When running under Valgrind, Valgrind opens several FDs for its
409 // own use and will complain if we try to close them. All of
410 // these FDs are >= |max_fds|, so we can check against that here
411 // before closing. See https://bugs.kde.org/show_bug.cgi?id=191758
[email protected]cabe39c2010-02-02 02:28:16412 if (fd < static_cast<int>(max_fds)) {
413 int ret = HANDLE_EINTR(close(fd));
414 DPCHECK(ret == 0);
415 }
[email protected]3f04f2b2009-04-30 19:40:03416 }
417}
418
[email protected]a82af392012-02-24 04:40:20419char** AlterEnvironment(const EnvironmentVector& changes,
[email protected]ef73044e2010-03-11 15:25:54420 const char* const* const env) {
421 unsigned count = 0;
422 unsigned size = 0;
423
424 // First assume that all of the current environment will be included.
425 for (unsigned i = 0; env[i]; i++) {
426 const char *const pair = env[i];
427 count++;
428 size += strlen(pair) + 1 /* terminating NUL */;
429 }
430
[email protected]a82af392012-02-24 04:40:20431 for (EnvironmentVector::const_iterator j = changes.begin();
432 j != changes.end();
433 ++j) {
[email protected]ef73044e2010-03-11 15:25:54434 bool found = false;
435 const char *pair;
436
437 for (unsigned i = 0; env[i]; i++) {
438 pair = env[i];
439 const char *const equals = strchr(pair, '=');
440 if (!equals)
441 continue;
442 const unsigned keylen = equals - pair;
443 if (keylen == j->first.size() &&
444 memcmp(pair, j->first.data(), keylen) == 0) {
445 found = true;
446 break;
447 }
448 }
449
450 // if found, we'll either be deleting or replacing this element.
451 if (found) {
452 count--;
453 size -= strlen(pair) + 1;
454 if (j->second.size())
455 found = false;
456 }
457
458 // if !found, then we have a new element to add.
[email protected]6775e40a2011-03-04 21:03:47459 if (!found && !j->second.empty()) {
[email protected]ef73044e2010-03-11 15:25:54460 count++;
461 size += j->first.size() + 1 /* '=' */ + j->second.size() + 1 /* NUL */;
462 }
463 }
464
465 count++; // for the final NULL
466 uint8_t *buffer = new uint8_t[sizeof(char*) * count + size];
467 char **const ret = reinterpret_cast<char**>(buffer);
468 unsigned k = 0;
469 char *scratch = reinterpret_cast<char*>(buffer + sizeof(char*) * count);
470
471 for (unsigned i = 0; env[i]; i++) {
472 const char *const pair = env[i];
473 const char *const equals = strchr(pair, '=');
474 if (!equals) {
475 const unsigned len = strlen(pair);
476 ret[k++] = scratch;
477 memcpy(scratch, pair, len + 1);
478 scratch += len + 1;
479 continue;
480 }
481 const unsigned keylen = equals - pair;
482 bool handled = false;
[email protected]a82af392012-02-24 04:40:20483 for (EnvironmentVector::const_iterator
[email protected]ef73044e2010-03-11 15:25:54484 j = changes.begin(); j != changes.end(); j++) {
485 if (j->first.size() == keylen &&
486 memcmp(j->first.data(), pair, keylen) == 0) {
487 if (!j->second.empty()) {
488 ret[k++] = scratch;
489 memcpy(scratch, pair, keylen + 1);
490 scratch += keylen + 1;
491 memcpy(scratch, j->second.c_str(), j->second.size() + 1);
492 scratch += j->second.size() + 1;
493 }
494 handled = true;
495 break;
496 }
497 }
498
499 if (!handled) {
500 const unsigned len = strlen(pair);
501 ret[k++] = scratch;
502 memcpy(scratch, pair, len + 1);
503 scratch += len + 1;
504 }
505 }
506
507 // Now handle new elements
[email protected]a82af392012-02-24 04:40:20508 for (EnvironmentVector::const_iterator
[email protected]ef73044e2010-03-11 15:25:54509 j = changes.begin(); j != changes.end(); j++) {
[email protected]f6b8ce32011-03-02 00:03:18510 if (j->second.empty())
[email protected]ef73044e2010-03-11 15:25:54511 continue;
512
513 bool found = false;
514 for (unsigned i = 0; env[i]; i++) {
515 const char *const pair = env[i];
516 const char *const equals = strchr(pair, '=');
517 if (!equals)
518 continue;
519 const unsigned keylen = equals - pair;
520 if (keylen == j->first.size() &&
521 memcmp(pair, j->first.data(), keylen) == 0) {
522 found = true;
523 break;
524 }
525 }
526
527 if (!found) {
528 ret[k++] = scratch;
529 memcpy(scratch, j->first.data(), j->first.size());
530 scratch += j->first.size();
531 *scratch++ = '=';
532 memcpy(scratch, j->second.c_str(), j->second.size() + 1);
533 scratch += j->second.size() + 1;
534 }
535 }
536
537 ret[k] = NULL;
538 return ret;
539}
540
[email protected]898a81a2011-06-30 22:56:15541bool LaunchProcess(const std::vector<std::string>& argv,
[email protected]e5992182011-07-15 16:47:02542 const LaunchOptions& options,
543 ProcessHandle* process_handle) {
[email protected]84b2d1d2011-09-01 21:44:24544 size_t fd_shuffle_size = 0;
[email protected]898a81a2011-06-30 22:56:15545 if (options.fds_to_remap) {
[email protected]84b2d1d2011-09-01 21:44:24546 fd_shuffle_size = options.fds_to_remap->size();
[email protected]898a81a2011-06-30 22:56:15547 }
[email protected]84b2d1d2011-09-01 21:44:24548
549#if defined(OS_MACOSX)
550 if (options.synchronize) {
551 // When synchronizing, the "read" end of the synchronization pipe needs
552 // to make it to the child process. This is handled by mapping it back to
553 // itself.
554 ++fd_shuffle_size;
555 }
556#endif // defined(OS_MACOSX)
557
558 InjectiveMultimap fd_shuffle1;
559 InjectiveMultimap fd_shuffle2;
560 fd_shuffle1.reserve(fd_shuffle_size);
561 fd_shuffle2.reserve(fd_shuffle_size);
562
[email protected]ef73044e2010-03-11 15:25:54563 scoped_array<char*> argv_cstr(new char*[argv.size() + 1]);
[email protected]898a81a2011-06-30 22:56:15564 scoped_array<char*> new_environ;
565 if (options.environ)
566 new_environ.reset(AlterEnvironment(*options.environ, GetEnvironment()));
[email protected]ef73044e2010-03-11 15:25:54567
[email protected]84b2d1d2011-09-01 21:44:24568#if defined(OS_MACOSX)
569 int synchronization_pipe_fds[2];
570 file_util::ScopedFD synchronization_read_fd;
571 file_util::ScopedFD synchronization_write_fd;
572
573 if (options.synchronize) {
574 // wait means "don't return from LaunchProcess until the child exits", and
575 // synchronize means "return from LaunchProcess but don't let the child
576 // run until LaunchSynchronize is called". These two options are highly
577 // incompatible.
[email protected]a42d4632011-10-26 21:48:00578 DCHECK(!options.wait);
[email protected]84b2d1d2011-09-01 21:44:24579
580 // Create the pipe used for synchronization.
581 if (HANDLE_EINTR(pipe(synchronization_pipe_fds)) != 0) {
[email protected]a42d4632011-10-26 21:48:00582 DPLOG(ERROR) << "pipe";
[email protected]84b2d1d2011-09-01 21:44:24583 return false;
584 }
585
586 // The parent process will only use synchronization_write_fd as the write
587 // side of the pipe. It can close the read side as soon as the child
588 // process has forked off. The child process will only use
589 // synchronization_read_fd as the read side of the pipe. In that process,
590 // the write side can be closed as soon as it has forked.
591 synchronization_read_fd.reset(&synchronization_pipe_fds[0]);
592 synchronization_write_fd.reset(&synchronization_pipe_fds[1]);
593 }
594#endif // OS_MACOSX
595
596 pid_t pid;
[email protected]ca7c4562011-07-15 23:55:21597#if defined(OS_LINUX)
[email protected]84b2d1d2011-09-01 21:44:24598 if (options.clone_flags) {
[email protected]ca7c4562011-07-15 23:55:21599 pid = syscall(__NR_clone, options.clone_flags, 0, 0, 0);
[email protected]84b2d1d2011-09-01 21:44:24600 } else
[email protected]ca7c4562011-07-15 23:55:21601#endif
[email protected]84b2d1d2011-09-01 21:44:24602 {
[email protected]ca7c4562011-07-15 23:55:21603 pid = fork();
604 }
[email protected]84b2d1d2011-09-01 21:44:24605
[email protected]56f0f262011-02-24 17:14:36606 if (pid < 0) {
[email protected]a42d4632011-10-26 21:48:00607 DPLOG(ERROR) << "fork";
[email protected]2aea9e092009-08-06 20:03:01608 return false;
[email protected]84b2d1d2011-09-01 21:44:24609 } else if (pid == 0) {
[email protected]2aea9e092009-08-06 20:03:01610 // Child process
[email protected]61b93f88f2010-09-22 17:28:30611
[email protected]ff09a4f2011-04-08 13:42:04612 // DANGER: fork() rule: in the child, if you don't end up doing exec*(),
613 // you call _exit() instead of exit(). This is because _exit() does not
614 // call any previously-registered (in the parent) exit handlers, which
615 // might do things like block waiting for threads that don't even exist
616 // in the child.
617
[email protected]955b7392011-03-09 00:49:20618 // If a child process uses the readline library, the process block forever.
619 // In BSD like OSes including OS X it is safe to assign /dev/null as stdin.
620 // See http://crbug.com/56596.
621 int null_fd = HANDLE_EINTR(open("/dev/null", O_RDONLY));
622 if (null_fd < 0) {
[email protected]ff09a4f2011-04-08 13:42:04623 RAW_LOG(ERROR, "Failed to open /dev/null");
624 _exit(127);
625 }
626
627 file_util::ScopedFD null_fd_closer(&null_fd);
628 int new_fd = HANDLE_EINTR(dup2(null_fd, STDIN_FILENO));
629 if (new_fd != STDIN_FILENO) {
630 RAW_LOG(ERROR, "Failed to dup /dev/null for stdin");
631 _exit(127);
[email protected]955b7392011-03-09 00:49:20632 }
633
[email protected]898a81a2011-06-30 22:56:15634 if (options.new_process_group) {
[email protected]61b93f88f2010-09-22 17:28:30635 // Instead of inheriting the process group ID of the parent, the child
636 // starts off a new process group with pgid equal to its process ID.
[email protected]56f0f262011-02-24 17:14:36637 if (setpgid(0, 0) < 0) {
[email protected]ff09a4f2011-04-08 13:42:04638 RAW_LOG(ERROR, "setpgid failed");
639 _exit(127);
[email protected]56f0f262011-02-24 17:14:36640 }
[email protected]61b93f88f2010-09-22 17:28:30641 }
[email protected]84b2d1d2011-09-01 21:44:24642
[email protected]7ce58b22012-09-26 05:17:25643 // Stop type-profiler.
644 // The profiler should be stopped between fork and exec since it inserts
645 // locks at new/delete expressions. See http://crbug.com/36678.
646 base::type_profiler::Controller::Stop();
647
[email protected]77540fdf2011-11-15 18:49:10648 if (options.maximize_rlimits) {
649 // Some resource limits need to be maximal in this child.
650 std::set<int>::const_iterator resource;
651 for (resource = options.maximize_rlimits->begin();
652 resource != options.maximize_rlimits->end();
653 ++resource) {
654 struct rlimit limit;
655 if (getrlimit(*resource, &limit) < 0) {
656 RAW_LOG(WARNING, "getrlimit failed");
657 } else if (limit.rlim_cur < limit.rlim_max) {
658 limit.rlim_cur = limit.rlim_max;
659 if (setrlimit(*resource, &limit) < 0) {
660 RAW_LOG(WARNING, "setrlimit failed");
661 }
662 }
663 }
664 }
665
[email protected]e9a8c19f2009-09-03 21:27:36666#if defined(OS_MACOSX)
667 RestoreDefaultExceptionHandler();
[email protected]84b2d1d2011-09-01 21:44:24668#endif // defined(OS_MACOSX)
[email protected]e9a8c19f2009-09-03 21:27:36669
[email protected]620a0032010-09-04 02:32:59670 ResetChildSignalHandlersToDefaults();
[email protected]01aa3cd2010-06-02 18:47:55671
[email protected]84b2d1d2011-09-01 21:44:24672#if defined(OS_MACOSX)
673 if (options.synchronize) {
674 // The "write" side of the synchronization pipe belongs to the parent.
675 synchronization_write_fd.reset(); // closes synchronization_pipe_fds[1]
676 }
677#endif // defined(OS_MACOSX)
678
[email protected]ef73044e2010-03-11 15:25:54679#if 0
680 // When debugging it can be helpful to check that we really aren't making
681 // any hidden calls to malloc.
682 void *malloc_thunk =
683 reinterpret_cast<void*>(reinterpret_cast<intptr_t>(malloc) & ~4095);
684 mprotect(malloc_thunk, 4096, PROT_READ | PROT_WRITE | PROT_EXEC);
685 memset(reinterpret_cast<void*>(malloc), 0xff, 8);
[email protected]84b2d1d2011-09-01 21:44:24686#endif // 0
[email protected]ef73044e2010-03-11 15:25:54687
688 // DANGER: no calls to malloc are allowed from now on:
689 // http://crbug.com/36678
690
[email protected]927054d2012-01-21 01:48:25691#if defined(OS_CHROMEOS)
692 if (options.ctrl_terminal_fd >= 0) {
693 // Set process' controlling terminal.
694 if (HANDLE_EINTR(setsid()) != -1) {
695 if (HANDLE_EINTR(
696 ioctl(options.ctrl_terminal_fd, TIOCSCTTY, NULL)) == -1) {
697 RAW_LOG(WARNING, "ioctl(TIOCSCTTY), ctrl terminal not set");
698 }
699 } else {
700 RAW_LOG(WARNING, "setsid failed, ctrl terminal not set");
701 }
702 }
703#endif // defined(OS_CHROMEOS)
704
[email protected]898a81a2011-06-30 22:56:15705 if (options.fds_to_remap) {
[email protected]a82af392012-02-24 04:40:20706 for (FileHandleMappingVector::const_iterator
[email protected]898a81a2011-06-30 22:56:15707 it = options.fds_to_remap->begin();
708 it != options.fds_to_remap->end(); ++it) {
709 fd_shuffle1.push_back(InjectionArc(it->first, it->second, false));
710 fd_shuffle2.push_back(InjectionArc(it->first, it->second, false));
711 }
[email protected]e6572302009-08-21 17:05:54712 }
[email protected]2aea9e092009-08-06 20:03:01713
[email protected]84b2d1d2011-09-01 21:44:24714#if defined(OS_MACOSX)
715 if (options.synchronize) {
716 // Remap the read side of the synchronization pipe back onto itself,
717 // ensuring that it won't be closed by CloseSuperfluousFds.
718 int keep_fd = *synchronization_read_fd.get();
719 fd_shuffle1.push_back(InjectionArc(keep_fd, keep_fd, false));
720 fd_shuffle2.push_back(InjectionArc(keep_fd, keep_fd, false));
721 }
722#endif // defined(OS_MACOSX)
723
[email protected]898a81a2011-06-30 22:56:15724 if (options.environ)
725 SetEnvironment(new_environ.get());
[email protected]2aea9e092009-08-06 20:03:01726
[email protected]ef73044e2010-03-11 15:25:54727 // fd_shuffle1 is mutated by this call because it cannot malloc.
728 if (!ShuffleFileDescriptors(&fd_shuffle1))
[email protected]2aea9e092009-08-06 20:03:01729 _exit(127);
730
[email protected]ef73044e2010-03-11 15:25:54731 CloseSuperfluousFds(fd_shuffle2);
[email protected]e6572302009-08-21 17:05:54732
[email protected]84b2d1d2011-09-01 21:44:24733#if defined(OS_MACOSX)
734 if (options.synchronize) {
735 // Do a blocking read to wait until the parent says it's OK to proceed.
736 // The byte that's read here is written by LaunchSynchronize.
737 char read_char;
738 int read_result =
739 HANDLE_EINTR(read(*synchronization_read_fd.get(), &read_char, 1));
740 if (read_result != 1) {
741 RAW_LOG(ERROR, "LaunchProcess: synchronization read: error");
742 _exit(127);
743 }
744
745 // The pipe is no longer useful. Don't let it live on in the new process
746 // after exec.
747 synchronization_read_fd.reset(); // closes synchronization_pipe_fds[0]
748 }
749#endif // defined(OS_MACOSX)
750
[email protected]e6572302009-08-21 17:05:54751 for (size_t i = 0; i < argv.size(); i++)
752 argv_cstr[i] = const_cast<char*>(argv[i].c_str());
753 argv_cstr[argv.size()] = NULL;
[email protected]2aea9e092009-08-06 20:03:01754 execvp(argv_cstr[0], argv_cstr.get());
[email protected]84b2d1d2011-09-01 21:44:24755
[email protected]075fb932011-07-19 16:31:28756 RAW_LOG(ERROR, "LaunchProcess: failed to execvp:");
[email protected]ef73044e2010-03-11 15:25:54757 RAW_LOG(ERROR, argv_cstr[0]);
[email protected]2aea9e092009-08-06 20:03:01758 _exit(127);
759 } else {
760 // Parent process
[email protected]898a81a2011-06-30 22:56:15761 if (options.wait) {
[email protected]b42c4652010-12-04 03:23:53762 // While this isn't strictly disk IO, waiting for another process to
763 // finish is the sort of thing ThreadRestrictions is trying to prevent.
764 base::ThreadRestrictions::AssertIOAllowed();
[email protected]cabe39c2010-02-02 02:28:16765 pid_t ret = HANDLE_EINTR(waitpid(pid, 0, 0));
766 DPCHECK(ret > 0);
767 }
[email protected]2aea9e092009-08-06 20:03:01768
[email protected]e5992182011-07-15 16:47:02769 if (process_handle)
770 *process_handle = pid;
[email protected]84b2d1d2011-09-01 21:44:24771
772#if defined(OS_MACOSX)
773 if (options.synchronize) {
774 // The "read" side of the synchronization pipe belongs to the child.
775 synchronization_read_fd.reset(); // closes synchronization_pipe_fds[0]
776 *options.synchronize = new int(*synchronization_write_fd.release());
777 }
778#endif // defined(OS_MACOSX)
[email protected]2aea9e092009-08-06 20:03:01779 }
780
781 return true;
782}
783
[email protected]84b2d1d2011-09-01 21:44:24784
[email protected]898a81a2011-06-30 22:56:15785bool LaunchProcess(const CommandLine& cmdline,
[email protected]e5992182011-07-15 16:47:02786 const LaunchOptions& options,
787 ProcessHandle* process_handle) {
788 return LaunchProcess(cmdline.argv(), options, process_handle);
[email protected]2aea9e092009-08-06 20:03:01789}
790
[email protected]84b2d1d2011-09-01 21:44:24791#if defined(OS_MACOSX)
792void LaunchSynchronize(LaunchSynchronizationHandle handle) {
793 int synchronization_fd = *handle;
794 file_util::ScopedFD synchronization_fd_closer(&synchronization_fd);
795 delete handle;
796
797 // Write a '\0' character to the pipe.
798 if (HANDLE_EINTR(write(synchronization_fd, "", 1)) != 1) {
[email protected]a42d4632011-10-26 21:48:00799 DPLOG(ERROR) << "write";
[email protected]84b2d1d2011-09-01 21:44:24800 }
801}
802#endif // defined(OS_MACOSX)
803
[email protected]0b100bc8b2008-10-14 20:49:16804ProcessMetrics::~ProcessMetrics() { }
805
[email protected]d6fc9fd2009-10-27 18:03:47806bool EnableInProcessStackDumping() {
807 // When running in an application, our code typically expects SIGPIPE
808 // to be ignored. Therefore, when testing that same code, it should run
809 // with SIGPIPE ignored as well.
810 struct sigaction action;
[email protected]2db7a1e52012-03-30 22:19:32811 memset(&action, 0, sizeof(action));
[email protected]d6fc9fd2009-10-27 18:03:47812 action.sa_handler = SIG_IGN;
[email protected]d6fc9fd2009-10-27 18:03:47813 sigemptyset(&action.sa_mask);
814 bool success = (sigaction(SIGPIPE, &action, NULL) == 0);
815
[email protected]1e932112011-06-29 20:53:22816 // Android has built-in crash handling, so no need to hook the signals.
817#if !defined(OS_ANDROID)
[email protected]7e3edc22010-11-22 22:31:00818 sig_t handler = reinterpret_cast<sig_t>(&StackDumpSignalHandler);
819 success &= (signal(SIGILL, handler) != SIG_ERR);
820 success &= (signal(SIGABRT, handler) != SIG_ERR);
821 success &= (signal(SIGFPE, handler) != SIG_ERR);
822 success &= (signal(SIGBUS, handler) != SIG_ERR);
823 success &= (signal(SIGSEGV, handler) != SIG_ERR);
824 success &= (signal(SIGSYS, handler) != SIG_ERR);
[email protected]1e932112011-06-29 20:53:22825#endif
[email protected]7e868c962010-04-30 06:24:37826
[email protected]d6fc9fd2009-10-27 18:03:47827 return success;
828}
829
[email protected]3d5617e2008-08-27 14:36:19830void RaiseProcessToHighPriority() {
831 // On POSIX, we don't actually do anything here. We could try to nice() or
832 // setpriority() or sched_getscheduler, but these all require extra rights.
833}
834
[email protected]443b80e2010-12-14 00:42:23835TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) {
836 int status = 0;
[email protected]eaec38c2010-11-29 19:30:23837 const pid_t result = HANDLE_EINTR(waitpid(handle, &status, WNOHANG));
838 if (result == -1) {
[email protected]a42d4632011-10-26 21:48:00839 DPLOG(ERROR) << "waitpid(" << handle << ")";
[email protected]443b80e2010-12-14 00:42:23840 if (exit_code)
841 *exit_code = 0;
842 return TERMINATION_STATUS_NORMAL_TERMINATION;
[email protected]eaec38c2010-11-29 19:30:23843 } else if (result == 0) {
844 // the child hasn't exited yet.
[email protected]443b80e2010-12-14 00:42:23845 if (exit_code)
846 *exit_code = 0;
847 return TERMINATION_STATUS_STILL_RUNNING;
[email protected]9c19aa12009-01-21 13:50:11848 }
849
[email protected]443b80e2010-12-14 00:42:23850 if (exit_code)
851 *exit_code = status;
[email protected]140a7cd2009-04-28 01:37:23852
[email protected]9c19aa12009-01-21 13:50:11853 if (WIFSIGNALED(status)) {
[email protected]2fdc86a2010-01-26 23:08:02854 switch (WTERMSIG(status)) {
[email protected]22b61ba2010-10-19 18:25:47855 case SIGABRT:
[email protected]443b80e2010-12-14 00:42:23856 case SIGBUS:
[email protected]22b61ba2010-10-19 18:25:47857 case SIGFPE:
[email protected]443b80e2010-12-14 00:42:23858 case SIGILL:
859 case SIGSEGV:
860 return TERMINATION_STATUS_PROCESS_CRASHED;
861 case SIGINT:
862 case SIGKILL:
863 case SIGTERM:
864 return TERMINATION_STATUS_PROCESS_WAS_KILLED;
[email protected]9c19aa12009-01-21 13:50:11865 default:
[email protected]443b80e2010-12-14 00:42:23866 break;
[email protected]9c19aa12009-01-21 13:50:11867 }
868 }
869
[email protected]443b80e2010-12-14 00:42:23870 if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
871 return TERMINATION_STATUS_ABNORMAL_TERMINATION;
[email protected]9c19aa12009-01-21 13:50:11872
[email protected]443b80e2010-12-14 00:42:23873 return TERMINATION_STATUS_NORMAL_TERMINATION;
[email protected]9c19aa12009-01-21 13:50:11874}
875
[email protected]c7856632009-01-13 17:38:49876bool WaitForExitCode(ProcessHandle handle, int* exit_code) {
877 int status;
[email protected]157c61b2009-05-01 21:37:31878 if (HANDLE_EINTR(waitpid(handle, &status, 0)) == -1) {
879 NOTREACHED();
880 return false;
[email protected]c7856632009-01-13 17:38:49881 }
882
883 if (WIFEXITED(status)) {
884 *exit_code = WEXITSTATUS(status);
885 return true;
886 }
887
888 // If it didn't exit cleanly, it must have been signaled.
889 DCHECK(WIFSIGNALED(status));
890 return false;
891}
892
[email protected]8004e682010-03-16 07:41:22893bool WaitForExitCodeWithTimeout(ProcessHandle handle, int* exit_code,
[email protected]6a1eea82012-07-26 23:41:41894 base::TimeDelta timeout) {
[email protected]eaec38c2010-11-29 19:30:23895 bool waitpid_success = false;
[email protected]6a1eea82012-07-26 23:41:41896 int status = WaitpidWithTimeout(handle, timeout.InMilliseconds(),
[email protected]eaec38c2010-11-29 19:30:23897 &waitpid_success);
898 if (status == -1)
899 return false;
900 if (!waitpid_success)
[email protected]8004e682010-03-16 07:41:22901 return false;
[email protected]8004e682010-03-16 07:41:22902 if (WIFSIGNALED(status)) {
903 *exit_code = -1;
904 return true;
905 }
[email protected]40bbe592011-04-06 12:18:20906 if (WIFEXITED(status)) {
907 *exit_code = WEXITSTATUS(status);
908 return true;
909 }
910 return false;
[email protected]8004e682010-03-16 07:41:22911}
912
[email protected]56f0f262011-02-24 17:14:36913#if defined(OS_MACOSX)
914// Using kqueue on Mac so that we can wait on non-child processes.
915// We can't use kqueues on child processes because we need to reap
916// our own children using wait.
917static bool WaitForSingleNonChildProcess(ProcessHandle handle,
[email protected]7e1117c2012-03-31 20:42:41918 base::TimeDelta wait) {
[email protected]6d780fd52011-08-22 23:27:11919 DCHECK_GT(handle, 0);
[email protected]7e1117c2012-03-31 20:42:41920 DCHECK(wait.InMilliseconds() == base::kNoTimeout || wait > base::TimeDelta());
[email protected]6d780fd52011-08-22 23:27:11921
[email protected]56f0f262011-02-24 17:14:36922 int kq = kqueue();
923 if (kq == -1) {
[email protected]a42d4632011-10-26 21:48:00924 DPLOG(ERROR) << "kqueue";
[email protected]56f0f262011-02-24 17:14:36925 return false;
926 }
[email protected]6d780fd52011-08-22 23:27:11927 file_util::ScopedFD kq_closer(&kq);
[email protected]56f0f262011-02-24 17:14:36928
[email protected]6d780fd52011-08-22 23:27:11929 struct kevent change = {0};
[email protected]56f0f262011-02-24 17:14:36930 EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
[email protected]6d780fd52011-08-22 23:27:11931 int result = HANDLE_EINTR(kevent(kq, &change, 1, NULL, 0, NULL));
932 if (result == -1) {
933 if (errno == ESRCH) {
934 // If the process wasn't found, it must be dead.
935 return true;
936 }
[email protected]56f0f262011-02-24 17:14:36937
[email protected]a42d4632011-10-26 21:48:00938 DPLOG(ERROR) << "kevent (setup " << handle << ")";
[email protected]6d780fd52011-08-22 23:27:11939 return false;
[email protected]56f0f262011-02-24 17:14:36940 }
941
[email protected]6d780fd52011-08-22 23:27:11942 // Keep track of the elapsed time to be able to restart kevent if it's
943 // interrupted.
[email protected]7e1117c2012-03-31 20:42:41944 bool wait_forever = wait.InMilliseconds() == base::kNoTimeout;
[email protected]6d780fd52011-08-22 23:27:11945 base::TimeDelta remaining_delta;
946 base::Time deadline;
947 if (!wait_forever) {
[email protected]7e1117c2012-03-31 20:42:41948 remaining_delta = wait;
[email protected]6d780fd52011-08-22 23:27:11949 deadline = base::Time::Now() + remaining_delta;
950 }
951
952 result = -1;
953 struct kevent event = {0};
954
[email protected]7e1117c2012-03-31 20:42:41955 while (wait_forever || remaining_delta > base::TimeDelta()) {
[email protected]6d780fd52011-08-22 23:27:11956 struct timespec remaining_timespec;
957 struct timespec* remaining_timespec_ptr;
958 if (wait_forever) {
959 remaining_timespec_ptr = NULL;
[email protected]56f0f262011-02-24 17:14:36960 } else {
[email protected]6d780fd52011-08-22 23:27:11961 remaining_timespec = remaining_delta.ToTimeSpec();
962 remaining_timespec_ptr = &remaining_timespec;
963 }
964
965 result = kevent(kq, NULL, 0, &event, 1, remaining_timespec_ptr);
966
967 if (result == -1 && errno == EINTR) {
968 if (!wait_forever) {
969 remaining_delta = deadline - base::Time::Now();
970 }
971 result = 0;
972 } else {
973 break;
[email protected]56f0f262011-02-24 17:14:36974 }
975 }
[email protected]6d780fd52011-08-22 23:27:11976
977 if (result < 0) {
[email protected]a42d4632011-10-26 21:48:00978 DPLOG(ERROR) << "kevent (wait " << handle << ")";
[email protected]6d780fd52011-08-22 23:27:11979 return false;
980 } else if (result > 1) {
[email protected]a42d4632011-10-26 21:48:00981 DLOG(ERROR) << "kevent (wait " << handle << "): unexpected result "
982 << result;
[email protected]6d780fd52011-08-22 23:27:11983 return false;
984 } else if (result == 0) {
985 // Timed out.
986 return false;
987 }
988
989 DCHECK_EQ(result, 1);
990
991 if (event.filter != EVFILT_PROC ||
992 (event.fflags & NOTE_EXIT) == 0 ||
993 event.ident != static_cast<uintptr_t>(handle)) {
[email protected]a42d4632011-10-26 21:48:00994 DLOG(ERROR) << "kevent (wait " << handle
995 << "): unexpected event: filter=" << event.filter
996 << ", fflags=" << event.fflags
997 << ", ident=" << event.ident;
[email protected]6d780fd52011-08-22 23:27:11998 return false;
999 }
1000
1001 return true;
[email protected]56f0f262011-02-24 17:14:361002}
1003#endif // OS_MACOSX
1004
[email protected]7e1117c2012-03-31 20:42:411005bool WaitForSingleProcess(ProcessHandle handle, base::TimeDelta wait) {
[email protected]56f0f262011-02-24 17:14:361006 ProcessHandle parent_pid = GetParentProcessId(handle);
1007 ProcessHandle our_pid = Process::Current().handle();
1008 if (parent_pid != our_pid) {
1009#if defined(OS_MACOSX)
1010 // On Mac we can wait on non child processes.
[email protected]7e1117c2012-03-31 20:42:411011 return WaitForSingleNonChildProcess(handle, wait);
[email protected]56f0f262011-02-24 17:14:361012#else
1013 // Currently on Linux we can't handle non child processes.
1014 NOTIMPLEMENTED();
1015#endif // OS_MACOSX
1016 }
[email protected]6d780fd52011-08-22 23:27:111017
[email protected]eaec38c2010-11-29 19:30:231018 bool waitpid_success;
[email protected]6d780fd52011-08-22 23:27:111019 int status = -1;
[email protected]7e1117c2012-03-31 20:42:411020 if (wait.InMilliseconds() == base::kNoTimeout) {
[email protected]eaec38c2010-11-29 19:30:231021 waitpid_success = (HANDLE_EINTR(waitpid(handle, &status, 0)) != -1);
[email protected]7e1117c2012-03-31 20:42:411022 } else {
1023 status = WaitpidWithTimeout(
1024 handle, wait.InMilliseconds(), &waitpid_success);
1025 }
[email protected]6d780fd52011-08-22 23:27:111026
[email protected]eaec38c2010-11-29 19:30:231027 if (status != -1) {
1028 DCHECK(waitpid_success);
1029 return WIFEXITED(status);
[email protected]ef0279272009-03-06 09:24:381030 } else {
[email protected]774f2202010-11-29 18:56:191031 return false;
[email protected]eaec38c2010-11-29 19:30:231032 }
[email protected]076bf0b62009-03-04 20:57:581033}
1034
[email protected]0d83c732008-12-02 16:50:471035int64 TimeValToMicroseconds(const struct timeval& tv) {
[email protected]2d9bb0222010-04-02 08:24:011036 static const int kMicrosecondsPerSecond = 1000000;
1037 int64 ret = tv.tv_sec; // Avoid (int * int) integer overflow.
1038 ret *= kMicrosecondsPerSecond;
1039 ret += tv.tv_usec;
1040 return ret;
[email protected]0d83c732008-12-02 16:50:471041}
1042
[email protected]d03b05c2011-07-06 06:14:481043// Return value used by GetAppOutputInternal to encapsulate the various exit
1044// scenarios from the function.
1045enum GetAppOutputInternalResult {
1046 EXECUTE_FAILURE,
1047 EXECUTE_SUCCESS,
1048 GOT_MAX_OUTPUT,
1049};
1050
[email protected]1a6ec692012-04-26 20:24:371051// Executes the application specified by |argv| and wait for it to exit. Stores
[email protected]3b9f5aa2010-07-28 04:02:341052// the output (stdout) in |output|. If |do_search_path| is set, it searches the
[email protected]f164cea2009-11-05 23:37:401053// path for the application; in that case, |envp| must be null, and it will use
[email protected]1a6ec692012-04-26 20:24:371054// the current environment. If |do_search_path| is false, |argv[0]| should fully
[email protected]f164cea2009-11-05 23:37:401055// specify the path of the application, and |envp| will be used as the
[email protected]d03b05c2011-07-06 06:14:481056// environment. Redirects stderr to /dev/null.
1057// If we successfully start the application and get all requested output, we
1058// return GOT_MAX_OUTPUT, or if there is a problem starting or exiting
1059// the application we return RUN_FAILURE. Otherwise we return EXECUTE_SUCCESS.
1060// The GOT_MAX_OUTPUT return value exists so a caller that asks for limited
1061// output can treat this as a success, despite having an exit code of SIG_PIPE
1062// due to us closing the output pipe.
1063// In the case of EXECUTE_SUCCESS, the application exit code will be returned
1064// in |*exit_code|, which should be checked to determine if the application
1065// ran successfully.
[email protected]1a6ec692012-04-26 20:24:371066static GetAppOutputInternalResult GetAppOutputInternal(
1067 const std::vector<std::string>& argv,
1068 char* const envp[],
1069 std::string* output,
1070 size_t max_output,
1071 bool do_search_path,
1072 int* exit_code) {
[email protected]b42c4652010-12-04 03:23:531073 // Doing a blocking wait for another command to finish counts as IO.
1074 base::ThreadRestrictions::AssertIOAllowed();
[email protected]d03b05c2011-07-06 06:14:481075 // exit_code must be supplied so calling function can determine success.
1076 DCHECK(exit_code);
1077 *exit_code = EXIT_FAILURE;
[email protected]b42c4652010-12-04 03:23:531078
[email protected]c0b210ee2009-04-17 09:57:521079 int pipe_fd[2];
1080 pid_t pid;
[email protected]ef73044e2010-03-11 15:25:541081 InjectiveMultimap fd_shuffle1, fd_shuffle2;
[email protected]ef73044e2010-03-11 15:25:541082 scoped_array<char*> argv_cstr(new char*[argv.size() + 1]);
1083
1084 fd_shuffle1.reserve(3);
1085 fd_shuffle2.reserve(3);
[email protected]c0b210ee2009-04-17 09:57:521086
[email protected]f164cea2009-11-05 23:37:401087 // Either |do_search_path| should be false or |envp| should be null, but not
1088 // both.
1089 DCHECK(!do_search_path ^ !envp);
1090
[email protected]c0b210ee2009-04-17 09:57:521091 if (pipe(pipe_fd) < 0)
[email protected]d03b05c2011-07-06 06:14:481092 return EXECUTE_FAILURE;
[email protected]c0b210ee2009-04-17 09:57:521093
1094 switch (pid = fork()) {
1095 case -1: // error
1096 close(pipe_fd[0]);
1097 close(pipe_fd[1]);
[email protected]d03b05c2011-07-06 06:14:481098 return EXECUTE_FAILURE;
[email protected]c0b210ee2009-04-17 09:57:521099 case 0: // child
1100 {
[email protected]e9a8c19f2009-09-03 21:27:361101#if defined(OS_MACOSX)
1102 RestoreDefaultExceptionHandler();
1103#endif
[email protected]ef73044e2010-03-11 15:25:541104 // DANGER: no calls to malloc are allowed from now on:
1105 // http://crbug.com/36678
[email protected]e9a8c19f2009-09-03 21:27:361106
[email protected]afa82472009-07-23 19:11:481107 // Obscure fork() rule: in the child, if you don't end up doing exec*(),
1108 // you call _exit() instead of exit(). This is because _exit() does not
1109 // call any previously-registered (in the parent) exit handlers, which
1110 // might do things like block waiting for threads that don't even exist
1111 // in the child.
[email protected]1912cfe2009-04-21 08:09:301112 int dev_null = open("/dev/null", O_WRONLY);
1113 if (dev_null < 0)
[email protected]7a97d292009-07-22 18:21:271114 _exit(127);
[email protected]1912cfe2009-04-21 08:09:301115
[email protected]7ce58b22012-09-26 05:17:251116 // Stop type-profiler.
1117 // The profiler should be stopped between fork and exec since it inserts
1118 // locks at new/delete expressions. See http://crbug.com/36678.
1119 base::type_profiler::Controller::Stop();
1120
[email protected]ef73044e2010-03-11 15:25:541121 fd_shuffle1.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true));
1122 fd_shuffle1.push_back(InjectionArc(dev_null, STDERR_FILENO, true));
1123 fd_shuffle1.push_back(InjectionArc(dev_null, STDIN_FILENO, true));
[email protected]3b9f5aa2010-07-28 04:02:341124 // Adding another element here? Remeber to increase the argument to
[email protected]ef73044e2010-03-11 15:25:541125 // reserve(), above.
[email protected]3f04f2b2009-04-30 19:40:031126
[email protected]ef73044e2010-03-11 15:25:541127 std::copy(fd_shuffle1.begin(), fd_shuffle1.end(),
1128 std::back_inserter(fd_shuffle2));
1129
1130 if (!ShuffleFileDescriptors(&fd_shuffle1))
[email protected]7a97d292009-07-22 18:21:271131 _exit(127);
[email protected]3f04f2b2009-04-30 19:40:031132
[email protected]ef73044e2010-03-11 15:25:541133 CloseSuperfluousFds(fd_shuffle2);
[email protected]c0b210ee2009-04-17 09:57:521134
[email protected]c0b210ee2009-04-17 09:57:521135 for (size_t i = 0; i < argv.size(); i++)
1136 argv_cstr[i] = const_cast<char*>(argv[i].c_str());
1137 argv_cstr[argv.size()] = NULL;
[email protected]f164cea2009-11-05 23:37:401138 if (do_search_path)
1139 execvp(argv_cstr[0], argv_cstr.get());
1140 else
1141 execve(argv_cstr[0], argv_cstr.get(), envp);
[email protected]7a97d292009-07-22 18:21:271142 _exit(127);
[email protected]c0b210ee2009-04-17 09:57:521143 }
1144 default: // parent
1145 {
1146 // Close our writing end of pipe now. Otherwise later read would not
1147 // be able to detect end of child's output (in theory we could still
1148 // write to the pipe).
1149 close(pipe_fd[1]);
1150
[email protected]96878a212010-06-10 18:26:331151 output->clear();
[email protected]c0b210ee2009-04-17 09:57:521152 char buffer[256];
[email protected]983ef7f2010-01-04 16:17:131153 size_t output_buf_left = max_output;
[email protected]f164cea2009-11-05 23:37:401154 ssize_t bytes_read = 1; // A lie to properly handle |max_output == 0|
1155 // case in the logic below.
[email protected]c0b210ee2009-04-17 09:57:521156
[email protected]983ef7f2010-01-04 16:17:131157 while (output_buf_left > 0) {
[email protected]f164cea2009-11-05 23:37:401158 bytes_read = HANDLE_EINTR(read(pipe_fd[0], buffer,
[email protected]983ef7f2010-01-04 16:17:131159 std::min(output_buf_left, sizeof(buffer))));
[email protected]157c61b2009-05-01 21:37:311160 if (bytes_read <= 0)
[email protected]c0b210ee2009-04-17 09:57:521161 break;
[email protected]96878a212010-06-10 18:26:331162 output->append(buffer, bytes_read);
[email protected]983ef7f2010-01-04 16:17:131163 output_buf_left -= static_cast<size_t>(bytes_read);
[email protected]c0b210ee2009-04-17 09:57:521164 }
[email protected]c0b210ee2009-04-17 09:57:521165 close(pipe_fd[0]);
[email protected]affb1842009-06-10 16:56:311166
[email protected]d03b05c2011-07-06 06:14:481167 // Always wait for exit code (even if we know we'll declare
1168 // GOT_MAX_OUTPUT).
1169 bool success = WaitForExitCode(pid, exit_code);
[email protected]983ef7f2010-01-04 16:17:131170
[email protected]d03b05c2011-07-06 06:14:481171 // If we stopped because we read as much as we wanted, we return
1172 // GOT_MAX_OUTPUT (because the child may exit due to |SIGPIPE|).
1173 if (!output_buf_left && bytes_read > 0)
1174 return GOT_MAX_OUTPUT;
1175 else if (success)
1176 return EXECUTE_SUCCESS;
1177 return EXECUTE_FAILURE;
[email protected]c0b210ee2009-04-17 09:57:521178 }
1179 }
1180}
1181
[email protected]f164cea2009-11-05 23:37:401182bool GetAppOutput(const CommandLine& cl, std::string* output) {
[email protected]1a6ec692012-04-26 20:24:371183 return GetAppOutput(cl.argv(), output);
1184}
1185
1186bool GetAppOutput(const std::vector<std::string>& argv, std::string* output) {
[email protected]f164cea2009-11-05 23:37:401187 // Run |execve()| with the current environment and store "unlimited" data.
[email protected]d03b05c2011-07-06 06:14:481188 int exit_code;
1189 GetAppOutputInternalResult result = GetAppOutputInternal(
[email protected]1a6ec692012-04-26 20:24:371190 argv, NULL, output, std::numeric_limits<std::size_t>::max(), true,
[email protected]d03b05c2011-07-06 06:14:481191 &exit_code);
1192 return result == EXECUTE_SUCCESS && exit_code == EXIT_SUCCESS;
[email protected]f164cea2009-11-05 23:37:401193}
1194
[email protected]3b9f5aa2010-07-28 04:02:341195// TODO(viettrungluu): Conceivably, we should have a timeout as well, so we
1196// don't hang if what we're calling hangs.
[email protected]f164cea2009-11-05 23:37:401197bool GetAppOutputRestricted(const CommandLine& cl,
1198 std::string* output, size_t max_output) {
1199 // Run |execve()| with the empty environment.
1200 char* const empty_environ = NULL;
[email protected]d03b05c2011-07-06 06:14:481201 int exit_code;
[email protected]1a6ec692012-04-26 20:24:371202 GetAppOutputInternalResult result = GetAppOutputInternal(
1203 cl.argv(), &empty_environ, output, max_output, false, &exit_code);
[email protected]d03b05c2011-07-06 06:14:481204 return result == GOT_MAX_OUTPUT || (result == EXECUTE_SUCCESS &&
1205 exit_code == EXIT_SUCCESS);
1206}
1207
1208bool GetAppOutputWithExitCode(const CommandLine& cl,
1209 std::string* output,
1210 int* exit_code) {
1211 // Run |execve()| with the current environment and store "unlimited" data.
1212 GetAppOutputInternalResult result = GetAppOutputInternal(
[email protected]1a6ec692012-04-26 20:24:371213 cl.argv(), NULL, output, std::numeric_limits<std::size_t>::max(), true,
[email protected]d03b05c2011-07-06 06:14:481214 exit_code);
1215 return result == EXECUTE_SUCCESS;
[email protected]f164cea2009-11-05 23:37:401216}
1217
[email protected]4f260d02010-12-23 18:35:421218bool WaitForProcessesToExit(const FilePath::StringType& executable_name,
[email protected]6a1eea82012-07-26 23:41:411219 base::TimeDelta wait,
[email protected]962dd312009-02-05 21:44:131220 const ProcessFilter* filter) {
1221 bool result = false;
1222
1223 // TODO(port): This is inefficient, but works if there are multiple procs.
1224 // TODO(port): use waitpid to avoid leaving zombies around
1225
[email protected]6a1eea82012-07-26 23:41:411226 base::Time end_time = base::Time::Now() + wait;
[email protected]962dd312009-02-05 21:44:131227 do {
1228 NamedProcessIterator iter(executable_name, filter);
1229 if (!iter.NextProcessEntry()) {
1230 result = true;
1231 break;
1232 }
[email protected]a1b75b942011-12-31 22:53:511233 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
[email protected]1e932112011-06-29 20:53:221234 } while ((end_time - base::Time::Now()) > base::TimeDelta());
[email protected]962dd312009-02-05 21:44:131235
1236 return result;
1237}
1238
[email protected]4f260d02010-12-23 18:35:421239bool CleanupProcesses(const FilePath::StringType& executable_name,
[email protected]5387fdd22012-07-31 23:22:481240 base::TimeDelta wait,
[email protected]962dd312009-02-05 21:44:131241 int exit_code,
1242 const ProcessFilter* filter) {
[email protected]5387fdd22012-07-31 23:22:481243 bool exited_cleanly = WaitForProcessesToExit(executable_name, wait, filter);
[email protected]962dd312009-02-05 21:44:131244 if (!exited_cleanly)
1245 KillProcesses(executable_name, exit_code, filter);
1246 return exited_cleanly;
1247}
1248
[email protected]eaac71592011-11-23 18:32:001249#if !defined(OS_MACOSX)
1250
1251namespace {
1252
1253// Return true if the given child is dead. This will also reap the process.
1254// Doesn't block.
1255static bool IsChildDead(pid_t child) {
1256 const pid_t result = HANDLE_EINTR(waitpid(child, NULL, WNOHANG));
1257 if (result == -1) {
1258 DPLOG(ERROR) << "waitpid(" << child << ")";
1259 NOTREACHED();
1260 } else if (result > 0) {
1261 // The child has died.
1262 return true;
1263 }
1264
1265 return false;
1266}
1267
1268// A thread class which waits for the given child to exit and reaps it.
1269// If the child doesn't exit within a couple of seconds, kill it.
1270class BackgroundReaper : public PlatformThread::Delegate {
1271 public:
1272 BackgroundReaper(pid_t child, unsigned timeout)
1273 : child_(child),
1274 timeout_(timeout) {
1275 }
1276
[email protected]c19003d2012-07-31 01:38:181277 // Overridden from PlatformThread::Delegate:
1278 virtual void ThreadMain() OVERRIDE {
[email protected]eaac71592011-11-23 18:32:001279 WaitForChildToDie();
1280 delete this;
1281 }
1282
1283 void WaitForChildToDie() {
1284 // Wait forever case.
1285 if (timeout_ == 0) {
1286 pid_t r = HANDLE_EINTR(waitpid(child_, NULL, 0));
1287 if (r != child_) {
1288 DPLOG(ERROR) << "While waiting for " << child_
1289 << " to terminate, we got the following result: " << r;
1290 }
1291 return;
1292 }
1293
1294 // There's no good way to wait for a specific child to exit in a timed
1295 // fashion. (No kqueue on Linux), so we just loop and sleep.
1296
1297 // Wait for 2 * timeout_ 500 milliseconds intervals.
1298 for (unsigned i = 0; i < 2 * timeout_; ++i) {
[email protected]a1b75b942011-12-31 22:53:511299 PlatformThread::Sleep(TimeDelta::FromMilliseconds(500));
[email protected]eaac71592011-11-23 18:32:001300 if (IsChildDead(child_))
1301 return;
1302 }
1303
1304 if (kill(child_, SIGKILL) == 0) {
1305 // SIGKILL is uncatchable. Since the signal was delivered, we can
1306 // just wait for the process to die now in a blocking manner.
1307 if (HANDLE_EINTR(waitpid(child_, NULL, 0)) < 0)
1308 DPLOG(WARNING) << "waitpid";
1309 } else {
1310 DLOG(ERROR) << "While waiting for " << child_ << " to terminate we"
1311 << " failed to deliver a SIGKILL signal (" << errno << ").";
1312 }
1313 }
1314
1315 private:
1316 const pid_t child_;
1317 // Number of seconds to wait, if 0 then wait forever and do not attempt to
1318 // kill |child_|.
1319 const unsigned timeout_;
1320
1321 DISALLOW_COPY_AND_ASSIGN(BackgroundReaper);
1322};
1323
1324} // namespace
1325
1326void EnsureProcessTerminated(ProcessHandle process) {
1327 // If the child is already dead, then there's nothing to do.
1328 if (IsChildDead(process))
1329 return;
1330
1331 const unsigned timeout = 2; // seconds
1332 BackgroundReaper* reaper = new BackgroundReaper(process, timeout);
1333 PlatformThread::CreateNonJoinable(0, reaper);
1334}
1335
1336void EnsureProcessGetsReaped(ProcessHandle process) {
1337 // If the child is already dead, then there's nothing to do.
1338 if (IsChildDead(process))
1339 return;
1340
1341 BackgroundReaper* reaper = new BackgroundReaper(process, 0);
1342 PlatformThread::CreateNonJoinable(0, reaper);
1343}
1344
1345#endif // !defined(OS_MACOSX)
1346
[email protected]aa660752008-11-14 03:39:461347} // namespace base