@@ -604,6 +604,13 @@ struct SwiftASTManager::Implementation {
604
604
WorkQueue ASTBuildQueue{ WorkQueue::Dequeuing::Serial,
605
605
" sourcekit.swift.ASTBuilding" };
606
606
607
+ // / Queue on which consumers may be notified about results and cancellation.
608
+ // / This is essentially just a background queue to which we can jump to inform
609
+ // / consumers while making sure that no locks are currently claimed.
610
+ WorkQueue ConsumerNotificationQueue{
611
+ WorkQueue::Dequeuing::Concurrent,
612
+ " SwiftASTManager::Implementation::ConsumerNotificationQueue" };
613
+
607
614
// / Remove all scheduled consumers that don't exist anymore. This is just a
608
615
// / garbage-collection operation to make sure the \c ScheduledConsumers vector
609
616
// / doesn't explode. One should never make assumptions that all consumers in
@@ -769,9 +776,11 @@ void SwiftASTManager::processASTAsync(
769
776
// Cancel any consumers with the same OncePerASTToken.
770
777
for (auto ScheduledConsumer : Impl.ScheduledConsumers ) {
771
778
if (ScheduledConsumer.OncePerASTToken == OncePerASTToken) {
772
- if (auto Consumer = ScheduledConsumer.Consumer .lock ()) {
773
- Consumer->requestCancellation ();
774
- }
779
+ Impl.ConsumerNotificationQueue .dispatch ([ScheduledConsumer]() {
780
+ if (auto Consumer = ScheduledConsumer.Consumer .lock ()) {
781
+ Consumer->requestCancellation ();
782
+ }
783
+ });
775
784
}
776
785
}
777
786
}
@@ -781,11 +790,17 @@ void SwiftASTManager::processASTAsync(
781
790
Producer->enqueueConsumer (ASTConsumer, fileSystem, shared_from_this ());
782
791
783
792
auto WeakConsumer = SwiftASTConsumerWeakRef (ASTConsumer);
784
- Impl.ReqTracker ->setCancellationHandler (CancellationToken, [WeakConsumer] {
785
- if (auto Consumer = WeakConsumer.lock ()) {
786
- Consumer->requestCancellation ();
787
- }
788
- });
793
+ auto WeakThis = std::weak_ptr<SwiftASTManager>(shared_from_this ());
794
+ Impl.ReqTracker ->setCancellationHandler (
795
+ CancellationToken, [WeakConsumer, WeakThis] {
796
+ if (auto This = WeakThis.lock ()) {
797
+ This->Impl .ConsumerNotificationQueue .dispatch ([WeakConsumer]() {
798
+ if (auto Consumer = WeakConsumer.lock ()) {
799
+ Consumer->requestCancellation ();
800
+ }
801
+ });
802
+ }
803
+ });
789
804
}
790
805
791
806
void SwiftASTManager::removeCachedAST (SwiftInvocationRef Invok) {
@@ -937,12 +952,14 @@ void ASTBuildOperation::requestConsumerCancellation(
937
952
return ;
938
953
}
939
954
Consumers.erase (ConsumerIndex);
940
- Consumer->cancelled ();
941
955
if (Consumers.empty ()) {
942
956
// If there are no more consumers waiting for this result, cancel the AST
943
957
// build.
944
958
CancellationFlag->store (true , std::memory_order_relaxed);
945
959
}
960
+ ASTManager->Impl .ConsumerNotificationQueue .dispatch ([Consumer] {
961
+ Consumer->cancelled ();
962
+ });
946
963
}
947
964
948
965
static void collectModuleDependencies (ModuleDecl *TopMod,
@@ -1014,11 +1031,15 @@ void ASTBuildOperation::informConsumer(SwiftASTConsumerRef Consumer) {
1014
1031
" more consumers attached to it and should not accept any "
1015
1032
" new consumers if the build operation was cancelled. Thus "
1016
1033
" this case should never happen." );
1017
- Consumer->cancelled ();
1034
+ ASTManager->Impl .ConsumerNotificationQueue .dispatch ([Consumer] {
1035
+ Consumer->cancelled ();
1036
+ });
1018
1037
} else if (Result.AST ) {
1019
1038
Result.AST ->Impl .consumeAsync (Consumer, Result.AST );
1020
1039
} else {
1021
- Consumer->failed (Result.Error );
1040
+ ASTManager->Impl .ConsumerNotificationQueue .dispatch ([Consumer, Error = Result.Error ] {
1041
+ Consumer->failed (Error);
1042
+ });
1022
1043
}
1023
1044
}
1024
1045
@@ -1136,6 +1157,7 @@ void ASTBuildOperation::schedule(WorkQueue Queue) {
1136
1157
/* ExpectedOldState=*/ State::Running);
1137
1158
};
1138
1159
1160
+ SmallVector<SwiftASTConsumerRef, 4 > ConsumersToCancel;
1139
1161
{
1140
1162
llvm::sys::ScopedLock L (ConsumersAndResultMtx);
1141
1163
if (Consumers.empty ()) {
@@ -1146,24 +1168,25 @@ void ASTBuildOperation::schedule(WorkQueue Queue) {
1146
1168
if (CancellationFlag->load (std::memory_order_relaxed)) {
1147
1169
assert (false && " We should only set the cancellation flag if there "
1148
1170
" are no more consumers" );
1149
- for (auto &Consumer : Consumers) {
1150
- Consumer->cancelled ();
1151
- }
1171
+ ConsumersToCancel = Consumers;
1152
1172
}
1153
1173
}
1174
+ for (auto &Consumer : ConsumersToCancel) {
1175
+ Consumer->cancelled ();
1176
+ }
1154
1177
1155
1178
std::string Error;
1156
1179
assert (!Result && " We should only be producing a result once" );
1157
1180
ASTUnitRef AST = buildASTUnit (Error);
1158
- SmallVector<SwiftASTConsumerRef, 4 > LocalConsumers ;
1181
+ SmallVector<SwiftASTConsumerRef, 4 > ConsumersToInform ;
1159
1182
{
1160
1183
llvm::sys::ScopedLock L (ConsumersAndResultMtx);
1161
1184
bool WasCancelled = CancellationFlag->load (std::memory_order_relaxed);
1162
1185
Result.emplace (AST, Error, WasCancelled);
1163
- LocalConsumers = Consumers;
1186
+ ConsumersToInform = Consumers;
1164
1187
Consumers = {};
1165
1188
}
1166
- for (auto &Consumer : LocalConsumers ) {
1189
+ for (auto &Consumer : ConsumersToInform ) {
1167
1190
informConsumer (Consumer);
1168
1191
}
1169
1192
DidFinishCallback ();
0 commit comments