In my implementation I am using Golang to call C code, how is the XPC lifecycle affected by this?
It isn’t, at least not from a launchd
perspective.
I’m presuming that your C code is linked into your executable and thus running in the same process as your Go code. In that case, this split doesn’t affect launchd
or the XPC API:
-
launchd
just starts a process that runs your executable. It doesn’t case what language you write this in.
-
Likewise, the XPC API doesn’t care about the language you use for your main
function.
Is the XPC listener launched on demand, or does it stay running as long as the daemon?
OK, so an XPC listener isn’t launched. Rather, it’s something that you start within your process by calling XPC APIs.
Your launchd
daemon is launched. Whether that’s on demand on not depends on how you’ve configured your launchd
property list.
If you list a named XPC endpoint in your MachServices
array then you must start an XPC listener for that endpoint when your daemon starts and keep that XPC listener alive until your process terminates. That listener checks in with launchd
and assumes responsibility for handling XPC requests on your named endpoint.
Do you mean launchd owns the endpoint?
Well, yeah, that’s pretty much what I wrote (-:
I go into this in some detail in XPC and App-to-App Communication. It’s really important that you read that.
I am using dispatch_resume that doesn’t return…
I’m still not sure why you’re calling dispatch_resume
at all. XPC listeners don’t need that in general. [goes to look at your test project] Oh, weird.
Anyway, that timer you create is pointless. You should get rid of it.
As to why your listener isn’t working, I’m not 100% sure but I suspect it’s combination of two things:
-
You should maintain a persistent reference to your listener. Right now it’s only stored in a local variable, listener
, which is released by ARC when you return from runXPCServer
. You need to persist that somehow.
One way to do that is to store it in a global. That’s acceptable because the listener is really a global resource, based on its connection to your MachServices
entry.
Alternatively, you could return it to your Go code and have that persist the reference. I don’t know enough about Go to advise you on how to do that.
-
In ListenerHandler
you’ve set an event handler on the new connection but not queue. XPC will default to its own queue for this, but I think it makes more sense for you to use the queue you created, xpcQueue
.
Finally, my general advice with XPC is that you do your bring up using a loopback connection. See TN3113 Testing and debugging XPC code with an anonymous listener. The code snippets in that technote are for NSXPCConnection
, but there was a recent thread here on the forums that explain how to get the same technique working with the low-level C API.
how can I free the dispatch source, queue and the XPC connection object variables?
You don’t. Your listener should run, and service requests, until your process terminates. If you shut your listener down without terminating, that kinda breaks your XPC named endpoint. Any clients that try to talk to that endpoint will be opening connections and sending messages with no hope of a reply.
Do you mean using xpc_transaction_begin and xpc_transaction_end?
Well, kinda.
You enable transaction via the EnableTransactions
property in your launchd
property list. You can then manually call xpc_transaction_begin
and xpc_transaction_end
to start and end a transaction. However, in many cases that’s not necessary. XPC starts a transaction when it delivers a request to your connection and ends it when you complete that request. So, if you only handle XPC requests, the transaction support is fully automatic.
The transaction API is for cases where that automatic support doesn’t work. For example, if you want to reply to a request and then do some housekeeping, you’d start a transaction before you reply and then end that transaction once the housekeeping is done.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"