49
49
#include " GlobalCompilationDatabase.h"
50
50
#include " Logger.h"
51
51
#include " ParsedAST.h"
52
+ #include " Path.h"
52
53
#include " Preamble.h"
54
+ #include " Threading.h"
53
55
#include " Trace.h"
54
56
#include " index/CanonicalIncludes.h"
55
57
#include " clang/Frontend/CompilerInvocation.h"
56
58
#include " clang/Tooling/CompilationDatabase.h"
57
59
#include " llvm/ADT/Optional.h"
58
60
#include " llvm/ADT/ScopeExit.h"
61
+ #include " llvm/ADT/StringRef.h"
59
62
#include " llvm/Support/Errc.h"
60
63
#include " llvm/Support/Path.h"
61
64
#include " llvm/Support/Threading.h"
@@ -149,6 +152,177 @@ class TUScheduler::ASTCache {
149
152
};
150
153
151
154
namespace {
155
+ // / Responsible for building and providing access to the preamble of a TU.
156
+ // / Whenever the thread is idle and the preamble is outdated, it starts to build
157
+ // / a fresh preamble from the latest inputs. If RunSync is true, preambles are
158
+ // / built synchronously in update() instead.
159
+ class PreambleThread {
160
+ public:
161
+ PreambleThread (llvm::StringRef FileName, ParsingCallbacks &Callbacks,
162
+ bool StorePreambleInMemory, bool RunSync)
163
+ : FileName(FileName), Callbacks(Callbacks),
164
+ StoreInMemory (StorePreambleInMemory), RunSync(RunSync) {}
165
+
166
+ size_t getUsedBytes () const {
167
+ auto Preamble = latest ();
168
+ return Preamble ? Preamble->Preamble .getSize () : 0 ;
169
+ }
170
+
171
+ // / It isn't guaranteed that each requested version will be built. If there
172
+ // / are multiple update requests while building a preamble, only the last one
173
+ // / will be built.
174
+ void update (CompilerInvocation *CI, ParseInputs PI) {
175
+ // If compiler invocation was broken, just fail out early.
176
+ if (!CI) {
177
+ TUStatus::BuildDetails Details;
178
+ Details.BuildFailed = true ;
179
+ std::string TaskName = llvm::formatv (" Update ({0})" , PI.Version );
180
+ emitTUStatus ({TUAction::BuildingPreamble, std::move (TaskName)}, &Details);
181
+ // Make sure anyone waiting for the preamble gets notified it could not be
182
+ // built.
183
+ BuiltFirst.notify ();
184
+ return ;
185
+ }
186
+ // Make possibly expensive copy while not holding the lock.
187
+ Request Req = {std::make_unique<CompilerInvocation>(*CI), std::move (PI)};
188
+ if (RunSync) {
189
+ build (std::move (Req));
190
+ return ;
191
+ }
192
+ {
193
+ std::lock_guard<std::mutex> Lock (Mutex);
194
+ assert (!Done && " Build request to PreambleWorker after stop" );
195
+ NextReq = std::move (Req);
196
+ }
197
+ // Let the worker thread know there's a request, notify_one is safe as there
198
+ // should be a single worker thread waiting on it.
199
+ ReqCV.notify_all ();
200
+ }
201
+
202
+ // / Blocks until at least a single request has been processed. Note that it
203
+ // / will unblock even after an unsuccessful build.
204
+ void waitForFirst () const { BuiltFirst.wait (); }
205
+
206
+ // / Returns the latest built preamble, might be null if no preamble has been
207
+ // / built or latest attempt resulted in a failure.
208
+ std::shared_ptr<const PreambleData> latest () const {
209
+ std::lock_guard<std::mutex> Lock (Mutex);
210
+ return LatestBuild;
211
+ }
212
+
213
+ void run () {
214
+ dlog (" Starting preamble worker for {0}" , FileName);
215
+ while (true ) {
216
+ {
217
+ std::unique_lock<std::mutex> Lock (Mutex);
218
+ assert (!CurrentReq && " Already processing a request?" );
219
+ // Wait until stop is called or there is a request.
220
+ ReqCV.wait (Lock, [this ] { return NextReq || Done; });
221
+ if (Done)
222
+ break ;
223
+ CurrentReq = std::move (*NextReq);
224
+ NextReq.reset ();
225
+ }
226
+ // Build the preamble and let the waiters know about it.
227
+ build (std::move (*CurrentReq));
228
+ {
229
+ std::lock_guard<std::mutex> Lock (Mutex);
230
+ CurrentReq.reset ();
231
+ }
232
+ ReqCV.notify_all ();
233
+ }
234
+ // We are no longer going to build any preambles, let the waiters know that.
235
+ BuiltFirst.notify ();
236
+ dlog (" Preamble worker for {0} finished" , FileName);
237
+ }
238
+
239
+ // / Signals the run loop to exit.
240
+ void stop () {
241
+ dlog (" Stopping preamble worker for {0}" , FileName);
242
+ {
243
+ std::lock_guard<std::mutex> Lock (Mutex);
244
+ Done = true ;
245
+ }
246
+ // Let the worker thread know that it should stop.
247
+ ReqCV.notify_all ();
248
+ }
249
+
250
+ bool blockUntilIdle (Deadline Timeout) const {
251
+ std::unique_lock<std::mutex> Lock (Mutex);
252
+ return wait (Lock, ReqCV, Timeout, [&] { return !NextReq && !CurrentReq; });
253
+ }
254
+
255
+ private:
256
+ // / Holds inputs required for building a preamble. CI is guaranteed to be
257
+ // / non-null.
258
+ struct Request {
259
+ std::unique_ptr<CompilerInvocation> CI;
260
+ ParseInputs Inputs;
261
+ };
262
+
263
+ bool isDone () {
264
+ std::lock_guard<std::mutex> Lock (Mutex);
265
+ return Done;
266
+ }
267
+
268
+ // / Updates the TUStatus and emits it. Only called in the worker thread.
269
+ void emitTUStatus (TUAction Action,
270
+ const TUStatus::BuildDetails *Details = nullptr ) {
271
+ // Do not emit TU statuses when the worker is shutting down.
272
+ if (isDone ())
273
+ return ;
274
+ TUStatus Status ({std::move (Action), {}});
275
+ if (Details)
276
+ Status.Details = *Details;
277
+ Callbacks.onFileUpdated (FileName, Status);
278
+ }
279
+
280
+ // / Builds a preamble for Req and caches it. Might re-use the latest built
281
+ // / preamble if it is valid for Req. Also signals waiters about the build.
282
+ // / FIXME: We shouldn't cache failed preambles, if we've got a successful
283
+ // / build before.
284
+ void build (Request Req) {
285
+ assert (Req.CI && " Got preamble request with null compiler invocation" );
286
+ const ParseInputs &Inputs = Req.Inputs ;
287
+ std::shared_ptr<const PreambleData> OldPreamble =
288
+ Inputs.ForceRebuild ? nullptr : latest ();
289
+
290
+ std::string TaskName = llvm::formatv (" Update ({0})" , Inputs.Version );
291
+ emitTUStatus ({TUAction::BuildingPreamble, std::move (TaskName)});
292
+
293
+ auto Preamble = clang::clangd::buildPreamble (
294
+ FileName, std::move (*Req.CI ), OldPreamble, Inputs, StoreInMemory,
295
+ [this , Version (Inputs.Version )](
296
+ ASTContext &Ctx, std::shared_ptr<clang::Preprocessor> PP,
297
+ const CanonicalIncludes &CanonIncludes) {
298
+ Callbacks.onPreambleAST (FileName, Version, Ctx, std::move (PP),
299
+ CanonIncludes);
300
+ });
301
+ {
302
+ std::lock_guard<std::mutex> Lock (Mutex);
303
+ // LatestBuild might be the last reference to old preamble, do not trigger
304
+ // destructor while holding the lock.
305
+ std::swap (LatestBuild, Preamble);
306
+ }
307
+ BuiltFirst.notify ();
308
+ }
309
+
310
+ mutable std::mutex Mutex;
311
+ bool Done = false ; /* GUARDED_BY(Mutex) */
312
+ llvm::Optional<Request> NextReq; /* GUARDED_BY(Mutex) */
313
+ llvm::Optional<Request> CurrentReq; /* GUARDED_BY(Mutex) */
314
+ // Signaled whenever a thread populates NextReq or worker thread builds a
315
+ // Preamble.
316
+ mutable std::condition_variable ReqCV; /* GUARDED_BY(Mutex) */
317
+ std::shared_ptr<const PreambleData> LatestBuild; /* GUARDED_BY(Mutex) */
318
+
319
+ Notification BuiltFirst;
320
+ const Path FileName;
321
+ ParsingCallbacks &Callbacks;
322
+ const bool StoreInMemory;
323
+ const bool RunSync;
324
+ };
325
+
152
326
class ASTWorkerHandle ;
153
327
154
328
// / Owns one instance of the AST, schedules updates and reads of it.
@@ -251,8 +425,6 @@ class ASTWorker {
251
425
// / File that ASTWorker is responsible for.
252
426
const Path FileName;
253
427
const GlobalCompilationDatabase &CDB;
254
- // / Whether to keep the built preambles in memory or on disk.
255
- const bool StorePreambleInMemory;
256
428
// / Callback invoked when preamble or main file AST is built.
257
429
ParsingCallbacks &Callbacks;
258
430
// / Only accessed by the worker thread.
@@ -266,13 +438,10 @@ class ASTWorker {
266
438
// / File inputs, currently being used by the worker.
267
439
// / Inputs are written and read by the worker thread, compile command can also
268
440
// / be consumed by clients of ASTWorker.
269
- std::shared_ptr<const ParseInputs> FileInputs; /* GUARDED_BY(Mutex) */
270
- std::shared_ptr<const PreambleData> LastBuiltPreamble; /* GUARDED_BY(Mutex) */
441
+ std::shared_ptr<const ParseInputs> FileInputs; /* GUARDED_BY(Mutex) */
271
442
// / Times of recent AST rebuilds, used for UpdateDebounce computation.
272
443
llvm::SmallVector<DebouncePolicy::clock::duration, 8 >
273
444
RebuildTimes; /* GUARDED_BY(Mutex) */
274
- // / Becomes ready when the first preamble build finishes.
275
- Notification PreambleWasBuilt;
276
445
// / Set to true to signal run() to finish processing.
277
446
bool Done; /* GUARDED_BY(Mutex) */
278
447
std::deque<Request> Requests; /* GUARDED_BY(Mutex) */
@@ -288,6 +457,8 @@ class ASTWorker {
288
457
// don't. When the old handle is destroyed, the old worker will stop reporting
289
458
// any results to the user.
290
459
bool CanPublishResults = true ; /* GUARDED_BY(PublishMu) */
460
+
461
+ PreambleThread PW;
291
462
};
292
463
293
464
// / A smart-pointer-like class that points to an active ASTWorker.
@@ -340,9 +511,12 @@ ASTWorker::create(PathRef FileName, const GlobalCompilationDatabase &CDB,
340
511
std::shared_ptr<ASTWorker> Worker (
341
512
new ASTWorker (FileName, CDB, IdleASTs, Barrier, /* RunSync=*/ !Tasks,
342
513
UpdateDebounce, StorePreamblesInMemory, Callbacks));
343
- if (Tasks)
344
- Tasks->runAsync (" worker :" + llvm::sys::path::filename (FileName),
514
+ if (Tasks) {
515
+ Tasks->runAsync (" ASTWorker :" + llvm::sys::path::filename (FileName),
345
516
[Worker]() { Worker->run (); });
517
+ Tasks->runAsync (" PreambleWorker:" + llvm::sys::path::filename (FileName),
518
+ [Worker]() { Worker->PW .run (); });
519
+ }
346
520
347
521
return ASTWorkerHandle (std::move (Worker));
348
522
}
@@ -353,10 +527,11 @@ ASTWorker::ASTWorker(PathRef FileName, const GlobalCompilationDatabase &CDB,
353
527
bool StorePreamblesInMemory, ParsingCallbacks &Callbacks)
354
528
: IdleASTs(LRUCache), RunSync(RunSync), UpdateDebounce(UpdateDebounce),
355
529
FileName(FileName), CDB(CDB),
356
- StorePreambleInMemory(StorePreamblesInMemory),
357
530
Callbacks(Callbacks), Status{TUAction (TUAction::Idle, " " ),
358
531
TUStatus::BuildDetails ()},
359
- Barrier (Barrier), Done(false ) {
532
+ Barrier (Barrier), Done(false ),
533
+ // FIXME: Run preambleworker async.
534
+ PW(FileName, Callbacks, StorePreamblesInMemory, /* RunSync=*/ true ) {
360
535
auto Inputs = std::make_shared<ParseInputs>();
361
536
// Set a fallback command because compile command can be accessed before
362
537
// `Inputs` is initialized. Other fields are only used after initialization
@@ -409,7 +584,6 @@ void ASTWorker::update(ParseInputs Inputs, WantDiagnostics WantDiags) {
409
584
FileInputs = std::make_shared<ParseInputs>(Inputs);
410
585
}
411
586
RanASTCallback = false ;
412
- emitTUStatus ({TUAction::BuildingPreamble, TaskName});
413
587
log (" ASTWorker building file {0} version {1} with command {2}\n [{3}]\n {4}" ,
414
588
FileName, Inputs.Version , Inputs.CompileCommand .Heuristic ,
415
589
Inputs.CompileCommand .Directory ,
@@ -419,6 +593,12 @@ void ASTWorker::update(ParseInputs Inputs, WantDiagnostics WantDiags) {
419
593
std::vector<std::string> CC1Args;
420
594
std::unique_ptr<CompilerInvocation> Invocation = buildCompilerInvocation (
421
595
Inputs, CompilerInvocationDiagConsumer, &CC1Args);
596
+ // This is true for now, as we always block until new preamble is build.
597
+ // Once we start to block preambles out-of-order we need to make sure
598
+ // OldPreamble refers to the preamble that was used to build last AST.
599
+ auto OldPreamble = PW.latest ();
600
+ PW.update (Invocation.get (), Inputs);
601
+ auto NewPreamble = PW.latest ();
422
602
// Log cc1 args even (especially!) if creating invocation failed.
423
603
if (!CC1Args.empty ())
424
604
vlog (" Driver produced command: cc1 {0}" , llvm::join (CC1Args, " " ));
@@ -428,40 +608,17 @@ void ASTWorker::update(ParseInputs Inputs, WantDiagnostics WantDiags) {
428
608
elog (" Could not build CompilerInvocation for file {0}" , FileName);
429
609
// Remove the old AST if it's still in cache.
430
610
IdleASTs.take (this );
431
- TUStatus::BuildDetails Details;
432
- Details.BuildFailed = true ;
433
- emitTUStatus ({TUAction::BuildingPreamble, TaskName}, &Details);
434
611
// Report the diagnostics we collected when parsing the command line.
435
612
Callbacks.onFailedAST (FileName, Inputs.Version ,
436
613
std::move (CompilerInvocationDiags), RunPublish);
437
- // Make sure anyone waiting for the preamble gets notified it could not
438
- // be built.
439
- PreambleWasBuilt.notify ();
440
614
return ;
441
615
}
442
616
443
- std::shared_ptr<const PreambleData> OldPreamble =
444
- Inputs.ForceRebuild ? std::shared_ptr<const PreambleData>()
445
- : getPossiblyStalePreamble ();
446
- std::shared_ptr<const PreambleData> NewPreamble = buildPreamble (
447
- FileName, *Invocation, OldPreamble, Inputs, StorePreambleInMemory,
448
- [this , Version (Inputs.Version )](
449
- ASTContext &Ctx, std::shared_ptr<clang::Preprocessor> PP,
450
- const CanonicalIncludes &CanonIncludes) {
451
- Callbacks.onPreambleAST (FileName, Version, Ctx, std::move (PP),
452
- CanonIncludes);
453
- });
454
-
455
617
bool CanReuseAST = InputsAreTheSame && (OldPreamble == NewPreamble);
456
- {
457
- std::lock_guard<std::mutex> Lock (Mutex);
458
- LastBuiltPreamble = NewPreamble;
459
- }
460
618
// Before doing the expensive AST reparse, we want to release our reference
461
619
// to the old preamble, so it can be freed if there are no other references
462
620
// to it.
463
621
OldPreamble.reset ();
464
- PreambleWasBuilt.notify ();
465
622
emitTUStatus ({TUAction::BuildingFile, TaskName});
466
623
if (!CanReuseAST) {
467
624
IdleASTs.take (this ); // Remove the old AST if it's still in cache.
@@ -591,8 +748,7 @@ void ASTWorker::runWithAST(
591
748
592
749
std::shared_ptr<const PreambleData>
593
750
ASTWorker::getPossiblyStalePreamble () const {
594
- std::lock_guard<std::mutex> Lock (Mutex);
595
- return LastBuiltPreamble;
751
+ return PW.latest ();
596
752
}
597
753
598
754
void ASTWorker::getCurrentPreamble (
@@ -625,7 +781,7 @@ void ASTWorker::getCurrentPreamble(
625
781
RequestsCV.notify_all ();
626
782
}
627
783
628
- void ASTWorker::waitForFirstPreamble () const { PreambleWasBuilt. wait (); }
784
+ void ASTWorker::waitForFirstPreamble () const { PW. waitForFirst (); }
629
785
630
786
std::shared_ptr<const ParseInputs> ASTWorker::getCurrentFileInputs () const {
631
787
std::unique_lock<std::mutex> Lock (Mutex);
@@ -713,6 +869,7 @@ void ASTWorker::emitTUStatus(TUAction Action,
713
869
}
714
870
715
871
void ASTWorker::run () {
872
+ auto _ = llvm::make_scope_exit ([this ] { PW.stop (); });
716
873
while (true ) {
717
874
{
718
875
std::unique_lock<std::mutex> Lock (Mutex);
0 commit comments