diff options
author | thakis@chromium.org <thakis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-10 03:44:46 +0000 |
---|---|---|
committer | thakis@chromium.org <thakis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-10 03:44:46 +0000 |
commit | a83c2ac610b6830985099978c4a4ee8d35cea8fd (patch) | |
tree | e9fb8ff18812592c8a28686bd7472dd06f6a9c04 /base | |
parent | cbdc0c73594139a186d28410122e1e98deb175df (diff) | |
download | chromium_src-a83c2ac610b6830985099978c4a4ee8d35cea8fd.zip chromium_src-a83c2ac610b6830985099978c4a4ee8d35cea8fd.tar.gz chromium_src-a83c2ac610b6830985099978c4a4ee8d35cea8fd.tar.bz2 |
Mac: Other approach for IPCing child task_ts.
Based on http://www.foldr.org/~michaelw/log/2009/03/13/ , right now in proof-of-concept quality.
Works for worker processes too and seems more reliable in general. Makes it impossible to call LaunchApp() concurrently though.
Submitting to get perf numbers, will revert.
Review URL: http://codereview.chromium.org/549002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@35883 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r-- | base/process_util_posix.cc | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/base/process_util_posix.cc b/base/process_util_posix.cc index 21626732..ba785e4 100644 --- a/base/process_util_posix.cc +++ b/base/process_util_posix.cc @@ -26,6 +26,12 @@ #include "base/time.h" #include "base/waitable_event.h" +#if defined(OS_MACOSX) +#include "base/mach_broker_mac.h" + + +#endif + const int kMicrosecondsPerSecond = 1000000; namespace base { @@ -280,11 +286,148 @@ void SetAllFDsToCloseOnExec() { } } +#if defined(OS_MACOSX) + +#define CHECK_MACH_ERROR(err, s) \ +do { \ + if (err != KERN_SUCCESS) { \ + fprintf(stderr, "%s 0x%x", s, (int)err); \ + exit(1); \ + } \ +} while (0) + +static int +setup_recv_port (mach_port_t *recv_port) +{ + kern_return_t err; + mach_port_t port = MACH_PORT_NULL; + err = mach_port_allocate (mach_task_self (), + MACH_PORT_RIGHT_RECEIVE, &port); + CHECK_MACH_ERROR (err, "mach_port_allocate failed:"); + + err = mach_port_insert_right (mach_task_self (), + port, + port, + MACH_MSG_TYPE_MAKE_SEND); + CHECK_MACH_ERROR (err, "mach_port_insert_right failed:"); + + *recv_port = port; + return 0; +} + +static int +send_port (mach_port_t remote_port, mach_port_t port) +{ + kern_return_t err; + + struct { + mach_msg_header_t header; + mach_msg_body_t body; + mach_msg_port_descriptor_t task_port; + } msg; + + msg.header.msgh_remote_port = remote_port; + msg.header.msgh_local_port = MACH_PORT_NULL; + msg.header.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, 0) | + MACH_MSGH_BITS_COMPLEX; + msg.header.msgh_size = sizeof msg; + + msg.body.msgh_descriptor_count = 1; + msg.task_port.name = port; + msg.task_port.disposition = MACH_MSG_TYPE_COPY_SEND; + msg.task_port.type = MACH_MSG_PORT_DESCRIPTOR; + + err = mach_msg_send (&msg.header); + CHECK_MACH_ERROR (err, "mach_msg_send failed:"); + + return 0; +} + +static int +recv_port (mach_port_t recv_port, mach_port_t *port) +{ + kern_return_t err; + struct { + mach_msg_header_t header; + mach_msg_body_t body; + mach_msg_port_descriptor_t task_port; + mach_msg_trailer_t trailer; + } msg; + + err = mach_msg (&msg.header, MACH_RCV_MSG, + 0, sizeof msg, recv_port, + MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + CHECK_MACH_ERROR (err, "mach_msg failed:"); + + *port = msg.task_port.name; + return 0; +} + +static task_t child_task = MACH_PORT_NULL; + +pid_t +sampling_fork () +{ + kern_return_t err; + mach_port_t parent_recv_port = MACH_PORT_NULL; + mach_port_t child_recv_port = MACH_PORT_NULL; + + if (setup_recv_port (&parent_recv_port) != 0) + return -1; + err = task_set_bootstrap_port (mach_task_self (), parent_recv_port); + CHECK_MACH_ERROR (err, "task_set_bootstrap_port failed:"); + + pid_t pid; + switch (pid = fork ()) { + case -1: + err = mach_port_deallocate (mach_task_self(), parent_recv_port); + CHECK_MACH_ERROR (err, "mach_port_deallocate failed:"); + return pid; + case 0: /* child */ + err = task_get_bootstrap_port (mach_task_self (), &parent_recv_port); + CHECK_MACH_ERROR (err, "task_get_bootstrap_port failed:"); + if (setup_recv_port (&child_recv_port) != 0) + return -1; + if (send_port (parent_recv_port, mach_task_self ()) != 0) + return -1; + if (send_port (parent_recv_port, child_recv_port) != 0) + return -1; + if (recv_port (child_recv_port, &bootstrap_port) != 0) + return -1; + err = task_set_bootstrap_port (mach_task_self (), bootstrap_port); + CHECK_MACH_ERROR (err, "task_set_bootstrap_port failed:"); + break; + default: /* parent */ + err = task_set_bootstrap_port (mach_task_self (), bootstrap_port); + CHECK_MACH_ERROR (err, "task_set_bootstrap_port failed:"); + if (recv_port (parent_recv_port, &child_task) != 0) + return -1; + if (recv_port (parent_recv_port, &child_recv_port) != 0) + return -1; + if (send_port (child_recv_port, bootstrap_port) != 0) + return -1; + err = mach_port_deallocate (mach_task_self(), parent_recv_port); + CHECK_MACH_ERROR (err, "mach_port_deallocate failed:"); + break; + } + + return pid; +} +#endif + bool LaunchApp(const std::vector<std::string>& argv, const environment_vector& environ, const file_handle_mapping_vector& fds_to_remap, bool wait, ProcessHandle* process_handle) { +#if defined(OS_MACOSX) + // Needs to be mutexed! :-( + pid_t pid = sampling_fork(); + MachBroker::instance()->RegisterPid( + pid, + MachBroker::MachInfo().SetTask(child_task)); +#else pid_t pid = fork(); +#endif if (pid < 0) return false; |