Created
February 23, 2014 07:43
-
-
Save nicoster/9168364 to your computer and use it in GitHub Desktop.
quoted from http://www.foldr.org/~michaelw/log/computers/macosx/task-info-fun-with-mach how mach_msg is used
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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