@@ -613,6 +613,13 @@ struct SwiftASTManager::Implementation {
613613 WorkQueue ASTBuildQueue{ WorkQueue::Dequeuing::Serial,
614614 " sourcekit.swift.ASTBuilding" };
615615
616+ // / Queue on which consumers may be notified about results and cancellation.
617+ // / This is essentially just a background queue to which we can jump to inform
618+ // / consumers while making sure that no locks are currently claimed.
619+ WorkQueue ConsumerNotificationQueue{
620+ WorkQueue::Dequeuing::Concurrent,
621+ " SwiftASTManager::Implementation::ConsumerNotificationQueue" };
622+
616623 // / Remove all scheduled consumers that don't exist anymore. This is just a
617624 // / garbage-collection operation to make sure the \c ScheduledConsumers vector
618625 // / doesn't explode. One should never make assumptions that all consumers in
@@ -782,9 +789,11 @@ void SwiftASTManager::processASTAsync(
782789 // Cancel any consumers with the same OncePerASTToken.
783790 for (auto ScheduledConsumer : Impl.ScheduledConsumers ) {
784791 if (ScheduledConsumer.OncePerASTToken == OncePerASTToken) {
785- if (auto Consumer = ScheduledConsumer.Consumer .lock ()) {
786- Consumer->requestCancellation ();
787- }
792+ Impl.ConsumerNotificationQueue .dispatch ([ScheduledConsumer]() {
793+ if (auto Consumer = ScheduledConsumer.Consumer .lock ()) {
794+ Consumer->requestCancellation ();
795+ }
796+ });
788797 }
789798 }
790799 }
@@ -794,11 +803,17 @@ void SwiftASTManager::processASTAsync(
794803 Producer->enqueueConsumer (ASTConsumer, fileSystem, shared_from_this ());
795804
796805 auto WeakConsumer = SwiftASTConsumerWeakRef (ASTConsumer);
797- Impl.ReqTracker ->setCancellationHandler (CancellationToken, [WeakConsumer] {
798- if (auto Consumer = WeakConsumer.lock ()) {
799- Consumer->requestCancellation ();
800- }
801- });
806+ auto WeakThis = std::weak_ptr<SwiftASTManager>(shared_from_this ());
807+ Impl.ReqTracker ->setCancellationHandler (
808+ CancellationToken, [WeakConsumer, WeakThis] {
809+ if (auto This = WeakThis.lock ()) {
810+ This->Impl .ConsumerNotificationQueue .dispatch ([WeakConsumer]() {
811+ if (auto Consumer = WeakConsumer.lock ()) {
812+ Consumer->requestCancellation ();
813+ }
814+ });
815+ }
816+ });
802817}
803818
804819void SwiftASTManager::removeCachedAST (SwiftInvocationRef Invok) {
@@ -950,12 +965,14 @@ void ASTBuildOperation::requestConsumerCancellation(
950965 return ;
951966 }
952967 Consumers.erase (ConsumerIndex);
953- Consumer->cancelled ();
954968 if (Consumers.empty ()) {
955969 // If there are no more consumers waiting for this result, cancel the AST
956970 // build.
957971 CancellationFlag->store (true , std::memory_order_relaxed);
958972 }
973+ ASTManager->Impl .ConsumerNotificationQueue .dispatch ([Consumer] {
974+ Consumer->cancelled ();
975+ });
959976}
960977
961978static void collectModuleDependencies (ModuleDecl *TopMod,
@@ -1027,11 +1044,15 @@ void ASTBuildOperation::informConsumer(SwiftASTConsumerRef Consumer) {
10271044 " more consumers attached to it and should not accept any "
10281045 " new consumers if the build operation was cancelled. Thus "
10291046 " this case should never happen." );
1030- Consumer->cancelled ();
1047+ ASTManager->Impl .ConsumerNotificationQueue .dispatch ([Consumer] {
1048+ Consumer->cancelled ();
1049+ });
10311050 } else if (Result.AST ) {
10321051 Result.AST ->Impl .consumeAsync (Consumer, Result.AST );
10331052 } else {
1034- Consumer->failed (Result.Error );
1053+ ASTManager->Impl .ConsumerNotificationQueue .dispatch ([Consumer, Error = Result.Error ] {
1054+ Consumer->failed (Error);
1055+ });
10351056 }
10361057}
10371058
0 commit comments