-
Notifications
You must be signed in to change notification settings - Fork 26
Remove runDetached API #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?
Remove runDetached API #95
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 |
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 |
e0559da
to
e65a537
Compare
14c7b48
to
636efc0
Compare
Currently runDetached returns a ProcessIdentifier, which contains a pidfd on Linux and HANDLE on Windows. These handles are closed as soon as runDetached returns, making the values effectively useless to the caller. Similar to #92, there is a Windows-specific race condition here. On Unix the pid will be valid until someone waitid's it, so a caller _could_ use pidfd_open to get a new pidfd. But on Windows the ProcessIdentifier may already be invalid by the time runDetached returns and therefore OpenProcess can't be used to recover a handle. On FreeBSD one can't get a process descriptor from a PID at all (PDs are only for child processes). In order to avoid these race conditions, runDetached would need to either return a type which manages the lifetime of the various platform-specific handles, or leak the handles and leave them to be managed by the user. Due to questionable utility of these APIs in the first place (the closure based API can be used in conjunction with a Task to do pretty much everything runDetached can, without the downsides), we simply remove them. Closes #94
e65a537
to
37a1e4e
Compare
636efc0
to
2967cad
Compare
Currently runDetached returns a ProcessIdentifier, which contains a pidfd on Linux and HANDLE on Windows. These handles are closed as soon as runDetached returns, making the values effectively useless to the caller. Similar to #92, there is a Windows-specific race condition here. On Unix the pid will be valid until someone waitid's it, so a caller could use pidfd_open to get a new pidfd. But on Windows the ProcessIdentifier may already be invalid by the time runDetached returns and therefore OpenProcess can't be used to recover a handle. On FreeBSD one can't get a process descriptor from a PID at all (PDs are only for child processes).
In order to avoid these race conditions, runDetached would need to either return a type which manages the lifetime of the various platform-specific handles, or leak the handles and leave them to be managed by the user. Due to questionable utility of these APIs in the first place (the closure based API can be used in conjunction with a Task to do pretty much everything runDetached can, without the downsides), we simply remove them.
Closes #94