-
Notifications
You must be signed in to change notification settings - Fork 22
Change runDetached to return a ProcessHandle instead of a ProcessIdentifier #95
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: eng/PR-platform-handles
Are you sure you want to change the base?
Conversation
e6e13a8
to
cebafd9
Compare
@compnerd Any thoughts on this or the associated GitHub issue? |
Exposing I do wonder if we need to worry about the resource leak as the |
I thought about that... I think we'd need to make Execution non-Copyable and add a deinit that calls CloseHandle? I seem to recall there was previous discussion about doing making Execution non-Copyable, but it didn't happen, maybe @iCharlesHu can provide some info on why that path wasn't chosen at the time? And then I wonder if we would want some method like "takeHandle" which would allow the client to explicitly take ownership of the HANDLE away from the Execution. |
7f1597d
to
6b7b547
Compare
cebafd9
to
7ad0121
Compare
I think we should start a discussion about this API change on the Swift forums. The current approach, which involves returning In my opinion, the only viable way to support this API on Windows is through a |
Doesn't Also, I would argue that returning a numeric pid on Unix is still a resource leak of sorts, since the zombie will remain in the process table until the user calls |
FWIW, I'm not sure we need runDetached as a dedicated API. I have a need for a long-running process and ended up creating a wrapper class that stores a Task as an ivar, whose body runs the closure based Subprocess API. That should work fine without the need for a dedicated runDetached API. |
2b8c265
to
6422350
Compare
7ad0121
to
c8c66e1
Compare
@iCharlesHu I ended up splitting part of this change into #101 (which also introduces new API but is independently useful of these runDetached-specific issues), and now instead of returning Execution, runDetached returns a new non-Copyable type ProcessHandle which guarantees that the underlying platform handle is released (so there can be no resource leaks) while still solving the underlying race condition since the caller now has access to the platform handles from the return value of runDetached. Happy to still start a thread on the Swift forums if you think it's needed but hopefully this removes the resource leakage controversy in an elegant way! |
FWIW, this was my initial feedback as well. I don't see a need for this API as well since users can just spawn a task to do this detached work. I do recall that @iCharlesHu had a good point for why we need it anyways.
I'm a bit worried about this in general but not too familiar with Windows. The reason we see very little |
…tifier Currently runDetached returns a ProcessIdentifier, which on Unix is a pid and on Windows is a numeric process identifier. Similar to #92, there is a Windows-specific race condition here. On Unix the pid will be valid until someone waitid's it. But on Windows the ProcessIdentifier may already be invalid by the time runDetached returns. This patch now returns a non-copyable ProcessHandle, which provides access to both the ProcessIdentifier and the underlying platform handles (like Execution), while also guaranteeing that the underlying platform handles are released once the ProcessHandle goes out of scope. In effect, the platform handles are now released at the end of the runDetached caller's scope, rather than just before runDetached itself returns to the caller, solving the Windows-specific race condition. This requires new API because ProcessIdentifier is Hashable and Codable and can't reasonably be made non-Copyable. Similarly, it's likely undesirable to use Execution as the return type because it too would need to be made non-Copyable to prevent the resource leak and there is at least one example in existing tests which requires Execution to be Copyable. Closes #94
eba918b
to
e0559da
Compare
c8c66e1
to
14c7b48
Compare
This is a good point. CloseHandle can fail, but should only be in cases where you've given an invalid handle or tried to close the same one multiple times, both of which are programmer error and can be precondition'd. I'm not sure if there could be platforms in the future where this is not the case (Fuschia or something?), but for now any current and speculative API calls in teardown would be CloseHandle on Windows and close on POSIX (for process file descriptors, which Linux and FreeBSD both have). Indeed if we could simply remove runDetached entirely, that would solve the problem. I'm interested in hearing @iCharlesHu's original reasoning for why we needed it, or if we could instead express whatever that was with the closure-based API. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This API change needs to be discussed.
@swift-ci please test |
Currently runDetached returns a ProcessIdentifier, which on Unix is a pid and on Windows is a numeric process identifier. Similar to #92, there is a Windows-specific race condition here. On Unix the pid will be valid until someone waitid's it. But on Windows the ProcessIdentifier may already be invalid by the time runDetached returns.
This patch now returns a non-copyable ProcessHandle, which provides access to both the ProcessIdentifier and the underlying platform handles (like Execution), while also guaranteeing that the underlying platform handles are released once the ProcessHandle goes out of scope. In effect, the platform handles are now released at the end of the runDetached caller's scope, rather than just before runDetached itself returns to the caller, solving the Windows-specific race condition.
This requires new API because ProcessIdentifier is Hashable and Codable and can't reasonably be made non-Copyable. Similarly, it's likely undesirable to use Execution as the return type because it too would need to be made non-Copyable to prevent the resource leak and there is at least one example in existing tests which requires Execution to be Copyable.
Closes #94