summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authorthakis@chromium.org <thakis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-10 03:44:46 +0000
committerthakis@chromium.org <thakis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-10 03:44:46 +0000
commita83c2ac610b6830985099978c4a4ee8d35cea8fd (patch)
treee9fb8ff18812592c8a28686bd7472dd06f6a9c04 /base
parentcbdc0c73594139a186d28410122e1e98deb175df (diff)
downloadchromium_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.cc143
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;