task_set_bootstrap_port
的行为在OS X 10.6和10.7之间发生了变化。在10.6中,这可以工作:
// parent process
mach_port_t parent_recv_port = MACH_PORT_NULL;
setup_recv_port (&parent_recv_port);
task_set_bootstrap_port(mach_task_self(), parent_recv_port);
NSTask *qtTask = [[NSTask alloc] init];
[qtTask setLaunchPath:...];
[qtTask launch];
...
// child process
int main (int argc, const char * argv[])
{
mach_port_t parent_recv_port = MACH_PORT_NULL;
task_get_bootstrap_port(mach_task_self(), &parent_recv_port);
...
}
在10.7中,子进程在父进程调用-launch
后不会立即执行main
的第一行——它等待直到父进程终止。(虽然子进程在ps
中会立即出现)
我已经把问题缩小到呼叫task_set_bootstrap_port
。当调用不存在时,子进程不会挂起。而且,如果我在task_set_bootstrap_port
之后立即恢复引导端口到原始端口——
task_set_bootstrap_port(mach_task_self(), bootstrap_port);
——那么子进程也不会挂起。
上面省略了错误处理代码,但实际上它是在每次调用后检查错误。没有错误。那么,你知道为什么task_set_bootstrap_port
的行为从10.6改变到10.7吗?有解决办法吗?
- 需要访问
mach_port_t
以传递给IOSurfaceLookupFromMachPort
。 - Runloop可能不存在,所以不能使用
NSMachPort
或CFMachPort
。
Apple Developer Technical Support告诉我,暂时改变引导端口,就像这段代码所做的那样,永远不能保证工作。在这种情况下,XPC试图在引导端口被更改后向它发送消息,但是失败了,所以事情就坏了。
快速修复是在父进程中使用bootstrap_register
(尽管已弃用),在子进程中使用bootstrap_look_up
。这允许子进程通过名称(一个字符串)查找父进程并从中获取端口。