Skip to content

Commit 38fddc3

Browse files
committed
Support configurable Windows Job Object assignment
On Windows, processes are currently assigned to Job Objects unconditionally. The drawback to this is that assignment can fail when the parent is already in a Job Object that doesn't allow nesting, or when the system otherwise cannot form a valid hierarchy. Add `PlatformOptions.JobObjectAssignment`, describing how Job Object assignment is handled. The default behavior of `.always` matches the current behavior.
1 parent 6b0d119 commit 38fddc3

4 files changed

Lines changed: 268 additions & 96 deletions

File tree

Sources/Subprocess/Error.swift

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ extension SubprocessError {
112112
private enum Context: Sendable, Hashable {
113113
case string(String)
114114
case int(Int)
115-
case processControlOperation(ProcessControlOperation)
115+
case processControlOperation(ProcessControlOperation, reason: String?)
116116
}
117117

118118
internal enum ProcessControlOperation: Sendable, Hashable {
@@ -199,22 +199,26 @@ extension SubprocessError: CustomStringConvertible, CustomDebugStringConvertible
199199
}
200200

201201
case .processControlFailed:
202-
if let context = self.context[self.code],
203-
case .processControlOperation(let operation) = context
204-
{
205-
switch operation {
206-
case .sendSignal(let signal):
207-
return "Failed to send signal \(signal) to child process"
208-
case .terminate:
209-
return "Failed to terminate child process."
210-
case .suspend:
211-
return "Failed to suspend child process."
212-
case .resume:
213-
return "Failed to resume child process."
214-
}
215-
} else {
202+
guard let context = self.context[self.code],
203+
case .processControlOperation(let operation, let reason) = context
204+
else {
216205
return "Failed to control child process state"
217206
}
207+
var message: [String]
208+
switch operation {
209+
case .sendSignal(let signal):
210+
message = ["Failed to send signal \(signal) to child process."]
211+
case .terminate:
212+
message = ["Failed to terminate child process."]
213+
case .suspend:
214+
message = ["Failed to suspend child process."]
215+
case .resume:
216+
message = ["Failed to resume child process."]
217+
}
218+
if let reason {
219+
message.append("Reason: \(reason)")
220+
}
221+
return message.joined(separator: " ")
218222
}
219223
}
220224

@@ -290,11 +294,15 @@ extension SubprocessError {
290294
)
291295
}
292296

293-
internal static func processControlFailed(_ operation: ProcessControlOperation, underlyingError: UnderlyingError?) -> Self {
297+
internal static func processControlFailed(
298+
_ operation: ProcessControlOperation,
299+
reason: String? = nil,
300+
underlyingError: UnderlyingError?
301+
) -> Self {
294302
return SubprocessError(
295303
code: .processControlFailed,
296304
underlyingError: underlyingError,
297-
context: [.processControlFailed: .processControlOperation(operation)]
305+
context: [.processControlFailed: .processControlOperation(operation, reason: reason)]
298306
)
299307
}
300308

0 commit comments

Comments
 (0)