mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Merge pull request #58978 from ahoppen/pr/no-deadlock-cancellation-bigger-change
[SoruceKit] Audit SwiftASTManager to prevent deadlocks
This commit is contained in:
@@ -1182,6 +1182,7 @@ void ASTBuildOperation::schedule(WorkQueue Queue) {
|
|||||||
/*ExpectedOldState=*/State::Running);
|
/*ExpectedOldState=*/State::Running);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SmallVector<SwiftASTConsumerRef, 4> ConsumersToCancel;
|
||||||
{
|
{
|
||||||
llvm::sys::ScopedLock L(ConsumersAndResultMtx);
|
llvm::sys::ScopedLock L(ConsumersAndResultMtx);
|
||||||
if (Consumers.empty()) {
|
if (Consumers.empty()) {
|
||||||
@@ -1192,24 +1193,25 @@ void ASTBuildOperation::schedule(WorkQueue Queue) {
|
|||||||
if (CancellationFlag->load(std::memory_order_relaxed)) {
|
if (CancellationFlag->load(std::memory_order_relaxed)) {
|
||||||
assert(false && "We should only set the cancellation flag if there "
|
assert(false && "We should only set the cancellation flag if there "
|
||||||
"are no more consumers");
|
"are no more consumers");
|
||||||
for (auto &Consumer : Consumers) {
|
ConsumersToCancel = Consumers;
|
||||||
Consumer->cancelled();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (auto &Consumer : ConsumersToCancel) {
|
||||||
|
Consumer->cancelled();
|
||||||
|
}
|
||||||
|
|
||||||
std::string Error;
|
std::string Error;
|
||||||
assert(!Result && "We should only be producing a result once");
|
assert(!Result && "We should only be producing a result once");
|
||||||
ASTUnitRef AST = buildASTUnit(Error);
|
ASTUnitRef AST = buildASTUnit(Error);
|
||||||
SmallVector<SwiftASTConsumerRef, 4> LocalConsumers;
|
SmallVector<SwiftASTConsumerRef, 4> ConsumersToInform;
|
||||||
{
|
{
|
||||||
llvm::sys::ScopedLock L(ConsumersAndResultMtx);
|
llvm::sys::ScopedLock L(ConsumersAndResultMtx);
|
||||||
bool WasCancelled = CancellationFlag->load(std::memory_order_relaxed);
|
bool WasCancelled = CancellationFlag->load(std::memory_order_relaxed);
|
||||||
Result.emplace(AST, Error, WasCancelled);
|
Result.emplace(AST, Error, WasCancelled);
|
||||||
LocalConsumers = Consumers;
|
ConsumersToInform = Consumers;
|
||||||
Consumers = {};
|
Consumers = {};
|
||||||
}
|
}
|
||||||
for (auto &Consumer : LocalConsumers) {
|
for (auto &Consumer : ConsumersToInform) {
|
||||||
informConsumer(Consumer);
|
informConsumer(Consumer);
|
||||||
}
|
}
|
||||||
DidFinishCallback();
|
DidFinishCallback();
|
||||||
|
|||||||
@@ -135,8 +135,9 @@ public:
|
|||||||
typedef IntrusiveRefCntPtr<ASTUnit> ASTUnitRef;
|
typedef IntrusiveRefCntPtr<ASTUnit> ASTUnitRef;
|
||||||
|
|
||||||
class SwiftASTConsumer : public std::enable_shared_from_this<SwiftASTConsumer> {
|
class SwiftASTConsumer : public std::enable_shared_from_this<SwiftASTConsumer> {
|
||||||
/// Mutex guarding all accesses to CancellationRequestCallback
|
/// Mutex guarding all accesses to \c CancellationRequestCallback and \c
|
||||||
llvm::sys::Mutex CancellationRequestCallbackMtx;
|
/// IsCancelled.
|
||||||
|
llvm::sys::Mutex CancellationRequestCallbackAndIsCancelledMtx;
|
||||||
|
|
||||||
/// A callback that informs the \c ASTBuildOperation, which is producing the
|
/// A callback that informs the \c ASTBuildOperation, which is producing the
|
||||||
/// AST for this consumer, that the consumer is no longer of interest. Calling
|
/// AST for this consumer, that the consumer is no longer of interest. Calling
|
||||||
@@ -160,12 +161,17 @@ public:
|
|||||||
/// cause the \c ASTBuildOperation to be cancelled if no other consumer is
|
/// cause the \c ASTBuildOperation to be cancelled if no other consumer is
|
||||||
/// depending on it.
|
/// depending on it.
|
||||||
void requestCancellation() {
|
void requestCancellation() {
|
||||||
llvm::sys::ScopedLock L(CancellationRequestCallbackMtx);
|
Optional<std::function<void(std::shared_ptr<SwiftASTConsumer>)>>
|
||||||
IsCancelled = true;
|
CallbackToCall;
|
||||||
if (CancellationRequestCallback.has_value()) {
|
{
|
||||||
(*CancellationRequestCallback)(shared_from_this());
|
llvm::sys::ScopedLock L(CancellationRequestCallbackAndIsCancelledMtx);
|
||||||
|
IsCancelled = true;
|
||||||
|
CallbackToCall = CancellationRequestCallback;
|
||||||
CancellationRequestCallback = None;
|
CancellationRequestCallback = None;
|
||||||
}
|
}
|
||||||
|
if (CallbackToCall.has_value()) {
|
||||||
|
(*CallbackToCall)(shared_from_this());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a cancellation request callback that informs a \c ASTBuildOperation
|
/// Set a cancellation request callback that informs a \c ASTBuildOperation
|
||||||
@@ -177,20 +183,26 @@ public:
|
|||||||
/// called, \c NewCallback will be called immediately.
|
/// called, \c NewCallback will be called immediately.
|
||||||
void setCancellationRequestCallback(
|
void setCancellationRequestCallback(
|
||||||
std::function<void(std::shared_ptr<SwiftASTConsumer>)> NewCallback) {
|
std::function<void(std::shared_ptr<SwiftASTConsumer>)> NewCallback) {
|
||||||
llvm::sys::ScopedLock L(CancellationRequestCallbackMtx);
|
bool ShouldCallCallback = false;
|
||||||
assert(!CancellationRequestCallback.has_value() &&
|
{
|
||||||
"Can't set two cancellation callbacks on a SwiftASTConsumer");
|
llvm::sys::ScopedLock L(CancellationRequestCallbackAndIsCancelledMtx);
|
||||||
if (IsCancelled) {
|
assert(!CancellationRequestCallback.has_value() &&
|
||||||
|
"Can't set two cancellation callbacks on a SwiftASTConsumer");
|
||||||
|
if (IsCancelled) {
|
||||||
|
ShouldCallCallback = true;
|
||||||
|
} else {
|
||||||
|
CancellationRequestCallback = NewCallback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ShouldCallCallback) {
|
||||||
NewCallback(shared_from_this());
|
NewCallback(shared_from_this());
|
||||||
} else {
|
|
||||||
CancellationRequestCallback = NewCallback;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes the cancellation request callback previously set by \c
|
/// Removes the cancellation request callback previously set by \c
|
||||||
/// setCancellationRequestCallback.
|
/// setCancellationRequestCallback.
|
||||||
void removeCancellationRequestCallback() {
|
void removeCancellationRequestCallback() {
|
||||||
llvm::sys::ScopedLock L(CancellationRequestCallbackMtx);
|
llvm::sys::ScopedLock L(CancellationRequestCallbackAndIsCancelledMtx);
|
||||||
CancellationRequestCallback = None;
|
CancellationRequestCallback = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user