My app (Cocoa) includes a privileged helper tool (C) that's installed using SMJobBless
, modeled after the SMJobBlessXPC sample code by Nathan de Vries. It successfully launches on a connection attempt to its exported Mach XPC connection. So far so good.
What I can't figure out is how to then terminate that process later on. When my application terminates, the helper tool has no business running anymore — in fact, it explicitly shouldn't be running anymore. I can't figure out for the life of me how to exit it, though.
Calling exit(0)
from the handler for an XPC event seems to have no effect, possibly because the docs state that exit
terminates the current thread, not the process. My main
function looks like this:
int main(int argc, const char * argv[])
{
// setup a Mach XPC service so that we can receive communication from the app
xpc_connection_t service = xpc_connection_create_mach_service("com.my.service.name", dispatch_get_main_queue(), XPC_CONNECTION_MACH_SERVICE_LISTENER);
xpc_connection_set_event_handler(service, ^(xpc_object_t connection){
handle_xpc_connection(connection);
});
xpc_connection_resume(service);
dispatch_main();
xpc_release(service);
return 0;
}
I know dispatch_main
never returns, so that could have something to do with it, but there must be SOME way to get the process to exit normally. Do I need to switch to using a CFRunLoop
?
As a corollary, how do I ensure that the process doesn't terminate prematurely? Either the helper tool or the main app will know exactly when the right time to terminate is. Once a job is started, will it continue to run until terminated? I'm a little fuzzy on launchd's lifecycle management, and it's not very well-documented (that I can find) beyond launchd.plist(5)
.