Environment:
- macOS 26.6.2 (25G83), Apple silicon
- Xcode 26.6 (17F113)
- DriverKit SDK 25.5
I am implementing a DriverKit IOService with an IOUserClient. This is a lifecycle and object-ownership question independent of the device protocol.
The intended design admits at most one user client during a provider lifetime. Lifecycle methods run on the provider’s default queue, while IOUserClient ExternalMethod requests run on a separate serial IODispatchQueue. At most one device request may be in flight.
The shutdown invariant we need is:
- Stop accepting new requests.
- Allow every accepted request to complete exactly once, or cancel it.
- Observe completion of the operation queue’s cancellation handler.
- Call the inherited Stop implementation last.
- Perform no provider access afterward.
The relevant public documentation is:
IOService::Stop: https://developer.apple.com/documentation/driverkit/ioservice/stop
IODispatchQueue::Cancel: https://developer.apple.com/documentation/driverkit/iodispatchqueue/cancel
IOService::SetDispatchQueue: https://developer.apple.com/documentation/driverkit/ioservice/setdispatchqueue
For the normal path, the proposed sequence is conceptually:
Stop(provider): close request admission operationQueue->Cancel(cancellationHandler) wait for the cancellation handler from the separate queue super::Stop(provider)
I need clarification of the complete supported public API contract:
-
If IODispatchQueue::Cancel returns a non-success result, is its cancellation handler still guaranteed to execute? If it is not, what supported action lets Stop keep the provider and user client valid until previously accepted work is no longer capable of accessing them?
-
Is it supported for the provider and its one user client to share the provider-owned serial operation queue? If the IOUserClient stops independently, must it own and cancel a separate queue, or is there a supported per-client drain mechanism that does not cancel provider-owned work?
-
Is the driver’s public IOService::Stop override guaranteed to run on every termination path where accepted user-client work must be drained, including when the provider is already inactive or the DriverKit server has slept? If not, which public lifecycle callback supplies that drain point?
-
Is blocking the provider’s default queue inside Stop while awaiting the cancellation handler from a separate operation queue the supported interpretation of “wait for your cancellation handlers”? If not, what public continuation mechanism should be used before calling inherited Stop?
We also observed one power-management panic after sleep/wake:
HiMDScsiDriver::setPowerState(..., 0 -> 4) timed out after 20342 ms
The DEXT does not currently override SetPowerState. This panic motivates the lifecycle review, but I am not treating it as proof that the Stop/drain design caused the timeout.
I am looking specifically for a supported public DriverKit sequence. I do not want to rely on private framework entry points or infer object-lifetime guarantees from a successful build or experiment.