-
Notifications
You must be signed in to change notification settings - Fork 1.2k
waitUntilExit: ignore RunLoop.run()'s return value #4740
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
waitUntilExit: ignore RunLoop.run()'s return value #4740
Conversation
We've been seeing frequent (but not reproducible in isolation) failures in our builds where waitUntilExit returns but terminationStatus fails its precondition on hasFinished because isRunning is still true. This is a speculative fix, since I haven't been able to reproduce the failure in a self-contained test. This should be safe since Process.waitUntilExit isn't spec'd to relate to RunLoop. In particular there is no guarantee that "stopping" a RunLoop should cause waitUntilExit to return before the monitored process has exited.
@swift-ci please test |
The reason I believe this PR might help the observed issue is that it's possible to make RunLoop.run(.default) return false with sufficiently esoteric setup, such as: import Foundation
let waiter = DispatchGroup()
waiter.enter()
let t = Thread {
defer { waiter.leave() }
let runLoop = RunLoop.current
let customMode = RunLoop.Mode("yo")
runLoop.add(Timer(timeInterval: 0.1, repeats: false) { _ in
let innerRunResult = runLoop.run(mode: .default, before: Date(timeIntervalSinceNow: 0.1))
print("inner runLoop.run(.default) returned \(innerRunResult)")
}, forMode: customMode)
let outerRunResult = runLoop.run(mode: customMode, before: Date(timeIntervalSinceNow: 1))
print("outer runLoop.run(custom) returned: \(outerRunResult)")
}
t.start()
waiter.wait() which emits:
That |
@swift-ci please test macOS platform |
@swift-ci please test |
@swift-ci please test Windows platform |
@@ -1179,7 +1179,7 @@ void __CFInitialize(void) { | |||
if (!__CFInitialized && !__CFInitializing) { | |||
__CFInitializing = 1; | |||
|
|||
#if __HAS_DISPATCH__ | |||
#if __HAS_DISPATCH__ && !TARGET_OS_MAC |
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.
Ideally we would use the deployment version - but this is still forwards/backwards incompatible. @parkera - any thoughts? I'm tempted to say we merge this even with that limitation as this is blocking PRs for other platforms.
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 code is designed to go with the corresponding libdispatch, so if we are making a change to both (or a change to dispatch has already been made), they would go together into a Swift release.
LGTM, thanks @fischman-bcny and @compnerd |
* waitUntilExit: ignore RunLoop.run()'s return value We've been seeing frequent (but not reproducible in isolation) failures in our builds where waitUntilExit returns but terminationStatus fails its precondition on hasFinished because isRunning is still true. This is a speculative fix, since I haven't been able to reproduce the failure in a self-contained test. This should be safe since Process.waitUntilExit isn't spec'd to relate to RunLoop. In particular there is no guarantee that "stopping" a RunLoop should cause waitUntilExit to return before the monitored process has exited. * Exclude libdispatch_init() on TARGET_OS_MAC because it duplicates the call from the static constructor https://github.com/apple/swift-corelibs-libdispatch/blob/7fb9d5ceea562d60fe34ec55b6b165ae5aca38eb/src/init.c#L56 (cherry picked from commit 818de48)
We've been seeing frequent (but not reproducible in isolation) failures in our builds where waitUntilExit returns but terminationStatus fails its precondition on hasFinished because isRunning is still true. This is a speculative fix, since I haven't been able to reproduce the failure in a self-contained test.
This should be safe since Process.waitUntilExit isn't spec'd to relate to RunLoop. In particular there is no guarantee that "stopping" a RunLoop should cause waitUntilExit to return before the monitored process has exited.
Unrelated to the above, the second commit in this PR is required to unbreak XCTest's tests, which are run as part of this repo's CI (and so is required to be able to get a green run for this PR).
Absent that commit, XCTest's tests exit -5 on my M1 Pro and -4 on CI (with no output). On my machine, Console reveals:
and running under lldb blames
CFRuntime.c:1185
's call tolibdispatch_init()
.Breaking on
libdispatch_init
in lldb confirmslibdispatch_init()
is called twice, first byswift-corelibs-libdispatch/src/init.c
in an__attribute__((constructor))
and the second in the site being disabled in this commit.