Skip to content

Instantly share code, notes, and snippets.

@nicoster
Created February 23, 2014 07:43
Show Gist options
  • Select an option

  • Save nicoster/9168364 to your computer and use it in GitHub Desktop.

Select an option

Save nicoster/9168364 to your computer and use it in GitHub Desktop.
#include <mach/mach.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#define CHECK_MACH_ERROR(a, msg) do {kern_return_t rr = (a); if ((rr) != KERN_SUCCESS) { printf("%s Mach error %x (%s) on line %d of file %s\n", msg, (rr), mach_error_string((rr)), __LINE__, __FILE__); abort(); } } 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;
err = task_get_bootstrap_port(mach_task_self(), &child_recv_port);
CHECK_MACH_ERROR (err, "task_get_bootstrap_port failed:");
printf("begin, task_get_bootstrap_port:%d, bootstrap_port:%d\n", child_recv_port, bootstrap_port);
if (setup_recv_port (&parent_recv_port) != 0)
return -1;
printf("parent_recv_port:%d\n", parent_recv_port);
err = task_set_bootstrap_port (mach_task_self (), parent_recv_port);
CHECK_MACH_ERROR (err, "task_set_bootstrap_port failed:");
err = task_get_bootstrap_port(mach_task_self(), &child_recv_port);
CHECK_MACH_ERROR (err, "task_get_bootstrap_port failed:");
printf("before fork, after task_set_bootstrap_port, task_get_bootstrap_port:%d, bootstrap_port:%d\n", child_recv_port, bootstrap_port);
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:");
printf("child, after fork, task_get_bootstrap_port:%d, bootstrap_port:%d\n", parent_recv_port, bootstrap_port);
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;
printf("child, after operation, bootstrap_port:%d\n", bootstrap_port);
err = task_set_bootstrap_port (mach_task_self (), bootstrap_port);
CHECK_MACH_ERROR (err, "task_set_bootstrap_port failed:");
err = task_get_bootstrap_port(mach_task_self(), &child_recv_port);
CHECK_MACH_ERROR (err, "task_get_bootstrap_port failed:");
printf("end, child, task_get_bootstrap_port:%d, bootstrap_port:%d\n", child_recv_port, bootstrap_port);
break;
default: /* parent */
printf("parent, after fork, bootstrap_port:%d\n", bootstrap_port);
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:");
err = task_get_bootstrap_port(mach_task_self(), &child_recv_port);
CHECK_MACH_ERROR (err, "task_get_bootstrap_port failed:");
printf("end, parent, task_get_bootstrap_port:%d, bootstrap_port:%d\n", child_recv_port, bootstrap_port);
break;
}
return pid;
}
int main()
{
sampling_fork();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment