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

Side by Side Diff: base/process_util_posix.cc

Issue 3443002: [Mac] Replace the existing browser-child mach ipc with a long-lived listener ... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 10 years, 3 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 | Annotate | Revision Log
« no previous file with comments | « base/process_util.h ('k') | chrome/app/chrome_dll_main.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) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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>
(...skipping 14 matching lines...) Expand all
25 #include "base/platform_thread.h" 25 #include "base/platform_thread.h"
26 #include "base/process_util.h" 26 #include "base/process_util.h"
27 #include "base/scoped_ptr.h" 27 #include "base/scoped_ptr.h"
28 #include "base/stringprintf.h" 28 #include "base/stringprintf.h"
29 #include "base/time.h" 29 #include "base/time.h"
30 #include "base/waitable_event.h" 30 #include "base/waitable_event.h"
31 31
32 #if defined(OS_MACOSX) 32 #if defined(OS_MACOSX)
33 #include <crt_externs.h> 33 #include <crt_externs.h>
34 #define environ (*_NSGetEnviron()) 34 #define environ (*_NSGetEnviron())
35 #include "base/mach_ipc_mac.h"
36 #include "base/rand_util.h"
37 #else 35 #else
38 extern char** environ; 36 extern char** environ;
39 #endif 37 #endif
40 38
41 namespace base { 39 namespace base {
42 40
43 namespace { 41 namespace {
44 42
45 int WaitpidWithTimeout(ProcessHandle handle, int64 wait_milliseconds, 43 int WaitpidWithTimeout(ProcessHandle handle, int64 wait_milliseconds,
46 bool* success) { 44 bool* success) {
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 // own use and will complain if we try to close them. All of 292 // own use and will complain if we try to close them. All of
295 // these FDs are >= |max_fds|, so we can check against that here 293 // these FDs are >= |max_fds|, so we can check against that here
296 // before closing. See https://bugs.kde.org/show_bug.cgi?id=191758 294 // before closing. See https://bugs.kde.org/show_bug.cgi?id=191758
297 if (fd < static_cast<int>(max_fds)) { 295 if (fd < static_cast<int>(max_fds)) {
298 int ret = HANDLE_EINTR(close(fd)); 296 int ret = HANDLE_EINTR(close(fd));
299 DPCHECK(ret == 0); 297 DPCHECK(ret == 0);
300 } 298 }
301 } 299 }
302 } 300 }
303 301
304 #if defined(OS_MACOSX)
305 static std::string MachErrorCode(kern_return_t err) {
306 return StringPrintf("0x%x %s", err, mach_error_string(err));
307 }
308
309 // Forks the current process and returns the child's |task_t| in the parent
310 // process.
311 static pid_t fork_and_get_task(task_t* child_task) {
312 const int kTimeoutMs = 100;
313 kern_return_t err;
314
315 // Put a random number into the channel name, so that a compromised renderer
316 // can't pretend being the child that's forked off.
317 std::string mach_connection_name = StringPrintf(
318 "com.google.Chrome.samplingfork.%p.%d",
319 child_task, base::RandInt(0, std::numeric_limits<int>::max()));
320
321 // Create the mach receive port before forking to ensure that it exists when
322 // the child tries to connect. Mach ports are not duped into the child, so
323 // this is safe to set up here.
324 ReceivePort parent_recv_port(mach_connection_name.c_str());
325
326 // Error handling philosophy: If Mach IPC fails, don't touch |child_task| but
327 // return a valid pid. If IPC fails in the child, the parent will have to wait
328 // until kTimeoutMs is over. This is not optimal, but I've never seen it
329 // happen, and stuff should still mostly work.
330 pid_t pid = fork();
331 switch (pid) {
332 case -1:
333 return pid;
334 case 0: { // child
335 // Must reset signal handlers before doing any mach IPC, as the mach IPC
336 // calls can potentially hang forever.
337 ResetChildSignalHandlersToDefaults();
338 MachSendMessage child_message(/* id= */0);
339 if (!child_message.AddDescriptor(mach_task_self())) {
340 LOG(ERROR) << "child AddDescriptor(mach_task_self()) failed.";
341 return pid;
342 }
343
344 MachPortSender child_sender(mach_connection_name.c_str());
345 err = child_sender.SendMessage(child_message, kTimeoutMs);
346 if (err != KERN_SUCCESS) {
347 LOG(ERROR) << "child SendMessage() failed: " << MachErrorCode(err);
348 return pid;
349 }
350 break;
351 }
352 default: { // parent
353 MachReceiveMessage child_message;
354 err = parent_recv_port.WaitForMessage(&child_message, kTimeoutMs);
355 if (err != KERN_SUCCESS) {
356 LOG(ERROR) << "parent WaitForMessage() failed: " << MachErrorCode(err);
357 return pid;
358 }
359
360 if (child_message.GetTranslatedPort(0) == MACH_PORT_NULL) {
361 LOG(ERROR) << "parent GetTranslatedPort(0) failed.";
362 return pid;
363 }
364 *child_task = child_message.GetTranslatedPort(0);
365 break;
366 }
367 }
368 return pid;
369 }
370
371 bool LaunchApp(const std::vector<std::string>& argv,
372 const environment_vector& env_changes,
373 const file_handle_mapping_vector& fds_to_remap,
374 bool wait, ProcessHandle* process_handle) {
375 return LaunchAppAndGetTask(
376 argv, env_changes, fds_to_remap, wait, NULL, process_handle);
377 }
378 #endif // defined(OS_MACOSX)
379
380 char** AlterEnvironment(const environment_vector& changes, 302 char** AlterEnvironment(const environment_vector& changes,
381 const char* const* const env) { 303 const char* const* const env) {
382 unsigned count = 0; 304 unsigned count = 0;
383 unsigned size = 0; 305 unsigned size = 0;
384 306
385 // First assume that all of the current environment will be included. 307 // First assume that all of the current environment will be included.
386 for (unsigned i = 0; env[i]; i++) { 308 for (unsigned i = 0; env[i]; i++) {
387 const char *const pair = env[i]; 309 const char *const pair = env[i];
388 count++; 310 count++;
389 size += strlen(pair) + 1 /* terminating NUL */; 311 size += strlen(pair) + 1 /* terminating NUL */;
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
491 *scratch++ = '='; 413 *scratch++ = '=';
492 memcpy(scratch, j->second.c_str(), j->second.size() + 1); 414 memcpy(scratch, j->second.c_str(), j->second.size() + 1);
493 scratch += j->second.size() + 1; 415 scratch += j->second.size() + 1;
494 } 416 }
495 } 417 }
496 418
497 ret[k] = NULL; 419 ret[k] = NULL;
498 return ret; 420 return ret;
499 } 421 }
500 422
501 #if defined(OS_MACOSX)
502 bool LaunchAppAndGetTask(
503 #else
504 bool LaunchApp( 423 bool LaunchApp(
505 #endif
506 const std::vector<std::string>& argv, 424 const std::vector<std::string>& argv,
507 const environment_vector& env_changes, 425 const environment_vector& env_changes,
508 const file_handle_mapping_vector& fds_to_remap, 426 const file_handle_mapping_vector& fds_to_remap,
509 bool wait, 427 bool wait,
510 #if defined(OS_MACOSX)
511 task_t* task_handle,
512 #endif
513 ProcessHandle* process_handle) { 428 ProcessHandle* process_handle) {
514 pid_t pid; 429 pid_t pid;
515 InjectiveMultimap fd_shuffle1, fd_shuffle2; 430 InjectiveMultimap fd_shuffle1, fd_shuffle2;
516 fd_shuffle1.reserve(fds_to_remap.size()); 431 fd_shuffle1.reserve(fds_to_remap.size());
517 fd_shuffle2.reserve(fds_to_remap.size()); 432 fd_shuffle2.reserve(fds_to_remap.size());
518 scoped_array<char*> argv_cstr(new char*[argv.size() + 1]); 433 scoped_array<char*> argv_cstr(new char*[argv.size() + 1]);
519 scoped_array<char*> new_environ(AlterEnvironment(env_changes, environ)); 434 scoped_array<char*> new_environ(AlterEnvironment(env_changes, environ));
520 435
521 #if defined(OS_MACOSX)
522 if (task_handle == NULL) {
523 pid = fork();
524 } else {
525 // On OS X, the task_t for a process is needed for several reasons. Sadly,
526 // the function task_for_pid() requires privileges a normal user doesn't
527 // have. Instead, a short-lived Mach IPC connection is opened between parent
528 // and child, and the child sends its task_t to the parent at fork time.
529 *task_handle = MACH_PORT_NULL;
530 pid = fork_and_get_task(task_handle);
531 }
532 #else
533 pid = fork(); 436 pid = fork();
534 #endif
535 if (pid < 0) 437 if (pid < 0)
536 return false; 438 return false;
537 439
538 if (pid == 0) { 440 if (pid == 0) {
539 // Child process 441 // Child process
540 #if defined(OS_MACOSX) 442 #if defined(OS_MACOSX)
541 RestoreDefaultExceptionHandler(); 443 RestoreDefaultExceptionHandler();
542 #endif 444 #endif
543 445
544 // On mac, the signal handlers are reset in |fork_and_get_task()|.
545 #if !defined(OS_MACOSX)
546 ResetChildSignalHandlersToDefaults(); 446 ResetChildSignalHandlersToDefaults();
547 #endif
548 447
549 #if 0 448 #if 0
550 // When debugging it can be helpful to check that we really aren't making 449 // When debugging it can be helpful to check that we really aren't making
551 // any hidden calls to malloc. 450 // any hidden calls to malloc.
552 void *malloc_thunk = 451 void *malloc_thunk =
553 reinterpret_cast<void*>(reinterpret_cast<intptr_t>(malloc) & ~4095); 452 reinterpret_cast<void*>(reinterpret_cast<intptr_t>(malloc) & ~4095);
554 mprotect(malloc_thunk, 4096, PROT_READ | PROT_WRITE | PROT_EXEC); 453 mprotect(malloc_thunk, 4096, PROT_READ | PROT_WRITE | PROT_EXEC);
555 memset(reinterpret_cast<void*>(malloc), 0xff, 8); 454 memset(reinterpret_cast<void*>(malloc), 0xff, 8);
556 #endif 455 #endif
557 456
(...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after
910 const ProcessFilter* filter) { 809 const ProcessFilter* filter) {
911 bool exited_cleanly = 810 bool exited_cleanly =
912 WaitForProcessesToExit(executable_name, wait_milliseconds, 811 WaitForProcessesToExit(executable_name, wait_milliseconds,
913 filter); 812 filter);
914 if (!exited_cleanly) 813 if (!exited_cleanly)
915 KillProcesses(executable_name, exit_code, filter); 814 KillProcesses(executable_name, exit_code, filter);
916 return exited_cleanly; 815 return exited_cleanly;
917 } 816 }
918 817
919 } // namespace base 818 } // namespace base
OLDNEW
« no previous file with comments | « base/process_util.h ('k') | chrome/app/chrome_dll_main.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698