Skip to content

Commit a875d8c

Browse files
authored
[Driver] Preserve filelists when a subprocess crashes. (#9849)
This should make it easier to rerun crashed jobs that use filelists; previously you'd have to run the top-level driver command again with -save-temps. I didn't want to save /all/ temporary files because that often includes things like .o files, which could fill up your disk pretty quickly. But we can always tweak this later.
1 parent ae98497 commit a875d8c

File tree

8 files changed

+66
-25
lines changed

8 files changed

+66
-25
lines changed

include/swift/Driver/Compilation.h

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,13 @@ enum class OutputLevel {
5757
Parseable,
5858
};
5959

60+
/// Indicates whether a temporary file should always be preserved if a part of
61+
/// the compilation crashes.
62+
enum class PreserveOnSignal : bool {
63+
No,
64+
Yes
65+
};
66+
6067
class Compilation {
6168
friend class PerformJobsState;
6269
private:
@@ -87,8 +94,8 @@ class Compilation {
8794

8895
/// Temporary files that should be cleaned up after the compilation finishes.
8996
///
90-
/// These apply whether the compilation succeeds or fails.
91-
std::vector<std::string> TempFilePaths;
97+
/// These apply whether the compilation succeeds or fails. If the
98+
llvm::StringMap<PreserveOnSignal> TempFilePaths;
9299

93100
/// Write information about this compilation to this file.
94101
///
@@ -174,14 +181,13 @@ class Compilation {
174181
}
175182
Job *addJob(std::unique_ptr<Job> J);
176183

177-
void addTemporaryFile(StringRef file) {
178-
TempFilePaths.push_back(file.str());
184+
void addTemporaryFile(StringRef file,
185+
PreserveOnSignal preserve = PreserveOnSignal::No) {
186+
TempFilePaths[file] = preserve;
179187
}
180188

181189
bool isTemporaryFile(StringRef file) {
182-
// TODO: Use a set instead of a linear search.
183-
return std::find(TempFilePaths.begin(), TempFilePaths.end(), file) !=
184-
TempFilePaths.end();
190+
return TempFilePaths.count(file);
185191
}
186192

187193
const llvm::opt::DerivedArgList &getArgs() const { return *TranslatedArgs; }
@@ -255,9 +261,12 @@ class Compilation {
255261
private:
256262
/// \brief Perform all jobs.
257263
///
258-
/// \returns exit code of the first failed Job, or 0 on success. A return
259-
/// value of -2 indicates that a Job crashed during execution.
260-
int performJobsImpl();
264+
/// \param[out] abnormalExit Set to true if any job exits abnormally (i.e.
265+
/// crashes).
266+
///
267+
/// \returns exit code of the first failed Job, or 0 on success. If a Job
268+
/// crashes during execution, a negative value will be returned.
269+
int performJobsImpl(bool &abnormalExit);
261270

262271
/// \brief Performs a single Job by executing in place, if possible.
263272
///

lib/Driver/Compilation.cpp

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@ namespace driver {
165165
/// Cumulative result of PerformJobs(), accumulated from subprocesses.
166166
int Result = EXIT_SUCCESS;
167167

168+
/// True if any Job crashed.
169+
bool AnyAbnormalExit = false;
170+
168171
/// Timers for monitoring execution time of subprocesses.
169172
llvm::TimerGroup DriverTimerGroup {"driver", "Driver Compilation Time"};
170173
llvm::SmallDenseMap<const Job *, std::unique_ptr<llvm::Timer>, 16>
@@ -470,6 +473,7 @@ namespace driver {
470473

471474
// Since the task signalled, unconditionally set result to -2.
472475
Result = -2;
476+
AnyAbnormalExit = true;
473477

474478
return TaskFinishedResponse::StopExecution;
475479
}
@@ -689,6 +693,10 @@ namespace driver {
689693
Result = Comp.Diags.hadAnyError();
690694
return Result;
691695
}
696+
697+
bool hadAnyAbnormalExit() {
698+
return AnyAbnormalExit;
699+
}
692700
};
693701
} // namespace driver
694702
} // namespace swift
@@ -816,8 +824,7 @@ static bool writeFilelistIfNecessary(const Job *job, DiagnosticEngine &diags) {
816824
return true;
817825
}
818826

819-
int Compilation::performJobsImpl() {
820-
827+
int Compilation::performJobsImpl(bool &abnormalExit) {
821828
PerformJobsState State(*this);
822829

823830
State.scheduleInitialJobs();
@@ -833,6 +840,7 @@ int Compilation::performJobsImpl() {
833840
InputInfo);
834841
}
835842

843+
abnormalExit = State.hadAnyAbnormalExit();
836844
return State.getResult();
837845
}
838846

@@ -917,15 +925,14 @@ int Compilation::performJobs() {
917925
if (!TaskQueue::supportsParallelExecution() && NumberOfParallelCommands > 1) {
918926
Diags.diagnose(SourceLoc(), diag::warning_parallel_execution_not_supported);
919927
}
920-
921-
int result = performJobsImpl();
928+
929+
bool abnormalExit;
930+
int result = performJobsImpl(abnormalExit);
922931

923932
if (!SaveTemps) {
924-
// FIXME: Do we want to be deleting temporaries even when a child process
925-
// crashes?
926-
for (auto &path : TempFilePaths) {
927-
// Ignore the error code for removing temporary files.
928-
(void)llvm::sys::fs::remove(path);
933+
for (const auto &pathPair : TempFilePaths) {
934+
if (!abnormalExit || pathPair.getValue() == PreserveOnSignal::No)
935+
(void)llvm::sys::fs::remove(pathPair.getKey());
929936
}
930937
}
931938

@@ -945,7 +952,7 @@ const char *Compilation::getAllSourcesPath() const {
945952
llvm::report_fatal_error("unable to create list of input sources");
946953
}
947954
auto *mutableThis = const_cast<Compilation *>(this);
948-
mutableThis->addTemporaryFile(Buffer.str());
955+
mutableThis->addTemporaryFile(Buffer.str(), PreserveOnSignal::Yes);
949956
mutableThis->AllSourceFilesPath = getArgs().MakeArgString(Buffer);
950957
}
951958
return AllSourceFilesPath;

lib/Driver/ToolChain.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ ToolChain::JobContext::getTemporaryFilePath(const llvm::Twine &name,
5757
llvm::report_fatal_error("unable to create temporary file for filelist");
5858
}
5959

60-
C.addTemporaryFile(buffer.str());
60+
C.addTemporaryFile(buffer.str(), PreserveOnSignal::Yes);
6161
// We can't just reference the data in the TemporaryFiles vector because
6262
// that could theoretically get copied to a new address.
6363
return C.getArgs().MakeArgString(buffer.str());

test/Driver/Dependencies/Inputs/update-dependencies-bad.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,16 @@
1212
# ----------------------------------------------------------------------------
1313
#
1414
# Fails if the input file is named "bad.swift" or "crash.swift"; otherwise
15-
# dispatches to update-dependencies.py. "crash.swift" gives an exit code
16-
# other than 1.
15+
# dispatches to update-dependencies.py. "crash.swift" results in an
16+
# exit-by-SIGKILL
1717
#
1818
# ----------------------------------------------------------------------------
1919

2020
from __future__ import print_function
2121

2222
import os
2323
import shutil
24+
import signal
2425
import sys
2526

2627
assert sys.argv[1] == '-frontend'
@@ -42,7 +43,8 @@
4243
if os.path.basename(primaryFile) == 'bad.swift':
4344
sys.exit(1)
4445
else:
45-
sys.exit(129)
46+
sys.stdout.flush()
47+
os.kill(os.getpid(), signal.SIGKILL)
4648

4749
execDir = os.path.dirname(os.path.abspath(__file__))
4850
exec(open(os.path.join(execDir, "update-dependencies.py")).read())

test/Driver/Dependencies/whole-module-build-record.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@
1414

1515

1616
// RUN: touch -t 201401240006 %t/other.swift
17-
// RUN: cd %t && not %swiftc_driver -c -driver-use-frontend-path %S/Inputs/fail.py -output-file-map %t/output.json -whole-module-optimization ./main.swift ./other.swift -module-name main -j1 -v 2>&1
17+
// RUN: cd %t && not %swiftc_driver -c -driver-use-frontend-path %S/../Inputs/fail.py -output-file-map %t/output.json -whole-module-optimization ./main.swift ./other.swift -module-name main -j1 -v 2>&1
1818

1919
// Just don't crash.

test/Driver/Inputs/crash.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/usr/bin/env python
2+
# crash.py - Sends SIGKILL to self. -*- python -*-
3+
#
4+
# This source file is part of the Swift.org open source project
5+
#
6+
# Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
7+
# Licensed under Apache License v2.0 with Runtime Library Exception
8+
#
9+
# See https://swift.org/LICENSE.txt for license information
10+
# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
11+
12+
import os
13+
import signal
14+
os.kill(os.getpid(), signal.SIGKILL)
File renamed without changes.

test/Driver/filelists.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,15 @@
3232
// CHECK-WMO-THREADED-NEXT: ...with output!
3333
// CHECK-WMO-THREADED-NOT: Handled
3434

35+
// RUN: mkdir -p %t/tmp-fail/
36+
// RUN: (cd %t && not env TMPDIR="%t/tmp-fail/" %swiftc_driver_plain -driver-use-frontend-path %S/Inputs/fail.py -c ./a.swift ./b.swift ./c.swift -module-name main -target x86_64-apple-macosx10.9 -driver-use-filelists -output-file-map=%S/Inputs/filelists/output.json -force-single-frontend-invocation -num-threads 1)
37+
// RUN: not ls %t/tmp-fail/sources-*
38+
// RUN: not ls %t/tmp-fail/outputs-*
39+
40+
// RUN: mkdir -p %t/tmp-crash/
41+
// RUN: (cd %t && not env TMPDIR="%t/tmp-crash/" %swiftc_driver_plain -driver-use-frontend-path %S/Inputs/crash.py -c ./a.swift ./b.swift ./c.swift -module-name main -target x86_64-apple-macosx10.9 -driver-use-filelists -output-file-map=%S/Inputs/filelists/output.json -force-single-frontend-invocation -num-threads 1)
42+
// RUN: ls %t/tmp-crash/sources-* %t/tmp-crash/outputs-*
43+
3544

3645
// RUN: (cd %t && env PATH=%t/bin/:$PATH %swiftc_driver_plain -driver-use-frontend-path %S/Inputs/filelists/check-filelist-abc.py -emit-library ./a.swift ./b.swift ./c.swift -module-name main -target x86_64-apple-macosx10.9 -driver-use-filelists -output-file-map=%S/Inputs/filelists/output.json 2>&1 | %FileCheck -check-prefix=CHECK-LINK %s)
3746
// RUN: (cd %t && env PATH=%t/bin/:$PATH %swiftc_driver_plain -driver-use-frontend-path %S/Inputs/filelists/check-filelist-abc.py -emit-library ./a.swift ./b.swift ./c.swift -module-name main -target x86_64-apple-macosx10.9 -driver-use-filelists -output-file-map=%S/Inputs/filelists/output.json -force-single-frontend-invocation -num-threads 1 2>&1 | %FileCheck -check-prefix=CHECK-LINK %s)

0 commit comments

Comments
 (0)