Repository navigation
Conditionally adopt swift-subprocess - #638
jakepetroules wants to merge 4 commits into
Conversation
|
@swift-ci test |
7e290ca to
5d1747c
Compare
|
@swift-ci test |
| platformOptions.teardownSequence = [.gracefulShutDown(allowedDurationToNextStep: .seconds(5))] | ||
| #if os(macOS) | ||
| if highPriority { | ||
| platformOptions.qualityOfService = .userInitiated |
There was a problem hiding this comment.
@compnerd Would it seem reasonable to call SetPriorityClass with HIGH_PRIORITY_CLASS for Windows (REALTIME_PRIORITY_CLASS definitely sounded excessive)? Currently this is used to elevate the build service process so that it can serve high-priority requests more efficiently (e.g. with Swift Concurrency task priority set higher than normal).
There was a problem hiding this comment.
Hmm, we should try it - it can saturate the system to the point of being unusable though, so I am a little concerned about that.
5d1747c to
1d4c11c
Compare
|
@swift-ci test |
922c246 to
bd4c32d
Compare
| platformOptions.teardownSequence = [.gracefulShutDown(allowedDurationToNextStep: .seconds(5))] | ||
| } | ||
| let result = try await Subprocess.run(.path(FilePath(url.filePath.str)), arguments: .init(arguments), environment: environment.map { .custom(.init($0)) } ?? .inherit, workingDirectory: (currentDirectoryURL?.filePath.str).map { FilePath($0) } ?? nil, platformOptions: platformOptions, body: { execution, inputWriter, outputReader, errorReader in | ||
| try await inputWriter.finish() |
There was a problem hiding this comment.
potential deadlock here. You can't assume that you can fully unload the stdin w/o reading stdout/err
There was a problem hiding this comment.
There's no deadlock here, all this is doing is closing a file descriptor. We have no input. That said, I'll move it below the output reading just to be correct.
| } | ||
| let result = try await Subprocess.run(.path(FilePath(url.filePath.str)), arguments: .init(arguments), environment: environment.map { .custom(.init($0)) } ?? .inherit, workingDirectory: (currentDirectoryURL?.filePath.str).map { FilePath($0) } ?? nil, platformOptions: platformOptions, body: { execution, inputWriter, outputReader, errorReader in | ||
| try await inputWriter.finish() | ||
| async let stdoutBytes = outputReader.collect().flatMap { $0.withUnsafeBytes(Array.init) } |
There was a problem hiding this comment.
so? we can't use Span yet, this still has to build with 6.1
| let result = try await Subprocess.run(.path(FilePath(url.filePath.str)), arguments: .init(arguments), environment: environment.map { .custom(.init($0)) } ?? .inherit, workingDirectory: (currentDirectoryURL?.filePath.str).map { FilePath($0) } ?? nil, platformOptions: platformOptions, body: { execution, inputWriter, outputReader, errorReader in | ||
| try await inputWriter.finish() | ||
| async let stdoutBytes = outputReader.collect().flatMap { $0.withUnsafeBytes(Array.init) } | ||
| async let stderrBytes = errorReader.collect().flatMap { $0.withUnsafeBytes(Array.init) } |
There was a problem hiding this comment.
collect will load all of this potentially infinite stream into memory and I don't even see a limit, seems dangerous. If anything, limit it to something high like 32 MB and throw if we're blowing through that.
There was a problem hiding this comment.
This is existing behavior; we can address it separately.
89d45c3 to
f84bfcf
Compare
5cd9b6f to
ec02157
Compare
e6eed8f to
553f25f
Compare
|
@swift-ci test |
|
@swift-ci test |
|
Moving to draft -- SwiftSubprocess is on its way to 1.0 with some API changes, so we might as well hold off until then. |
ceaf055 to
bed300e
Compare
|
@swift-ci test |
bed300e to
4f3de6e
Compare
|
@swift-ci test |
4f3de6e to
de0160b
Compare
0922413 to
bf161b7
Compare
|
Please test with following PRs: @swift-ci please build toolchain Linux platform |
|
Please test with following PRs: @swift-ci please build toolchain macOS platform |
|
Please test with following PRs: @swift-ci please build toolchain Windows platform |
bf161b7 to
9be9ce5
Compare
9be9ce5 to
814774e
Compare
666f639 to
b7a5d07
Compare
|
Now waiting on a new tag of swift-subprocess with the recent CMake changes, and for swiftlang/swift to adopt that in update-checkout. |
This fully resolves working directory thread safety issues with subprocess spawning across all platforms. For now, subprocess is adopted conditionally in order to continue building in certain environments where the Subprocess module may not be available, in which case we fall back to Foundation Process. Closes swiftlang#441
- Require swift-subprocess 1.0.1 and adapt to its API (Configuration(executable:), the Execution-based run overload, closureResult). - Use .combinedWithOutput for merged output instead of a manually shared pipe. - Collect output without relying on the SubprocessFoundation trait, which isn't enabled in CMake builds of swift-subprocess. - Map swift-subprocess launch failures to RunProcessLaunchError, matching the Foundation.Process code path. - Restore the @test attribute on ProcessTests.workingDirectory. - Build swift-system before swift-subprocess in the CMake smoke test so that swift-subprocess doesn't fall back to fetching swift-system from the network.
Optionally find SwiftSubprocess and link it into SWBUtil, so CMake builds (including the toolchain) use swift-subprocess rather than Foundation.Process. SwiftBuildConfig.cmake loads SwiftSubprocess for clients when it was used, so that the exported SWBUtil target's link interface resolves.
b7a5d07 to
a92d36c
Compare
| if("@SwiftSubprocess_FOUND@" AND NOT TARGET SwiftSubprocess::Subprocess) | ||
| find_package(SwiftSubprocess CONFIG REQUIRED | ||
| NO_DEFAULT_PATH PATHS "@SwiftSubprocess_DIR@") | ||
| endif() |
There was a problem hiding this comment.
Can we avoid this and use CMakeFindDependencyMacro instead? That is meant to propagate the dependency across the boundary to the consumers without them having to do find_package and pass along the variables. It isn't perfect because it might lead to under-specifying the dependencies, but I think that it is still a good option.
This fully resolves working directory thread safety issues with subprocess spawning across all platforms. For now, subprocess is adopted conditionally in order to continue building in certain environments where the Subprocess module may not be available, in which case we fall back to Foundation Process.
Closes #441
(migrated from #584 in accordance with our new policy to require PRs from forks)