@@ -613,6 +613,13 @@ struct SwiftASTManager::Implementation {
613
613
WorkQueue ASTBuildQueue{ WorkQueue::Dequeuing::Serial,
614
614
" sourcekit.swift.ASTBuilding" };
615
615
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
+
616
623
// / Remove all scheduled consumers that don't exist anymore. This is just a
617
624
// / garbage-collection operation to make sure the \c ScheduledConsumers vector
618
625
// / doesn't explode. One should never make assumptions that all consumers in
@@ -782,9 +789,11 @@ void SwiftASTManager::processASTAsync(
782
789
// Cancel any consumers with the same OncePerASTToken.
783
790
for (auto ScheduledConsumer : Impl.ScheduledConsumers ) {
784
791
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
+ });
788
797
}
789
798
}
790
799
}
@@ -794,11 +803,17 @@ void SwiftASTManager::processASTAsync(
794
803
Producer->enqueueConsumer (ASTConsumer, fileSystem, shared_from_this ());
795
804
796
805
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
+ });
802
817
}
803
818
804
819
void SwiftASTManager::removeCachedAST (SwiftInvocationRef Invok) {
@@ -950,12 +965,14 @@ void ASTBuildOperation::requestConsumerCancellation(
950
965
return ;
951
966
}
952
967
Consumers.erase (ConsumerIndex);
953
- Consumer->cancelled ();
954
968
if (Consumers.empty ()) {
955
969
// If there are no more consumers waiting for this result, cancel the AST
956
970
// build.
957
971
CancellationFlag->store (true , std::memory_order_relaxed);
958
972
}
973
+ ASTManager->Impl .ConsumerNotificationQueue .dispatch ([Consumer] {
974
+ Consumer->cancelled ();
975
+ });
959
976
}
960
977
961
978
static void collectModuleDependencies (ModuleDecl *TopMod,
@@ -1027,11 +1044,15 @@ void ASTBuildOperation::informConsumer(SwiftASTConsumerRef Consumer) {
1027
1044
" more consumers attached to it and should not accept any "
1028
1045
" new consumers if the build operation was cancelled. Thus "
1029
1046
" this case should never happen." );
1030
- Consumer->cancelled ();
1047
+ ASTManager->Impl .ConsumerNotificationQueue .dispatch ([Consumer] {
1048
+ Consumer->cancelled ();
1049
+ });
1031
1050
} else if (Result.AST ) {
1032
1051
Result.AST ->Impl .consumeAsync (Consumer, Result.AST );
1033
1052
} else {
1034
- Consumer->failed (Result.Error );
1053
+ ASTManager->Impl .ConsumerNotificationQueue .dispatch ([Consumer, Error = Result.Error ] {
1054
+ Consumer->failed (Error);
1055
+ });
1035
1056
}
1036
1057
}
1037
1058
0 commit comments