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

Side by Side Diff: base/process_util_posix.cc

Issue 549002: Mac: Other approach for IPCing child task_ts. (Closed)
Patch Set: '' Created 10 years, 11 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 unified diff | Download patch
« no previous file with comments | « base/process_util.h ('k') | chrome/browser/child_process_launcher.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <dirent.h> 5 #include <dirent.h>
6 #include <errno.h> 6 #include <errno.h>
7 #include <fcntl.h> 7 #include <fcntl.h>
8 #include <signal.h> 8 #include <signal.h>
9 #include <stdlib.h> 9 #include <stdlib.h>
10 #include <sys/resource.h> 10 #include <sys/resource.h>
11 #include <sys/time.h> 11 #include <sys/time.h>
12 #include <sys/types.h> 12 #include <sys/types.h>
13 #include <sys/wait.h> 13 #include <sys/wait.h>
14 #include <unistd.h> 14 #include <unistd.h>
15 15
16 #include <limits> 16 #include <limits>
17 #include <set> 17 #include <set>
18 18
19 #include "base/debug_util.h" 19 #include "base/debug_util.h"
20 #include "base/eintr_wrapper.h" 20 #include "base/eintr_wrapper.h"
21 #include "base/logging.h" 21 #include "base/logging.h"
22 #include "base/platform_thread.h" 22 #include "base/platform_thread.h"
23 #include "base/process_util.h" 23 #include "base/process_util.h"
24 #include "base/rand_util.h"
24 #include "base/scoped_ptr.h" 25 #include "base/scoped_ptr.h"
25 #include "base/sys_info.h" 26 #include "base/sys_info.h"
26 #include "base/time.h" 27 #include "base/time.h"
27 #include "base/waitable_event.h" 28 #include "base/waitable_event.h"
28 29
30 #if defined(OS_MACOSX)
31 #include "base/mach_ipc_mac.h"
32 #endif
33
29 const int kMicrosecondsPerSecond = 1000000; 34 const int kMicrosecondsPerSecond = 1000000;
30 35
31 namespace base { 36 namespace base {
32 37
33 namespace { 38 namespace {
34 39
35 int WaitpidWithTimeout(ProcessHandle handle, int64 wait_milliseconds, 40 int WaitpidWithTimeout(ProcessHandle handle, int64 wait_milliseconds,
36 bool* success) { 41 bool* success) {
37 // This POSIX version of this function only guarantees that we wait no less 42 // This POSIX version of this function only guarantees that we wait no less
38 // than |wait_milliseconds| for the proces to exit. The child process may 43 // than |wait_milliseconds| for the proces to exit. The child process may
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after
273 if (i <= STDERR_FILENO) 278 if (i <= STDERR_FILENO)
274 continue; 279 continue;
275 280
276 int flags = fcntl(i, F_GETFD); 281 int flags = fcntl(i, F_GETFD);
277 if ((flags == -1) || (fcntl(i, F_SETFD, flags | FD_CLOEXEC) == -1)) { 282 if ((flags == -1) || (fcntl(i, F_SETFD, flags | FD_CLOEXEC) == -1)) {
278 DLOG(ERROR) << "fcntl failure."; 283 DLOG(ERROR) << "fcntl failure.";
279 } 284 }
280 } 285 }
281 } 286 }
282 287
288 #if defined(OS_MACOSX)
289 static std::string MachErrorCode(kern_return_t err) {
290 return StringPrintf("0x%x %s", err, mach_error_string(err));
291 }
292
293 // Forks the current process and returns the child's |task_t| in the parent
294 // process.
295 static pid_t fork_and_get_task(task_t* child_task) {
296 const int kTimeoutMs = 100;
297 kern_return_t err;
298
299 // Put a random number into the channel name, so that a compromised renderer
300 // can't pretend being the child that's forked off.
301 std::string mach_connection_name = StringPrintf(
302 "com.google.Chrome.samplingfork.%p.%d",
303 child_task, base::RandInt(0, std::numeric_limits<int>::max()));
304 ReceivePort parent_recv_port(mach_connection_name.c_str());
305
306 // Error handling philosophy: If Mach IPC fails, don't touch |child_task| but
307 // return a valid pid. If IPC fails in the child, the parent will have to wait
308 // until kTimeoutMs is over. This is not optimal, but I've never seen it
309 // happen, and stuff should still mostly work.
310 pid_t pid = fork();
311 switch (pid) {
312 case -1:
313 return pid;
314 case 0: { // child
315 ReceivePort child_recv_port;
316
317 MachSendMessage child_message(/* id= */0);
318 if (!child_message.AddDescriptor(mach_task_self())) {
319 LOG(ERROR) << "child AddDescriptor(mach_task_self()) failed.";
320 return pid;
321 }
322 mach_port_t raw_child_recv_port = child_recv_port.GetPort();
323 if (!child_message.AddDescriptor(raw_child_recv_port)) {
324 LOG(ERROR) << "child AddDescriptor(" << raw_child_recv_port
325 << ") failed.";
326 return pid;
327 }
328
329 MachPortSender child_sender(mach_connection_name.c_str());
330 err = child_sender.SendMessage(child_message, kTimeoutMs);
331 if (err != KERN_SUCCESS) {
332 LOG(ERROR) << "child SendMessage() failed: " << MachErrorCode(err);
333 return pid;
334 }
335
336 MachReceiveMessage parent_message;
337 err = child_recv_port.WaitForMessage(&parent_message, kTimeoutMs);
338 if (err != KERN_SUCCESS) {
339 LOG(ERROR) << "child WaitForMessage() failed: " << MachErrorCode(err);
340 return pid;
341 }
342
343 if (parent_message.GetTranslatedPort(0) == MACH_PORT_NULL) {
344 LOG(ERROR) << "child GetTranslatedPort(0) failed.";
345 return pid;
346 }
347 err = task_set_bootstrap_port(mach_task_self(),
348 parent_message.GetTranslatedPort(0));
349 if (err != KERN_SUCCESS) {
350 LOG(ERROR) << "child task_set_bootstrap_port() failed: "
351 << MachErrorCode(err);
352 return pid;
353 }
354 break;
355 }
356 default: { // parent
357 MachReceiveMessage child_message;
358 err = parent_recv_port.WaitForMessage(&child_message, kTimeoutMs);
359 if (err != KERN_SUCCESS) {
360 LOG(ERROR) << "parent WaitForMessage() failed: " << MachErrorCode(err);
361 return pid;
362 }
363
364 if (child_message.GetTranslatedPort(0) == MACH_PORT_NULL) {
365 LOG(ERROR) << "parent GetTranslatedPort(0) failed.";
366 return pid;
367 }
368 *child_task = child_message.GetTranslatedPort(0);
369
370 if (child_message.GetTranslatedPort(1) == MACH_PORT_NULL) {
371 LOG(ERROR) << "parent GetTranslatedPort(1) failed.";
372 return pid;
373 }
374 MachPortSender parent_sender(child_message.GetTranslatedPort(1));
375
376 MachSendMessage parent_message(/* id= */0);
377 if (!parent_message.AddDescriptor(bootstrap_port)) {
378 LOG(ERROR) << "parent AddDescriptor(" << bootstrap_port << ") failed.";
379 return pid;
380 }
381
382 err = parent_sender.SendMessage(parent_message, kTimeoutMs);
383 if (err != KERN_SUCCESS) {
384 LOG(ERROR) << "parent SendMessage() failed: " << MachErrorCode(err);
385 return pid;
386 }
387 break;
388 }
389 }
390 return pid;
391 }
392
283 bool LaunchApp(const std::vector<std::string>& argv, 393 bool LaunchApp(const std::vector<std::string>& argv,
284 const environment_vector& environ, 394 const environment_vector& environ,
285 const file_handle_mapping_vector& fds_to_remap, 395 const file_handle_mapping_vector& fds_to_remap,
286 bool wait, ProcessHandle* process_handle) { 396 bool wait, ProcessHandle* process_handle) {
287 pid_t pid = fork(); 397 return LaunchAppAndGetTask(
398 argv, environ, fds_to_remap, wait, NULL, process_handle);
399 }
400 #endif // defined(OS_MACOSX)
401
402 #if defined(OS_MACOSX)
403 bool LaunchAppAndGetTask(
404 #else
405 bool LaunchApp(
406 #endif
407 const std::vector<std::string>& argv,
408 const environment_vector& environ,
409 const file_handle_mapping_vector& fds_to_remap,
410 bool wait,
411 #if defined(OS_MACOSX)
412 task_t* task_handle,
413 #endif
414 ProcessHandle* process_handle) {
415 pid_t pid;
416 #if defined(OS_MACOSX)
417 if (task_handle == NULL) {
418 pid = fork();
419 } else {
420 // On OS X, the task_t for a process is needed for several reasons. Sadly,
421 // the function task_for_pid() requires privileges a normal user doesn't
422 // have. Instead, a short-lived Mach IPC connection is opened between parent
423 // and child, and the child sends its task_t to the parent at fork time.
424 *task_handle = MACH_PORT_NULL;
425 pid = fork_and_get_task(task_handle);
426 }
427 #else
428 pid = fork();
429 #endif
288 if (pid < 0) 430 if (pid < 0)
289 return false; 431 return false;
290 432
291 if (pid == 0) { 433 if (pid == 0) {
292 // Child process 434 // Child process
293 #if defined(OS_MACOSX) 435 #if defined(OS_MACOSX)
294 RestoreDefaultExceptionHandler(); 436 RestoreDefaultExceptionHandler();
295 #endif 437 #endif
296 438
297 InjectiveMultimap fd_shuffle; 439 InjectiveMultimap fd_shuffle;
(...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after
677 const ProcessFilter* filter) { 819 const ProcessFilter* filter) {
678 bool exited_cleanly = 820 bool exited_cleanly =
679 WaitForProcessesToExit(executable_name, wait_milliseconds, 821 WaitForProcessesToExit(executable_name, wait_milliseconds,
680 filter); 822 filter);
681 if (!exited_cleanly) 823 if (!exited_cleanly)
682 KillProcesses(executable_name, exit_code, filter); 824 KillProcesses(executable_name, exit_code, filter);
683 return exited_cleanly; 825 return exited_cleanly;
684 } 826 }
685 827
686 } // namespace base 828 } // namespace base
OLDNEW
« no previous file with comments | « base/process_util.h ('k') | chrome/browser/child_process_launcher.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698