Skip to content

Commit 7c9eed8

Browse files
authored
Merge pull request #961 from compnerd/5.6-abnormality
[5.6] SwiftDriver: address TODO about abnormal process termination
2 parents 5eec122 + cb9df1c commit 7c9eed8

File tree

6 files changed

+96
-12
lines changed

6 files changed

+96
-12
lines changed

Sources/SwiftDriver/Driver/ToolExecutionDelegate.swift

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,14 +91,15 @@ import Glibc
9191

9292
buildRecordInfo?.jobFinished(job: job, result: result)
9393

94-
// FIXME: Currently, TSCBasic.Process uses NSProcess on Windows and discards
95-
// the bits of the exit code used to differentiate between normal and abnormal
96-
// termination.
97-
#if !os(Windows)
94+
#if os(Windows)
95+
if case .abnormal = result.exitStatus {
96+
anyJobHadAbnormalExit = true
97+
}
98+
#else
9899
if case .signalled = result.exitStatus {
99100
anyJobHadAbnormalExit = true
100101
}
101-
#endif
102+
#endif
102103

103104
switch mode {
104105
case .silent:
@@ -123,7 +124,13 @@ import Glibc
123124
pid: pid).map {
124125
ParsableMessage(name: job.kind.rawValue, kind: .finished($0))
125126
}
126-
#if !os(Windows)
127+
#if os(Windows)
128+
case .abnormal(let exception):
129+
messages = constructAbnormalExitMessage(job: job, output: output,
130+
exception: exception, pid: pid).map {
131+
ParsableMessage(name: job.kind.rawValue, kind: .abnormal($0))
132+
}
133+
#else
127134
case .signalled(let signal):
128135
let errorMessage = strsignal(signal).map { String(cString: $0) } ?? ""
129136
messages = constructJobSignalledMessages(job: job, error: errorMessage, output: output,
@@ -132,6 +139,7 @@ import Glibc
132139
}
133140
#endif
134141
}
142+
135143
for message in messages {
136144
emit(message)
137145
}
@@ -265,6 +273,22 @@ private extension ToolExecutionDelegate {
265273
return FinishedMessage(exitStatus: Int(exitCode), output: output, pid: pid, realPid: realPid)
266274
}
267275

276+
// MARK: - Abnormal Exit
277+
func constructAbnormalExitMessage(job: Job, output: String?, exception: UInt32, pid: Int) -> [AbnormalExitMessage] {
278+
let result: [AbnormalExitMessage]
279+
if job.kind == .compile, job.primaryInputs.count > 1 {
280+
result = job.primaryInputs.map {
281+
guard let quasiPid = batchJobInputQuasiPIDMap[(job, $0)] else {
282+
fatalError("Parsable-Output batch sub-job abnormal exit with no matching started message: \(job.description): \($0.file.description)")
283+
}
284+
return AbnormalExitMessage(pid: quasiPid, realPid: pid, output: output, exception: exception)
285+
}
286+
} else {
287+
result = [AbnormalExitMessage(pid: pid, realPid: pid, output: output, exception: exception)]
288+
}
289+
return result
290+
}
291+
268292
// MARK: - Job Signalled
269293
func constructJobSignalledMessages(job: Job, error: String, output: String?,
270294
signal: Int32, pid: Int) -> [SignalledMessage] {

Sources/SwiftDriver/Execution/DriverExecutor.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,13 @@ extension DriverExecutor {
123123
switch exitStatus {
124124
case .terminated(let code):
125125
returnCode = Int(code)
126-
#if !os(Windows)
126+
#if os(Windows)
127+
case .abnormal(let exception):
128+
returnCode = Int(exception)
129+
#else
127130
case .signalled(let signal):
128131
returnCode = Int(signal)
129-
#endif
132+
#endif
130133
}
131134
return returnCode
132135
}

Sources/SwiftDriver/Execution/ParsableOutput.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import Foundation
1616
public enum Kind {
1717
case began(BeganMessage)
1818
case finished(FinishedMessage)
19+
case abnormal(AbnormalExitMessage)
1920
case signalled(SignalledMessage)
2021
case skipped(SkippedMessage)
2122
}
@@ -133,6 +134,27 @@ import Foundation
133134
}
134135
}
135136

137+
@_spi(Testing) public struct AbnormalExitMessage: Encodable {
138+
let pid: Int
139+
let process: ActualProcess
140+
let output: String?
141+
let exception: UInt32
142+
143+
public init(pid: Int, realPid: Int, output: String?, exception: UInt32) {
144+
self.pid = pid
145+
self.process = ActualProcess(realPid: realPid)
146+
self.output = output
147+
self.exception = exception
148+
}
149+
150+
private enum CodingKeys: String, CodingKey {
151+
case pid
152+
case process
153+
case output
154+
case exception
155+
}
156+
}
157+
136158
@_spi(Testing) public struct SignalledMessage: Encodable {
137159
let pid: Int
138160
let process: ActualProcess
@@ -174,6 +196,9 @@ import Foundation
174196
case .finished(let msg):
175197
try container.encode("finished", forKey: .kind)
176198
try msg.encode(to: encoder)
199+
case .abnormal(let msg):
200+
try container.encode("abnormal-exit", forKey: .kind)
201+
try msg.encode(to: encoder)
177202
case .signalled(let msg):
178203
try container.encode("signalled", forKey: .kind)
179204
try msg.encode(to: encoder)

Sources/SwiftDriver/Jobs/PrebuiltModulesJob.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,10 @@ fileprivate class ModuleCompileDelegate: JobExecutionDelegate {
122122
stderrStream.flush()
123123
}
124124
}
125-
#if !os(Windows)
125+
#if os(Windows)
126+
case .abnormal(let exception):
127+
diagnosticsEngine.emit(.remark("\(job.moduleName) exception: \(exception)"))
128+
#else
126129
case .signalled:
127130
diagnosticsEngine.emit(.remark("\(job.moduleName) interrupted"))
128131
#endif

Sources/SwiftDriverExecution/MultiJobExecutor.swift

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,13 @@ public final class MultiJobExecutor {
211211
switch (result.exitStatus, continueBuildingAfterErrors) {
212212
case (.terminated(let code), false) where code != EXIT_SUCCESS:
213213
isBuildCancelled = true
214-
#if !os(Windows)
214+
#if os(Windows)
215+
case (.abnormal, false):
216+
isBuildCancelled = true
217+
#else
215218
case (.signalled, _):
216219
isBuildCancelled = true
217-
#endif
220+
#endif
218221
default:
219222
break
220223
}
@@ -614,7 +617,10 @@ class ExecuteJobRule: LLBuildRule {
614617
if !job.kind.isCompile || code != EXIT_FAILURE {
615618
context.diagnosticsEngine.emit(.error_command_failed(kind: job.kind, code: code))
616619
}
617-
#if !os(Windows)
620+
#if os(Windows)
621+
case let .abnormal(exception):
622+
context.diagnosticsEngine.emit(.error_command_exception(kind: job.kind, exception: exception))
623+
#else
618624
case let .signalled(signal):
619625
// An interrupt of an individual compiler job means it was deliberatly cancelled,
620626
// most likely by the driver itself. This does not constitute an error.
@@ -667,4 +673,8 @@ private extension TSCBasic.Diagnostic.Message {
667673
static func error_command_signalled(kind: Job.Kind, signal: Int32) -> TSCBasic.Diagnostic.Message {
668674
.error("\(kind.rawValue) command failed due to signal \(signal) (use -v to see invocation)")
669675
}
676+
677+
static func error_command_exception(kind: Job.Kind, exception: UInt32) -> TSCBasic.Diagnostic.Message {
678+
.error("\(kind.rawValue) command failed due to exception \(exception) (use -v to see invocation)")
679+
}
670680
}

Tests/SwiftDriverTests/ParsableMessageTests.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,25 @@ final class ParsableMessageTests: XCTestCase {
117117
""")
118118
}
119119

120+
func testAbnormalExitMessage() throws {
121+
let exit = AbnormalExitMessage(pid: 1024, realPid: 1024, output: nil, exception: 0x8000_0003)
122+
let message = ParsableMessage(name: "compile", kind: .abnormal(exit))
123+
let encoded = try message.toJSON()
124+
let string = String(data: encoded, encoding: .utf8)!
125+
126+
XCTAssertEqual(string, """
127+
{
128+
"exception" : 2147483651,
129+
"kind" : "abnormal-exit",
130+
"name" : "compile",
131+
"pid" : 1024,
132+
"process" : {
133+
"real_pid" : 1024
134+
}
135+
}
136+
""")
137+
}
138+
120139
func testBeganBatchMessages() throws {
121140
do {
122141
try withTemporaryDirectory { path in

0 commit comments

Comments
 (0)