Skip to content

Commit 8c8dbbf

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 1163367 commit 8c8dbbf

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

@@ -255,11 +259,15 @@ extension SubprocessError {
255259
)
256260
}
257261

258-
internal static func processControlFailed(_ operation: ProcessControlOperation, underlyingError: UnderlyingError?) -> Self {
262+
internal static func processControlFailed(
263+
_ operation: ProcessControlOperation,
264+
reason: String? = nil,
265+
underlyingError: UnderlyingError?
266+
) -> Self {
259267
return SubprocessError(
260268
code: .processControlFailed,
261269
underlyingError: underlyingError,
262-
context: [.processControlFailed: .processControlOperation(operation)]
270+
context: [.processControlFailed: .processControlOperation(operation, reason: reason)]
263271
)
264272
}
265273

0 commit comments

Comments
 (0)