Skip to content

Commit 694fb03

Browse files
authored
Merge pull request swiftlang#145 from ddunbar/improve-cancellation
Improve cancellation
2 parents c47d2c4 + 7622e55 commit 694fb03

14 files changed

+313
-237
lines changed

include/llbuild/BuildSystem/BuildDescription.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class BuildKey;
4343
class BuildValue;
4444
class Command;
4545
class Node;
46+
struct QueueJobContext;
4647

4748
/// Context for information that may be needed for a configuration action.
4849
//
@@ -250,7 +251,11 @@ class Command {
250251
virtual void provideValue(BuildSystemCommandInterface&, core::Task*,
251252
uintptr_t inputID, const BuildValue& value) = 0;
252253

253-
virtual void inputsAvailable(BuildSystemCommandInterface&, core::Task*) = 0;
254+
/// Execute the command, and return the value.
255+
///
256+
/// This method will always be executed on the build execution queue.
257+
virtual BuildValue execute(BuildSystemCommandInterface&, core::Task*,
258+
QueueJobContext* context) = 0;
254259

255260
/// @}
256261
};

include/llbuild/BuildSystem/BuildSystem.h

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -124,11 +124,6 @@ class BuildSystemDelegate {
124124

125125
/// Called by the build system to get create the object used to dispatch work.
126126
virtual std::unique_ptr<BuildExecutionQueue> createExecutionQueue() = 0;
127-
128-
/// Called by the build system to determine if the build has been cancelled.
129-
///
130-
/// This is checked before starting each new command.
131-
virtual bool isCancelled() = 0;
132127

133128
/// Called by the build system to report a command failure.
134129
virtual void hadCommandFailure() = 0;
@@ -238,7 +233,7 @@ class BuildSystem {
238233
/// \returns The result of computing the value, or nil if the build failed.
239234
llvm::Optional<BuildValue> build(BuildKey target);
240235

241-
/// Cancel the current build
236+
/// Cancel the current build.
242237
void cancel();
243238

244239
/// @}

include/llbuild/BuildSystem/BuildSystemFrontend.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ class BuildSystemFrontendDelegate : public BuildSystemDelegate {
107107

108108
private:
109109
void* impl;
110-
std::atomic<bool> isCancelled_;
111110

112111
/// Default implementation, cannot be overriden by subclasses.
113112
virtual void setFileContentsBeingParsed(StringRef buffer) override;
@@ -140,10 +139,6 @@ class BuildSystemFrontendDelegate : public BuildSystemDelegate {
140139
/// Provides an appropriate execution queue based on the invocation options.
141140
virtual std::unique_ptr<BuildExecutionQueue> createExecutionQueue() override;
142141

143-
/// Provides a default cancellation implementation that will cancel when any
144-
/// command has failed.
145-
virtual bool isCancelled() override;
146-
147142
/// Cancels the current build.
148143
virtual void cancel();
149144

include/llbuild/BuildSystem/ExternalCommand.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,9 @@ class ExternalCommand : public Command {
138138
uintptr_t inputID,
139139
const BuildValue& value) override;
140140

141-
virtual void inputsAvailable(BuildSystemCommandInterface& bsci,
142-
core::Task* task) override;
141+
virtual BuildValue execute(BuildSystemCommandInterface& bsci,
142+
core::Task* task,
143+
QueueJobContext* context) override;
143144
};
144145

145146
}

lib/BuildSystem/BuildSystem.cpp

Lines changed: 74 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@ class BuildSystemImpl : public BuildSystemCommandInterface {
165165
/// Flag indicating if the build has been aborted.
166166
bool buildWasAborted = false;
167167

168+
/// Flag indicating if the build has been cancelled.
169+
std::atomic<bool> isCancelled_{ false };
170+
168171
/// @name BuildSystemCommandInterface Implementation
169172
/// @{
170173

@@ -297,7 +300,18 @@ class BuildSystemImpl : public BuildSystemCommandInterface {
297300
void setBuildWasAborted(bool value) {
298301
buildWasAborted = value;
299302
}
300-
303+
304+
/// Cancel the running build.
305+
void cancel() {
306+
isCancelled_ = true;
307+
getExecutionQueue().cancelAllJobs();
308+
}
309+
310+
/// Check if the build has been cancelled.
311+
bool isCancelled() {
312+
return isCancelled_;
313+
}
314+
301315
/// @}
302316
};
303317

@@ -309,10 +323,6 @@ static BuildSystemImpl& getBuildSystem(BuildEngine& engine) {
309323
return static_cast<BuildSystemEngineDelegate*>(
310324
engine.getDelegate())->getBuildSystem();
311325
}
312-
313-
static bool isCancelled(BuildEngine& engine) {
314-
return getBuildSystem(engine).getCommandInterface().getDelegate().isCancelled();
315-
}
316326

317327
/// This is the task used to "build" a target, it translates between the request
318328
/// for building a target key and the requests for all of its nodes.
@@ -361,7 +371,7 @@ class TargetTask : public Task {
361371

362372
virtual void inputsAvailable(BuildEngine& engine) override {
363373
// If the build should cancel, do nothing.
364-
if (isCancelled(engine)) {
374+
if (getBuildSystem(engine).isCancelled()) {
365375
engine.taskIsComplete(this, BuildValue::makeSkippedCommand().toData());
366376
return;
367377
}
@@ -835,6 +845,9 @@ class CommandTask : public Task {
835845
Command& command;
836846

837847
virtual void start(BuildEngine& engine) override {
848+
// Notify the client the command is preparing to run.
849+
getBuildSystem(engine).getDelegate().commandPreparing(&command);
850+
838851
command.start(getBuildSystem(engine).getCommandInterface(), this);
839852
}
840853

@@ -853,28 +866,33 @@ class CommandTask : public Task {
853866
}
854867

855868
virtual void inputsAvailable(BuildEngine& engine) override {
856-
// If the build should cancel, do nothing.
857-
if (isCancelled(engine)) {
858-
engine.taskIsComplete(this, BuildValue::makeSkippedCommand().toData());
859-
return;
860-
}
861-
862869
auto& bsci = getBuildSystem(engine).getCommandInterface();
863870
auto fn = [this, &bsci=bsci](QueueJobContext* context) {
864-
bool shouldSkip = !bsci.getDelegate().shouldCommandStart(&command);
871+
// If the build should cancel, do nothing.
872+
if (getBuildSystem(bsci.getBuildEngine()).isCancelled()) {
873+
bsci.taskIsComplete(this, BuildValue::makeCancelledCommand());
874+
return;
875+
}
865876

866-
if (shouldSkip) {
877+
// Check if the command should be skipped.
878+
if (!bsci.getDelegate().shouldCommandStart(&command)) {
867879
// We need to call commandFinished here because commandPreparing and
868880
// shouldCommandStart guarantee that they're followed by
869881
// commandFinished.
870882
bsci.getDelegate().commandFinished(&command);
871-
872883
bsci.taskIsComplete(this, BuildValue::makeSkippedCommand());
873-
} else {
874-
command.inputsAvailable(bsci, this);
884+
return;
885+
}
886+
887+
// Execute the command, with notifications to the delegate.
888+
auto result = command.execute(bsci, this, context);
889+
890+
// Inform the engine of the result.
891+
if (result.isFailedCommand()) {
892+
bsci.getDelegate().hadCommandFailure();
875893
}
894+
bsci.taskIsComplete(this, std::move(result));
876895
};
877-
878896
bsci.addJob({ &command, std::move(fn) });
879897
}
880898

@@ -2064,9 +2082,6 @@ class SymlinkCommand : public Command {
20642082

20652083
virtual void start(BuildSystemCommandInterface& bsci,
20662084
core::Task* task) override {
2067-
// Notify the client the command is preparing to run.
2068-
bsci.getDelegate().commandPreparing(this);
2069-
20702085
// The command itself takes no inputs, so just treat any declared inputs as
20712086
// "must follow" directives.
20722087
//
@@ -2088,70 +2103,53 @@ class SymlinkCommand : public Command {
20882103
assert(0 && "unexpected API call");
20892104
}
20902105

2091-
virtual void inputsAvailable(BuildSystemCommandInterface& bsci,
2092-
core::Task* task) override {
2093-
// If the build should cancel, do nothing.
2094-
if (bsci.getDelegate().isCancelled()) {
2095-
bsci.taskIsComplete(task, BuildValue::makeCancelledCommand());
2096-
return;
2097-
}
2098-
2106+
virtual BuildValue execute(BuildSystemCommandInterface& bsci,
2107+
core::Task* task,
2108+
QueueJobContext* context) override {
20992109
// It is an error if this command isn't configured properly.
21002110
if (!output) {
2101-
bsci.getDelegate().hadCommandFailure();
2102-
bsci.taskIsComplete(task, BuildValue::makeFailedCommand());
2103-
return;
2111+
return BuildValue::makeFailedCommand();
21042112
}
2105-
2106-
auto fn = [this, &bsci=bsci, task](QueueJobContext* context) {
2107-
// Notify the client the actual command body is going to run.
2108-
bsci.getDelegate().commandStarted(this);
2109-
2110-
// Create the directory containing the symlink, if necessary.
2111-
//
2112-
// FIXME: Shared behavior with ExternalCommand.
2113-
{
2114-
auto parent = llvm::sys::path::parent_path(output->getName());
2115-
if (!parent.empty()) {
2116-
(void) bsci.getDelegate().getFileSystem().createDirectories(parent);
2117-
}
2113+
2114+
// Create the directory containing the symlink, if necessary.
2115+
//
2116+
// FIXME: Shared behavior with ExternalCommand.
2117+
{
2118+
auto parent = llvm::sys::path::parent_path(output->getName());
2119+
if (!parent.empty()) {
2120+
(void) bsci.getDelegate().getFileSystem().createDirectories(parent);
21182121
}
2122+
}
21192123

2120-
// Create the symbolic link (note that despite the poorly chosen LLVM
2121-
// name, this is a symlink).
2122-
//
2123-
// FIXME: Need to use the filesystem interfaces.
2124-
auto success = true;
2125-
if (llvm::sys::fs::create_link(contents, output->getName())) {
2126-
// On failure, we attempt to unlink the file and retry.
2127-
basic::sys::unlink(output->getName().str().c_str());
2124+
// Create the symbolic link (note that despite the poorly chosen LLVM
2125+
// name, this is a symlink).
2126+
//
2127+
// FIXME: Need to use the filesystem interfaces.
2128+
bsci.getDelegate().commandStarted(this);
2129+
auto success = true;
2130+
if (llvm::sys::fs::create_link(contents, output->getName())) {
2131+
// On failure, we attempt to unlink the file and retry.
2132+
basic::sys::unlink(output->getName().str().c_str());
21282133

2129-
if (llvm::sys::fs::create_link(contents, output->getName())) {
2130-
getBuildSystem(bsci.getBuildEngine()).error(
2131-
"", "unable to create symlink at '" + output->getName() + "'");
2132-
success = false;
2133-
}
2134+
if (llvm::sys::fs::create_link(contents, output->getName())) {
2135+
getBuildSystem(bsci.getBuildEngine()).error(
2136+
"", "unable to create symlink at '" + output->getName() + "'");
2137+
success = false;
21342138
}
2135-
2136-
// Notify the client the command is complete.
2137-
bsci.getDelegate().commandFinished(this);
2139+
}
2140+
bsci.getDelegate().commandFinished(this);
21382141

2139-
// Process the result.
2140-
if (!success) {
2141-
bsci.getDelegate().hadCommandFailure();
2142-
bsci.taskIsComplete(task, BuildValue::makeFailedCommand());
2143-
return;
2144-
}
2142+
// Process the result.
2143+
if (!success) {
2144+
return BuildValue::makeFailedCommand();
2145+
}
21452146

2146-
// Capture the *link* information of the output.
2147-
FileInfo outputInfo = output->getLinkInfo(
2148-
bsci.getDelegate().getFileSystem());
2147+
// Capture the *link* information of the output.
2148+
FileInfo outputInfo = output->getLinkInfo(
2149+
bsci.getDelegate().getFileSystem());
21492150

2150-
// Complete with a successful result.
2151-
bsci.taskIsComplete(
2152-
task, BuildValue::makeSuccessfulCommand(outputInfo, getSignature()));
2153-
};
2154-
bsci.addJob({ this, std::move(fn) });
2151+
// Complete with a successful result.
2152+
return BuildValue::makeSuccessfulCommand(outputInfo, getSignature());
21552153
}
21562154

21572155
public:
@@ -2428,7 +2426,6 @@ bool BuildSystem::build(StringRef name) {
24282426

24292427
void BuildSystem::cancel() {
24302428
if (impl) {
2431-
auto buildSystemImpl = static_cast<BuildSystemImpl*>(impl);
2432-
buildSystemImpl->getCommandInterface().getExecutionQueue().cancelAllJobs();
2429+
static_cast<BuildSystemImpl*>(impl)->cancel();
24332430
}
24342431
}

lib/BuildSystem/BuildSystemFrontend.cpp

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ BuildSystemFrontendDelegate(llvm::SourceMgr& sourceMgr,
224224
StringRef name,
225225
uint32_t version)
226226
: BuildSystemDelegate(name, version),
227-
impl(new BuildSystemFrontendDelegateImpl(sourceMgr, invocation)), isCancelled_(false)
227+
impl(new BuildSystemFrontendDelegateImpl(sourceMgr, invocation))
228228
{
229229

230230
}
@@ -333,18 +333,7 @@ BuildSystemFrontendDelegate::createExecutionQueue() {
333333
impl->invocation.environment));
334334
}
335335

336-
bool BuildSystemFrontendDelegate::isCancelled() {
337-
// Stop the build after any command failures.
338-
return getNumFailedCommands() > 0 || isCancelled_;
339-
}
340-
341336
void BuildSystemFrontendDelegate::cancel() {
342-
// FIXME: We should audit that a build is happening.
343-
if (isCancelled_) {
344-
return;
345-
}
346-
isCancelled_ = true;
347-
348337
auto delegateImpl = static_cast<BuildSystemFrontendDelegateImpl*>(impl);
349338
auto system = delegateImpl->system;
350339
if (system) {
@@ -355,7 +344,6 @@ void BuildSystemFrontendDelegate::cancel() {
355344
void BuildSystemFrontendDelegate::resetForBuild() {
356345
auto impl = static_cast<BuildSystemFrontendDelegateImpl*>(this->impl);
357346

358-
isCancelled_ = false;
359347
impl->numFailedCommands = 0;
360348
}
361349

0 commit comments

Comments
 (0)