clang-tools 8.0.0

TUScheduler.cpp
Go to the documentation of this file.
1 //===--- TUScheduler.cpp -----------------------------------------*-C++-*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 // For each file, managed by TUScheduler, we create a single ASTWorker that
10 // manages an AST for that file. All operations that modify or read the AST are
11 // run on a separate dedicated thread asynchronously in FIFO order.
12 //
13 // We start processing each update immediately after we receive it. If two or
14 // more updates come subsequently without reads in-between, we attempt to drop
15 // an older one to not waste time building the ASTs we don't need.
16 //
17 // The processing thread of the ASTWorker is also responsible for building the
18 // preamble. However, unlike AST, the same preamble can be read concurrently, so
19 // we run each of async preamble reads on its own thread.
20 //
21 // To limit the concurrent load that clangd produces we maintain a semaphore
22 // that keeps more than a fixed number of threads from running concurrently.
23 //
24 // Rationale for cancelling updates.
25 // LSP clients can send updates to clangd on each keystroke. Some files take
26 // significant time to parse (e.g. a few seconds) and clangd can get starved by
27 // the updates to those files. Therefore we try to process only the last update,
28 // if possible.
29 // Our current strategy to do that is the following:
30 // - For each update we immediately schedule rebuild of the AST.
31 // - Rebuild of the AST checks if it was cancelled before doing any actual work.
32 // If it was, it does not do an actual rebuild, only reports llvm::None to the
33 // callback
34 // - When adding an update, we cancel the last update in the queue if it didn't
35 // have any reads.
36 // There is probably a optimal ways to do that. One approach we might take is
37 // the following:
38 // - For each update we remember the pending inputs, but delay rebuild of the
39 // AST for some timeout.
40 // - If subsequent updates come before rebuild was started, we replace the
41 // pending inputs and reset the timer.
42 // - If any reads of the AST are scheduled, we start building the AST
43 // immediately.
44
45 #include "TUScheduler.h"
46 #include "Cancellation.h"
47 #include "Logger.h"
48 #include "Trace.h"
49 #include "clang/Frontend/CompilerInvocation.h"
50 #include "clang/Frontend/PCHContainerOperations.h"
51 #include "llvm/ADT/ScopeExit.h"
52 #include "llvm/Support/Errc.h"
53 #include "llvm/Support/Path.h"
54 #include <algorithm>
55 #include <memory>
56 #include <queue>
57 #include <thread>
58
59 namespace clang {
60 namespace clangd {
61 using std::chrono::steady_clock;
62
63 namespace {
64 class ASTWorker;
65 }
66
67 static clang::clangd::Key<std::string> kFileBeingProcessed;
68
69 llvm::Optional<llvm::StringRef> TUScheduler::getFileBeingProcessedInContext() {
70 if (auto *File = Context::current().get(kFileBeingProcessed))
71 return llvm::StringRef(*File);
72 return None;
73 }
74
75 /// An LRU cache of idle ASTs.
76 /// Because we want to limit the overall number of these we retain, the cache
77 /// owns ASTs (and may evict them) while their workers are idle.
78 /// Workers borrow ASTs when active, and return them when done.
79 class TUScheduler::ASTCache {
80 public:
81 using Key = const ASTWorker *;
82
83 ASTCache(unsigned MaxRetainedASTs) : MaxRetainedASTs(MaxRetainedASTs) {}
84
85 /// Returns result of getUsedBytes() for the AST cached by \p K.
86 /// If no AST is cached, 0 is returned.
87 std::size_t getUsedBytes(Key K) {
88 std::lock_guard<std::mutex> Lock(Mut);
89 auto It = findByKey(K);
90 if (It == LRU.end() || !It->second)
91 return 0;
92 return It->second->getUsedBytes();
93 }
94
95 /// Store the value in the pool, possibly removing the last used AST.
96 /// The value should not be in the pool when this function is called.
97 void put(Key K, std::unique_ptr<ParsedAST> V) {
98 std::unique_lock<std::mutex> Lock(Mut);
99 assert(findByKey(K) == LRU.end());
100
101 LRU.insert(LRU.begin(), {K, std::move(V)});
102 if (LRU.size() <= MaxRetainedASTs)
103 return;
104 // We're past the limit, remove the last element.
105 std::unique_ptr<ParsedAST> ForCleanup = std::move(LRU.back().second);
106 LRU.pop_back();
107 // Run the expensive destructor outside the lock.
108 Lock.unlock();
109 ForCleanup.reset();
110 }
111
112 /// Returns the cached value for \p K, or llvm::None if the value is not in
113 /// the cache anymore. If nullptr was cached for \p K, this function will
114 /// return a null unique_ptr wrapped into an optional.
115 llvm::Optional<std::unique_ptr<ParsedAST>> take(Key K) {
116 std::unique_lock<std::mutex> Lock(Mut);
117 auto Existing = findByKey(K);
118 if (Existing == LRU.end())
119 return None;
120 std::unique_ptr<ParsedAST> V = std::move(Existing->second);
121 LRU.erase(Existing);
122 // GCC 4.8 fails to compile `return V;`, as it tries to call the copy
123 // constructor of unique_ptr, so we call the move ctor explicitly to avoid
124 // this miscompile.
125 return llvm::Optional<std::unique_ptr<ParsedAST>>(std::move(V));
126 }
127
128 private:
129 using KVPair = std::pair<Key, std::unique_ptr<ParsedAST>>;
130
131 std::vector<KVPair>::iterator findByKey(Key K) {
132 return llvm::find_if(LRU, [K](const KVPair &P) { return P.first == K; });
133 }
134
135 std::mutex Mut;
136 unsigned MaxRetainedASTs;
137 /// Items sorted in LRU order, i.e. first item is the most recently accessed
138 /// one.
139 std::vector<KVPair> LRU; /* GUARDED_BY(Mut) */
140 };
141
142 namespace {
143 class ASTWorkerHandle;
144
145 /// Owns one instance of the AST, schedules updates and reads of it.
146 /// Also responsible for building and providing access to the preamble.
147 /// Each ASTWorker processes the async requests sent to it on a separate
148 /// dedicated thread.
149 /// The ASTWorker that manages the AST is shared by both the processing thread
150 /// and the TUScheduler. The TUScheduler should discard an ASTWorker when
151 /// remove() is called, but its thread may be busy and we don't want to block.
152 /// So the workers are accessed via an ASTWorkerHandle. Destroying the handle
153 /// signals the worker to exit its run loop and gives up shared ownership of the
154 /// worker.
155 class ASTWorker {
156 friend class ASTWorkerHandle;
157 ASTWorker(PathRef FileName, TUScheduler::ASTCache &LRUCache,
158 Semaphore &Barrier, bool RunSync,
159 steady_clock::duration UpdateDebounce,
160 std::shared_ptr<PCHContainerOperations> PCHs,
161 bool StorePreamblesInMemory, ParsingCallbacks &Callbacks);
162
163 public:
164 /// Create a new ASTWorker and return a handle to it.
165 /// The processing thread is spawned using \p Tasks. However, when \p Tasks
166 /// is null, all requests will be processed on the calling thread
167 /// synchronously instead. \p Barrier is acquired when processing each
168 /// request, it is used to limit the number of actively running threads.
169 static ASTWorkerHandle create(PathRef FileName,
170 TUScheduler::ASTCache &IdleASTs,
171 AsyncTaskRunner *Tasks, Semaphore &Barrier,
172 steady_clock::duration UpdateDebounce,
173 std::shared_ptr<PCHContainerOperations> PCHs,
174 bool StorePreamblesInMemory,
175 ParsingCallbacks &Callbacks);
176 ~ASTWorker();
177
178 void update(ParseInputs Inputs, WantDiagnostics);
179 void
180 runWithAST(llvm::StringRef Name,
181 llvm::unique_function<void(llvm::Expected<InputsAndAST>)> Action);
182 bool blockUntilIdle(Deadline Timeout) const;
183
184 std::shared_ptr<const PreambleData> getPossiblyStalePreamble() const;
185 /// Obtain a preamble reflecting all updates so far. Threadsafe.
186 /// It may be delivered immediately, or later on the worker thread.
187 void getCurrentPreamble(
188 llvm::unique_function<void(std::shared_ptr<const PreambleData>)>);
189 /// Wait for the first build of preamble to finish. Preamble itself can be
190 /// accessed via getPossiblyStalePreamble(). Note that this function will
191 /// return after an unsuccessful build of the preamble too, i.e. result of
192 /// getPossiblyStalePreamble() can be null even after this function returns.
193 void waitForFirstPreamble() const;
194
195 std::size_t getUsedBytes() const;
196 bool isASTCached() const;
197
198 private:
199 // Must be called exactly once on processing thread. Will return after
200 // stop() is called on a separate thread and all pending requests are
201 // processed.
202 void run();
203 /// Signal that run() should finish processing pending requests and exit.
204 void stop();
205 /// Adds a new task to the end of the request queue.
206 void startTask(llvm::StringRef Name, llvm::unique_function<void()> Task,
207 llvm::Optional<WantDiagnostics> UpdateType);
208 /// Updates the TUStatus and emits it. Only called in the worker thread.
209 void emitTUStatus(TUAction FAction,
210 const TUStatus::BuildDetails *Detail = nullptr);
211
212 /// Determines the next action to perform.
213 /// All actions that should never run are discarded.
214 /// Returns a deadline for the next action. If it's expired, run now.
215 /// scheduleLocked() is called again at the deadline, or if requests arrive.
216 Deadline scheduleLocked();
217 /// Should the first task in the queue be skipped instead of run?
218 bool shouldSkipHeadLocked() const;
219
220 struct Request {
221 llvm::unique_function<void()> Action;
222 std::string Name;
223 steady_clock::time_point AddTime;
224 Context Ctx;
225 llvm::Optional<WantDiagnostics> UpdateType;
226 };
227
228 /// Handles retention of ASTs.
229 TUScheduler::ASTCache &IdleASTs;
230 const bool RunSync;
231 /// Time to wait after an update to see whether another update obsoletes it.
232 const steady_clock::duration UpdateDebounce;
233 /// File that ASTWorker is responsible for.
234 const Path FileName;
235 /// Whether to keep the built preambles in memory or on disk.
236 const bool StorePreambleInMemory;
237 /// Callback invoked when preamble or main file AST is built.
238 ParsingCallbacks &Callbacks;
239 /// Helper class required to build the ASTs.
240 const std::shared_ptr<PCHContainerOperations> PCHs;
241 /// Only accessed by the worker thread.
242 TUStatus Status;
243
244 Semaphore &Barrier;
245 /// Inputs, corresponding to the current state of AST.
246 ParseInputs FileInputs;
247 /// Whether the diagnostics for the current FileInputs were reported to the
248 /// users before.
249 bool DiagsWereReported = false;
250 /// Size of the last AST
251 /// Guards members used by both TUScheduler and the worker thread.
252 mutable std::mutex Mutex;
253 std::shared_ptr<const PreambleData> LastBuiltPreamble; /* GUARDED_BY(Mutex) */
254 /// Becomes ready when the first preamble build finishes.
255 Notification PreambleWasBuilt;
256 /// Set to true to signal run() to finish processing.
257 bool Done; /* GUARDED_BY(Mutex) */
258 std::deque<Request> Requests; /* GUARDED_BY(Mutex) */
259 mutable std::condition_variable RequestsCV;
260 // FIXME: rename it to better fix the current usage, we also use it to guard
261 // emitting TUStatus.
262 /// Guards a critical section for running the diagnostics callbacks.
263 std::mutex DiagsMu;
264 // Used to prevent remove document + leading to out-of-order diagnostics:
265 // The lifetime of the old/new ASTWorkers will overlap, but their handles
266 // don't. When the old handle is destroyed, the old worker will stop reporting
267 // diagnostics.
268 bool ReportDiagnostics = true; /* GUARDED_BY(DiagMu) */
269 };
270
271 /// A smart-pointer-like class that points to an active ASTWorker.
272 /// In destructor, signals to the underlying ASTWorker that no new requests will
273 /// be sent and the processing loop may exit (after running all pending
274 /// requests).
275 class ASTWorkerHandle {
276 friend class ASTWorker;
277 ASTWorkerHandle(std::shared_ptr<ASTWorker> Worker)
278 : Worker(std::move(Worker)) {
279 assert(this->Worker);
280 }
281
282 public:
283 ASTWorkerHandle(const ASTWorkerHandle &) = delete;
284 ASTWorkerHandle &operator=(const ASTWorkerHandle &) = delete;
285 ASTWorkerHandle(ASTWorkerHandle &&) = default;
286 ASTWorkerHandle &operator=(ASTWorkerHandle &&) = default;
287
288 ~ASTWorkerHandle() {
289 if (Worker)
290 Worker->stop();
291 }
292
293 ASTWorker &operator*() {
294 assert(Worker && "Handle was moved from");
295 return *Worker;
296 }
297
298 ASTWorker *operator->() {
299 assert(Worker && "Handle was moved from");
300 return Worker.get();
301 }
302
303 /// Returns an owning reference to the underlying ASTWorker that can outlive
304 /// the ASTWorkerHandle. However, no new requests to an active ASTWorker can
305 /// be schedule via the returned reference, i.e. only reads of the preamble
306 /// are possible.
307 std::shared_ptr<const ASTWorker> lock() { return Worker; }
308
309 private:
310 std::shared_ptr<ASTWorker> Worker;
311 };
312
313 ASTWorkerHandle ASTWorker::create(PathRef FileName,
314 TUScheduler::ASTCache &IdleASTs,
315 AsyncTaskRunner *Tasks, Semaphore &Barrier,
316 steady_clock::duration UpdateDebounce,
317 std::shared_ptr<PCHContainerOperations> PCHs,
318 bool StorePreamblesInMemory,
319 ParsingCallbacks &Callbacks) {
320 std::shared_ptr<ASTWorker> Worker(new ASTWorker(
321 FileName, IdleASTs, Barrier, /*RunSync=*/!Tasks, UpdateDebounce,
322 std::move(PCHs), StorePreamblesInMemory, Callbacks));
323 if (Tasks)
324 Tasks->runAsync("worker:" + llvm::sys::path::filename(FileName),
325 [Worker]() { Worker->run(); });
326
327 return ASTWorkerHandle(std::move(Worker));
328 }
329
330 ASTWorker::ASTWorker(PathRef FileName, TUScheduler::ASTCache &LRUCache,
331 Semaphore &Barrier, bool RunSync,
332 steady_clock::duration UpdateDebounce,
333 std::shared_ptr<PCHContainerOperations> PCHs,
334 bool StorePreamblesInMemory, ParsingCallbacks &Callbacks)
335 : IdleASTs(LRUCache), RunSync(RunSync), UpdateDebounce(UpdateDebounce),
336 FileName(FileName), StorePreambleInMemory(StorePreamblesInMemory),
337 Callbacks(Callbacks),
338 PCHs(std::move(PCHs)), Status{TUAction(TUAction::Idle, ""),
339 TUStatus::BuildDetails()},
340 Barrier(Barrier), Done(false) {}
341
342 ASTWorker::~ASTWorker() {
343 // Make sure we remove the cached AST, if any.
344 IdleASTs.take(this);
345 #ifndef NDEBUG
346 std::lock_guard<std::mutex> Lock(Mutex);
347 assert(Done && "handle was not destroyed");
348 assert(Requests.empty() && "unprocessed requests when destroying ASTWorker");
349 #endif
350 }
351
352 void ASTWorker::update(ParseInputs Inputs, WantDiagnostics WantDiags) {
353 llvm::StringRef TaskName = "Update";
354 auto Task = [=]() mutable {
355 // Will be used to check if we can avoid rebuilding the AST.
356 bool InputsAreTheSame =
357 std::tie(FileInputs.CompileCommand, FileInputs.Contents) ==
358 std::tie(Inputs.CompileCommand, Inputs.Contents);
359
360 tooling::CompileCommand OldCommand = std::move(FileInputs.CompileCommand);
361 bool PrevDiagsWereReported = DiagsWereReported;
362 FileInputs = Inputs;
363 DiagsWereReported = false;
364 emitTUStatus({TUAction::BuildingPreamble, TaskName});
365 log("Updating file {0} with command [{1}] {2}", FileName,
366 Inputs.CompileCommand.Directory,
367 llvm::join(Inputs.CompileCommand.CommandLine, " "));
368 // Rebuild the preamble and the AST.
369 std::unique_ptr<CompilerInvocation> Invocation =
370 buildCompilerInvocation(Inputs);
371 if (!Invocation) {
372 elog("Could not build CompilerInvocation for file {0}", FileName);
373 // Remove the old AST if it's still in cache.
374 IdleASTs.take(this);
375 TUStatus::BuildDetails Details;
376 Details.BuildFailed = true;
377 emitTUStatus({TUAction::BuildingPreamble, TaskName}, &Details);
378 // Make sure anyone waiting for the preamble gets notified it could not
379 // be built.
380 PreambleWasBuilt.notify();
381 return;
382 }
383
384 std::shared_ptr<const PreambleData> OldPreamble =
385 getPossiblyStalePreamble();
386 std::shared_ptr<const PreambleData> NewPreamble = buildPreamble(
387 FileName, *Invocation, OldPreamble, OldCommand, Inputs, PCHs,
388 StorePreambleInMemory,
389 [this](ASTContext &Ctx, std::shared_ptr<clang::Preprocessor> PP) {
390 Callbacks.onPreambleAST(FileName, Ctx, std::move(PP));
391 });
392
393 bool CanReuseAST = InputsAreTheSame && (OldPreamble == NewPreamble);
394 {
395 std::lock_guard<std::mutex> Lock(Mutex);
396 LastBuiltPreamble = NewPreamble;
397 }
398 // Before doing the expensive AST reparse, we want to release our reference
399 // to the old preamble, so it can be freed if there are no other references
400 // to it.
401 OldPreamble.reset();
402 PreambleWasBuilt.notify();
403 emitTUStatus({TUAction::BuildingFile, TaskName});
404 if (!CanReuseAST) {
405 IdleASTs.take(this); // Remove the old AST if it's still in cache.
406 } else {
407 // Since we don't need to rebuild the AST, we might've already reported
408 // the diagnostics for it.
409 if (PrevDiagsWereReported) {
410 DiagsWereReported = true;
411 // Take a shortcut and don't report the diagnostics, since they should
412 // not changed. All the clients should handle the lack of OnUpdated()
413 // call anyway to handle empty result from buildAST.
414 // FIXME(ibiryukov): the AST could actually change if non-preamble
415 // includes changed, but we choose to ignore it.
416 // FIXME(ibiryukov): should we refresh the cache in IdleASTs for the
417 // current file at this point?
418 log("Skipping rebuild of the AST for {0}, inputs are the same.",
419 FileName);
420 TUStatus::BuildDetails Details;
421 Details.ReuseAST = true;
422 emitTUStatus({TUAction::BuildingFile, TaskName}, &Details);
423 return;
424 }
425 }
426
427 // We only need to build the AST if diagnostics were requested.
428 if (WantDiags == WantDiagnostics::No)
429 return;
430
431 {
432 std::lock_guard<std::mutex> Lock(DiagsMu);
433 // No need to rebuild the AST if we won't send the diagnotics. However,
434 // note that we don't prevent preamble rebuilds.
435 if (!ReportDiagnostics)
436 return;
437 }
438
439 // Get the AST for diagnostics.
440 llvm::Optional<std::unique_ptr<ParsedAST>> AST = IdleASTs.take(this);
441 if (!AST) {
442 llvm::Optional<ParsedAST> NewAST =
443 buildAST(FileName, std::move(Invocation), Inputs, NewPreamble, PCHs);
444 AST = NewAST ? llvm::make_unique<ParsedAST>(std::move(*NewAST)) : nullptr;
445 if (!(*AST)) { // buildAST fails.
446 TUStatus::BuildDetails Details;
447 Details.BuildFailed = true;
448 emitTUStatus({TUAction::BuildingFile, TaskName}, &Details);
449 }
450 } else {
451 // We are reusing the AST.
452 TUStatus::BuildDetails Details;
453 Details.ReuseAST = true;
454 emitTUStatus({TUAction::BuildingFile, TaskName}, &Details);
455 }
456 // We want to report the diagnostics even if this update was cancelled.
457 // It seems more useful than making the clients wait indefinitely if they
458 // spam us with updates.
459 // Note *AST can still be null if buildAST fails.
460 if (*AST) {
461 {
462 std::lock_guard<std::mutex> Lock(DiagsMu);
463 if (ReportDiagnostics)
464 Callbacks.onDiagnostics(FileName, (*AST)->getDiagnostics());
465 }
466 trace::Span Span("Running main AST callback");
467 Callbacks.onMainAST(FileName, **AST);
468 DiagsWereReported = true;
469 }
470 // Stash the AST in the cache for further use.
471 IdleASTs.put(this, std::move(*AST));
472 };
473 startTask(TaskName, std::move(Task), WantDiags);
474 }
475
476 void ASTWorker::runWithAST(
477 llvm::StringRef Name,
478 llvm::unique_function<void(llvm::Expected<InputsAndAST>)> Action) {
479 auto Task = [=](decltype(Action) Action) {
480 if (isCancelled())
481 return Action(llvm::make_error<CancelledError>());
482 llvm::Optional<std::unique_ptr<ParsedAST>> AST = IdleASTs.take(this);
483 if (!AST) {
484 std::unique_ptr<CompilerInvocation> Invocation =
485 buildCompilerInvocation(FileInputs);
486 // Try rebuilding the AST.
487 llvm::Optional<ParsedAST> NewAST =
488 Invocation
489 ? buildAST(FileName,
490 llvm::make_unique<CompilerInvocation>(*Invocation),
491 FileInputs, getPossiblyStalePreamble(), PCHs)
492 : None;
493 AST = NewAST ? llvm::make_unique<ParsedAST>(std::move(*NewAST)) : nullptr;
494 }
495 // Make sure we put the AST back into the LRU cache.
496 auto _ = llvm::make_scope_exit(
497 [&AST, this]() { IdleASTs.put(this, std::move(*AST)); });
498 // Run the user-provided action.
499 if (!*AST)
500 return Action(llvm::make_error<llvm::StringError>(
501 "invalid AST", llvm::errc::invalid_argument));
502 Action(InputsAndAST{FileInputs, **AST});
503 };
504 startTask(Name, Bind(Task, std::move(Action)),
505 /*UpdateType=*/None);
506 }
507
508 std::shared_ptr<const PreambleData>
509 ASTWorker::getPossiblyStalePreamble() const {
510 std::lock_guard<std::mutex> Lock(Mutex);
511 return LastBuiltPreamble;
512 }
513
514 void ASTWorker::getCurrentPreamble(
515 llvm::unique_function<void(std::shared_ptr<const PreambleData>)> Callback) {
516 // We could just call startTask() to throw the read on the queue, knowing
517 // it will run after any updates. But we know this task is cheap, so to
518 // improve latency we cheat: insert it on the queue after the last update.
519 std::unique_lock<std::mutex> Lock(Mutex);
520 auto LastUpdate =
521 std::find_if(Requests.rbegin(), Requests.rend(),
522 [](const Request &R) { return R.UpdateType.hasValue(); });
523 // If there were no writes in the queue, the preamble is ready now.
524 if (LastUpdate == Requests.rend()) {
525 Lock.unlock();
526 return Callback(getPossiblyStalePreamble());
527 }
528 assert(!RunSync && "Running synchronously, but queue is non-empty!");
529 Requests.insert(LastUpdate.base(),
530 Request{Bind(
531 [this](decltype(Callback) Callback) {
532 Callback(getPossiblyStalePreamble());
533 },
534 std::move(Callback)),
535 "GetPreamble", steady_clock::now(),
536 Context::current().clone(),
537 /*UpdateType=*/None});
538 Lock.unlock();
539 RequestsCV.notify_all();
540 }
541
542 void ASTWorker::waitForFirstPreamble() const { PreambleWasBuilt.wait(); }
543
544 std::size_t ASTWorker::getUsedBytes() const {
545 // Note that we don't report the size of ASTs currently used for processing
546 // the in-flight requests. We used this information for debugging purposes
547 // only, so this should be fine.
548 std::size_t Result = IdleASTs.getUsedBytes(this);
549 if (auto Preamble = getPossiblyStalePreamble())
550 Result += Preamble->Preamble.getSize();
551 return Result;
552 }
553
554 bool ASTWorker::isASTCached() const { return IdleASTs.getUsedBytes(this) != 0; }
555
556 void ASTWorker::stop() {
557 {
558 std::lock_guard<std::mutex> Lock(DiagsMu);
559 ReportDiagnostics = false;
560 }
561 {
562 std::lock_guard<std::mutex> Lock(Mutex);
563 assert(!Done && "stop() called twice");
564 Done = true;
565 }
566 RequestsCV.notify_all();
567 }
568
569 void ASTWorker::startTask(llvm::StringRef Name,
570 llvm::unique_function<void()> Task,
571 llvm::Optional<WantDiagnostics> UpdateType) {
572 if (RunSync) {
573 assert(!Done && "running a task after stop()");
574 trace::Span Tracer(Name + ":" + llvm::sys::path::filename(FileName));
575 Task();
576 return;
577 }
578
579 {
580 std::lock_guard<std::mutex> Lock(Mutex);
581 assert(!Done && "running a task after stop()");
582 Requests.push_back(
583 {std::move(Task), Name, steady_clock::now(),
584 Context::current().derive(kFileBeingProcessed, FileName), UpdateType});
585 }
586 RequestsCV.notify_all();
587 }
588
589 void ASTWorker::emitTUStatus(TUAction Action,
590 const TUStatus::BuildDetails *Details) {
591 Status.Action = std::move(Action);
592 if (Details)
593 Status.Details = *Details;
594 std::lock_guard<std::mutex> Lock(DiagsMu);
595 // Do not emit TU statuses when the ASTWorker is shutting down.
596 if (ReportDiagnostics) {
597 Callbacks.onFileUpdated(FileName, Status);
598 }
599 }
600
601 void ASTWorker::run() {
602 while (true) {
603 Request Req;
604 {
605 std::unique_lock<std::mutex> Lock(Mutex);
606 for (auto Wait = scheduleLocked(); !Wait.expired();
607 Wait = scheduleLocked()) {
608 if (Done) {
609 if (Requests.empty())
610 return;
611 else // Even though Done is set, finish pending requests.
612 break; // However, skip delays to shutdown fast.
613 }
614
615 // Tracing: we have a next request, attribute this sleep to it.
616 llvm::Optional<WithContext> Ctx;
617 llvm::Optional<trace::Span> Tracer;
618 if (!Requests.empty()) {
619 Ctx.emplace(Requests.front().Ctx.clone());
620 Tracer.emplace("Debounce");
621 SPAN_ATTACH(*Tracer, "next_request", Requests.front().Name);
622 if (!(Wait == Deadline::infinity())) {
623 emitTUStatus({TUAction::Queued, Req.Name});
624 SPAN_ATTACH(*Tracer, "sleep_ms",
625 std::chrono::duration_cast<std::chrono::milliseconds>(
626 Wait.time() - steady_clock::now())
627 .count());
628 }
629 }
630
631 wait(Lock, RequestsCV, Wait);
632 }
633 Req = std::move(Requests.front());
634 // Leave it on the queue for now, so waiters don't see an empty queue.
635 } // unlock Mutex
636
637 {
638 std::unique_lock<Semaphore> Lock(Barrier, std::try_to_lock);
639 if (!Lock.owns_lock()) {
640 emitTUStatus({TUAction::Queued, Req.Name});
641 Lock.lock();
642 }
643 WithContext Guard(std::move(Req.Ctx));
644 trace::Span Tracer(Req.Name);
645 emitTUStatus({TUAction::RunningAction, Req.Name});
646 Req.Action();
647 }
648
649 bool IsEmpty = false;
650 {
651 std::lock_guard<std::mutex> Lock(Mutex);
652 Requests.pop_front();
653 IsEmpty = Requests.empty();
654 }
655 if (IsEmpty)
656 emitTUStatus({TUAction::Idle, /*Name*/ ""});
657 RequestsCV.notify_all();
658 }
659 }
660
661 Deadline ASTWorker::scheduleLocked() {
662 if (Requests.empty())
663 return Deadline::infinity(); // Wait for new requests.
664 // Handle cancelled requests first so the rest of the scheduler doesn't.
665 for (auto I = Requests.begin(), E = Requests.end(); I != E; ++I) {
666 if (!isCancelled(I->Ctx)) {
667 // Cancellations after the first read don't affect current scheduling.
668 if (I->UpdateType == None)
669 break;
670 continue;
671 }
672 // Cancelled reads are moved to the front of the queue and run immediately.
673 if (I->UpdateType == None) {
674 Request R = std::move(*I);
675 Requests.erase(I);
676 Requests.push_front(std::move(R));
677 return Deadline::zero();
678 }
679 // Cancelled updates are downgraded to auto-diagnostics, and may be elided.
680 if (I->UpdateType == WantDiagnostics::Yes)
681 I->UpdateType = WantDiagnostics::Auto;
682 }
683
684 while (shouldSkipHeadLocked())
685 Requests.pop_front();
686 assert(!Requests.empty() && "skipped the whole queue");
687 // Some updates aren't dead yet, but never end up being used.
688 // e.g. the first keystroke is live until obsoleted by the second.
689 // We debounce "maybe-unused" writes, sleeping 500ms in case they become dead.
690 // But don't delay reads (including updates where diagnostics are needed).
691 for (const auto &R : Requests)
692 if (R.UpdateType == None || R.UpdateType == WantDiagnostics::Yes)
693 return Deadline::zero();
694 // Front request needs to be debounced, so determine when we're ready.
695 Deadline D(Requests.front().AddTime + UpdateDebounce);
696 return D;
697 }
698
699 // Returns true if Requests.front() is a dead update that can be skipped.
700 bool ASTWorker::shouldSkipHeadLocked() const {
701 assert(!Requests.empty());
702 auto Next = Requests.begin();
703 auto UpdateType = Next->UpdateType;
704 if (!UpdateType) // Only skip updates.
705 return false;
706 ++Next;
707 // An update is live if its AST might still be read.
708 // That is, if it's not immediately followed by another update.
709 if (Next == Requests.end() || !Next->UpdateType)
710 return false;
711 // The other way an update can be live is if its diagnostics might be used.
712 switch (*UpdateType) {
713 case WantDiagnostics::Yes:
714 return false; // Always used.
715 case WantDiagnostics::No:
716 return true; // Always dead.
717 case WantDiagnostics::Auto:
718 // Used unless followed by an update that generates diagnostics.
719 for (; Next != Requests.end(); ++Next)
720 if (Next->UpdateType == WantDiagnostics::Yes ||
721 Next->UpdateType == WantDiagnostics::Auto)
722 return true; // Prefer later diagnostics.
723 return false;
724 }
725 llvm_unreachable("Unknown WantDiagnostics");
726 }
727
728 bool ASTWorker::blockUntilIdle(Deadline Timeout) const {
729 std::unique_lock<std::mutex> Lock(Mutex);
730 return wait(Lock, RequestsCV, Timeout, [&] { return Requests.empty(); });
731 }
732
733 // Render a TUAction to a user-facing string representation.
734 // TUAction represents clangd-internal states, we don't intend to expose them
735 // to users (say C++ programmers) directly to avoid confusion, we use terms that
736 // are familiar by C++ programmers.
737 std::string renderTUAction(const TUAction &Action) {
738 std::string Result;
739 llvm::raw_string_ostream OS(Result);
740 switch (Action.S) {
741 case TUAction::Queued:
742 OS << "file is queued";
743 break;
744 case TUAction::RunningAction:
745 OS << "running " << Action.Name;
746 break;
747 case TUAction::BuildingPreamble:
748 OS << "parsing includes";
749 break;
750 case TUAction::BuildingFile:
751 OS << "parsing main file";
752 break;
753 case TUAction::Idle:
754 OS << "idle";
755 break;
756 }
757 return OS.str();
758 }
759
760 } // namespace
761
762 unsigned getDefaultAsyncThreadsCount() {
763 unsigned HardwareConcurrency = std::thread::hardware_concurrency();
764 // C++ standard says that hardware_concurrency()
765 // may return 0, fallback to 1 worker thread in
766 // that case.
767 if (HardwareConcurrency == 0)
768 return 1;
769 return HardwareConcurrency;
770 }
771
772 FileStatus TUStatus::render(PathRef File) const {
773 FileStatus FStatus;
774 FStatus.uri = URIForFile::canonicalize(File, /*TUPath=*/File);
775 FStatus.state = renderTUAction(Action);
776 return FStatus;
777 }
778
779 struct TUScheduler::FileData {
780 /// Latest inputs, passed to TUScheduler::update().
781 std::string Contents;
782 tooling::CompileCommand Command;
783 ASTWorkerHandle Worker;
784 };
785
786 TUScheduler::TUScheduler(unsigned AsyncThreadsCount,
787 bool StorePreamblesInMemory,
788 std::unique_ptr<ParsingCallbacks> Callbacks,
789 std::chrono::steady_clock::duration UpdateDebounce,
790 ASTRetentionPolicy RetentionPolicy)
791 : StorePreamblesInMemory(StorePreamblesInMemory),
792 PCHOps(std::make_shared<PCHContainerOperations>()),
793 Callbacks(Callbacks ? move(Callbacks)
794 : llvm::make_unique<ParsingCallbacks>()),
795 Barrier(AsyncThreadsCount),
796 IdleASTs(llvm::make_unique<ASTCache>(RetentionPolicy.MaxRetainedASTs)),
797 UpdateDebounce(UpdateDebounce) {
798 if (0 < AsyncThreadsCount) {
799 PreambleTasks.emplace();
800 WorkerThreads.emplace();
801 }
802 }
803
804 TUScheduler::~TUScheduler() {
805 // Notify all workers that they need to stop.
806 Files.clear();
807
808 // Wait for all in-flight tasks to finish.
809 if (PreambleTasks)
810 PreambleTasks->wait();
811 if (WorkerThreads)
812 WorkerThreads->wait();
813 }
814
815 bool TUScheduler::blockUntilIdle(Deadline D) const {
816 for (auto &File : Files)
817 if (!File.getValue()->Worker->blockUntilIdle(D))
818 return false;
819 if (PreambleTasks)
820 if (!PreambleTasks->wait(D))
821 return false;
822 return true;
823 }
824
825 void TUScheduler::update(PathRef File, ParseInputs Inputs,
826 WantDiagnostics WantDiags) {
827 std::unique_ptr<FileData> &FD = Files[File];
828 if (!FD) {
829 // Create a new worker to process the AST-related tasks.
830 ASTWorkerHandle Worker = ASTWorker::create(
831 File, *IdleASTs, WorkerThreads ? WorkerThreads.getPointer() : nullptr,
832 Barrier, UpdateDebounce, PCHOps, StorePreamblesInMemory, *Callbacks);
833 FD = std::unique_ptr<FileData>(new FileData{
834 Inputs.Contents, Inputs.CompileCommand, std::move(Worker)});
835 } else {
836 FD->Contents = Inputs.Contents;
837 FD->Command = Inputs.CompileCommand;
838 }
839 FD->Worker->update(std::move(Inputs), WantDiags);
840 }
841
842 void TUScheduler::remove(PathRef File) {
843 bool Removed = Files.erase(File);
844 if (!Removed)
845 elog("Trying to remove file from TUScheduler that is not tracked: {0}",
846 File);
847 }
848
849 void TUScheduler::run(llvm::StringRef Name,
850 llvm::unique_function<void()> Action) {
851 if (!PreambleTasks)
852 return Action();
853 PreambleTasks->runAsync(Name, std::move(Action));
854 }
855
856 void TUScheduler::runWithAST(
857 llvm::StringRef Name, PathRef File,
858 llvm::unique_function<void(llvm::Expected<InputsAndAST>)> Action) {
859 auto It = Files.find(File);
860 if (It == Files.end()) {
861 Action(llvm::make_error<LSPError>(
862 "trying to get AST for non-added document", ErrorCode::InvalidParams));
863 return;
864 }
865
866 It->second->Worker->runWithAST(Name, std::move(Action));
867 }
868
869 void TUScheduler::runWithPreamble(
870 llvm::StringRef Name, PathRef File, PreambleConsistency Consistency,
871 llvm::unique_function<void(llvm::Expected<InputsAndPreamble>)> Action) {
872 auto It = Files.find(File);
873 if (It == Files.end()) {
874 Action(llvm::make_error<LSPError>(
875 "trying to get preamble for non-added document",
876 ErrorCode::InvalidParams));
877 return;
878 }
879
880 if (!PreambleTasks) {
881 trace::Span Tracer(Name);
882 SPAN_ATTACH(Tracer, "file", File);
883 std::shared_ptr<const PreambleData> Preamble =
884 It->second->Worker->getPossiblyStalePreamble();
885 Action(InputsAndPreamble{It->second->Contents, It->second->Command,
886 Preamble.get()});
887 return;
888 }
889
890 // Future is populated if the task needs a specific preamble.
891 std::future<std::shared_ptr<const PreambleData>> ConsistentPreamble;
892 if (Consistency == Consistent) {
893 std::promise<std::shared_ptr<const PreambleData>> Promise;
894 ConsistentPreamble = Promise.get_future();
895 It->second->Worker->getCurrentPreamble(Bind(
896 [](decltype(Promise) Promise,
897 std::shared_ptr<const PreambleData> Preamble) {
898 Promise.set_value(std::move(Preamble));
899 },
900 std::move(Promise)));
901 }
902
903 std::shared_ptr<const ASTWorker> Worker = It->second->Worker.lock();
904 auto Task = [Worker, this](std::string Name, std::string File,
905 std::string Contents,
906 tooling::CompileCommand Command, Context Ctx,
907 decltype(ConsistentPreamble) ConsistentPreamble,
908 decltype(Action) Action) mutable {
909 std::shared_ptr<const PreambleData> Preamble;
910 if (ConsistentPreamble.valid()) {
911 Preamble = ConsistentPreamble.get();
912 } else {
913 // We don't want to be running preamble actions before the preamble was
914 // built for the first time. This avoids extra work of processing the
915 // preamble headers in parallel multiple times.
916 Worker->waitForFirstPreamble();
917 Preamble = Worker->getPossiblyStalePreamble();
918 }
919
920 std::lock_guard<Semaphore> BarrierLock(Barrier);
921 WithContext Guard(std::move(Ctx));
922 trace::Span Tracer(Name);
923 SPAN_ATTACH(Tracer, "file", File);
924 Action(InputsAndPreamble{Contents, Command, Preamble.get()});
925 };
926
927 PreambleTasks->runAsync(
928 "task:" + llvm::sys::path::filename(File),
929 Bind(Task, std::string(Name), std::string(File), It->second->Contents,
930 It->second->Command,
931 Context::current().derive(kFileBeingProcessed, File),
932 std::move(ConsistentPreamble), std::move(Action)));
933 }
934
935 std::vector<std::pair<Path, std::size_t>>
936 TUScheduler::getUsedBytesPerFile() const {
937 std::vector<std::pair<Path, std::size_t>> Result;
938 Result.reserve(Files.size());
939 for (auto &&PathAndFile : Files)
940 Result.push_back(
941 {PathAndFile.first(), PathAndFile.second->Worker->getUsedBytes()});
942 return Result;
943 }
944
945 std::vector<Path> TUScheduler::getFilesWithCachedAST() const {
946 std::vector<Path> Result;
947 for (auto &&PathAndFile : Files) {
948 if (!PathAndFile.second->Worker->isASTCached())
949 continue;
950 Result.push_back(PathAndFile.first());
951 }
952 return Result;
953 }
954
955 } // namespace clangd
956 } // namespace clang
clang::clangd::TUScheduler::PreambleConsistency
PreambleConsistency
Controls whether preamble reads wait for the preamble to be up-to-date.
Definition: TUScheduler.h:166
Command
const tooling::CompileCommand & Command
Definition: CodeComplete.cpp:1005
clang::clangd::TUScheduler::~TUScheduler
~TUScheduler()
Definition: TUScheduler.cpp:804
clang::clangd::WantDiagnostics
WantDiagnostics
Determines whether diagnostics should be generated for a file snapshot.
Definition: TUScheduler.h:39
Trace.h
Contents
llvm::StringRef Contents
Definition: CodeComplete.cpp:1007
llvm
Some operations such as code completion produce a set of candidates.
Definition: YAMLGenerator.cpp:28
clang::clangd::WantDiagnostics::No
Diagnostics must be generated for this snapshot.
clang::clangd::TUStatus::render
FileStatus render(PathRef File) const
Serialize this to an LSP file status item.
Definition: TUScheduler.cpp:772
clang::clangd::TUScheduler::getFileBeingProcessedInContext
static llvm::Optional< llvm::StringRef > getFileBeingProcessedInContext()
Definition: TUScheduler.cpp:69
clang::clangd::TUScheduler::blockUntilIdle
bool blockUntilIdle(Deadline D) const
Wait until there are no scheduled or running tasks.
Definition: TUScheduler.cpp:815
clang::clangd::buildAST
llvm::Optional< ParsedAST > buildAST(PathRef FileName, std::unique_ptr< CompilerInvocation > Invocation, const ParseInputs &Inputs, std::shared_ptr< const PreambleData > Preamble, std::shared_ptr< PCHContainerOperations > PCHs)
Build an AST from provided user inputs.
Definition: ClangdUnit.cpp:523
clang::clangd::TUScheduler::remove
void remove(PathRef File)
Remove File from the list of tracked files and schedule removal of its resources. ...
Definition: TUScheduler.cpp:842
clang::clangd::TUAction::Idle
Definition: TUScheduler.h:62
clang::clangd::TUAction::Queued
Definition: TUScheduler.h:57
clang::clangd::FileStatus::state
std::string state
The human-readable string presents the current state of the file, can be shown in the UI (e...
Definition: Protocol.h:1011
clang::clangd::PathRef
llvm::StringRef PathRef
A typedef to represent a ref to file path.
Definition: Path.h:24
clang::clangd::TUAction::RunningAction
Definition: TUScheduler.h:58
clang::clangd::TUScheduler::update
void update(PathRef File, ParseInputs Inputs, WantDiagnostics WD)
Schedule an update for File.
Definition: TUScheduler.cpp:825
clang::clangd::Key
Values in a Context are indexed by typed keys.
Definition: Context.h:41
clang::clangd::Callback
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
Definition: Function.h:29
clang::clangd::TextDocumentSyncKind::None
Documents should not be synced at all.
clang::clangd::Semaphore
Limits the number of threads that can acquire the lock at the same time.
Definition: Threading.h:41
clang::clangd::FileStatus::uri
URIForFile uri
The text document&#39;s URI.
Definition: Protocol.h:1008
clang::clangd::TUAction::BuildingFile
Definition: TUScheduler.h:60
clang::clangd::elog
void elog(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:57
clang::clangd::ParseInputs::Contents
std::string Contents
Definition: ClangdUnit.h:67
clang::clangd::TUScheduler::TUScheduler
TUScheduler(unsigned AsyncThreadsCount, bool StorePreamblesInMemory, std::unique_ptr< ParsingCallbacks > ASTCallbacks, std::chrono::steady_clock::duration UpdateDebounce, ASTRetentionPolicy RetentionPolicy)
Definition: TUScheduler.cpp:786
clang::clangd::ASTRetentionPolicy
Configuration of the AST retention policy.
Definition: TUScheduler.h:49
clang::clangd::isCancelled
bool isCancelled(const Context &Ctx)
True if the current context is within a cancelable task which was cancelled.
Definition: Cancellation.cpp:27
Cancellation.h
clang::clangd::WantDiagnostics::Yes
Ctx
Context Ctx
Definition: TUScheduler.cpp:224
clang::clangd::SymbolOrigin::AST
clang::clangd::Context::clone
Context clone() const
Clone this context object.
Definition: Context.cpp:21
clang::clangd::Bind
ForwardBinder< Func, Args... > Bind(Func F, Args &&... As)
Creates an object that stores a callable (F) and first arguments to the callable (As) and allows to c...
Definition: Function.h:82
UpdateType
llvm::Optional< WantDiagnostics > UpdateType
Definition: TUScheduler.cpp:225
clang::clangd::Deadline::infinity
static Deadline infinity()
Definition: Threading.h:63
Action
llvm::unique_function< void()> Action
Definition: TUScheduler.cpp:221
clang::clangd::log
void log(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:63
clang::clangd::TUScheduler::ASTCache::put
void put(Key K, std::unique_ptr< ParsedAST > V)
Store the value in the pool, possibly removing the last used AST.
Definition: TUScheduler.cpp:97
clang::clangd::Path
std::string Path
A typedef to represent a file path.
Definition: Path.h:21
clang::clangd::Context::current
static const Context & current()
Returns the context for the current thread, creating it if needed.
Definition: Context.cpp:28
clang::clangd::buildCompilerInvocation
std::unique_ptr< CompilerInvocation > buildCompilerInvocation(const ParseInputs &Inputs)
Builds compiler invocation that could be used to build AST or preamble.
Definition: ClangdUnit.cpp:426
clang::clangd::ParseInputs::CompileCommand
tooling::CompileCommand CompileCommand
Definition: ClangdUnit.h:65
clang::clangd::URIForFile::canonicalize
static URIForFile canonicalize(llvm::StringRef AbsPath, llvm::StringRef TUPath)
Canonicalizes AbsPath via URI.
Definition: Protocol.cpp:32
clang::clangd::TUScheduler::getUsedBytesPerFile
std::vector< std::pair< Path, std::size_t > > getUsedBytesPerFile() const
Returns estimated memory usage for each of the currently open files.
Definition: TUScheduler.cpp:936
clang::clangd::TUScheduler::runWithPreamble
void runWithPreamble(llvm::StringRef Name, PathRef File, PreambleConsistency Consistency, Callback< InputsAndPreamble > Action)
Schedule an async read of the preamble.
Definition: TUScheduler.cpp:869
D
const Decl * D
Definition: XRefs.cpp:79
Result
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
Definition: ClangdServer.cpp:60
clang::clangd::TUScheduler::getFilesWithCachedAST
std::vector< Path > getFilesWithCachedAST() const
Returns a list of files with ASTs currently stored in memory.
Definition: TUScheduler.cpp:945
clang::clangd::buildPreamble
std::shared_ptr< const PreambleData > buildPreamble(PathRef FileName, CompilerInvocation &CI, std::shared_ptr< const PreambleData > OldPreamble, const tooling::CompileCommand &OldCompileCommand, const ParseInputs &Inputs, std::shared_ptr< PCHContainerOperations > PCHs, bool StoreInMemory, PreambleParsedCallback PreambleCallback)
Rebuild the preamble for the new inputs unless the old one can be reused.
Definition: ClangdUnit.cpp:454
FileName
PathRef FileName
Definition: CodeComplete.cpp:1004
clang::clangd::wait
void wait(std::unique_lock< std::mutex > &Lock, std::condition_variable &CV, Deadline D)
Wait once on CV for the specified duration.
Definition: Threading.cpp:107
clang::clangd::ErrorCode::InvalidParams
clang::clangd::AsyncTaskRunner
Runs tasks on separate (detached) threads and wait for all tasks to finish.
Definition: Threading.h:105
clang::clangd::Context
A context is an immutable container for per-request data that must be propagated through layers that ...
Definition: Context.h:70
Name
std::string Name
Definition: TUScheduler.cpp:222
clang::clangd::TUScheduler::ASTCache::Key
const ASTWorker * Key
Definition: TUScheduler.cpp:81
clang::clangd::TUStatus::BuildDetails
Definition: TUScheduler.h:74
clang::clangd::getDefaultAsyncThreadsCount
unsigned getDefaultAsyncThreadsCount()
Returns a number of a default async threads to use for TUScheduler.
Definition: TUScheduler.cpp:762
clang::clangd::WithContext
WithContext replaces Context::current() with a provided scope.
Definition: Context.h:190
clang::clangd::TUAction
Definition: TUScheduler.h:55
clang::clangd::ParsingCallbacks
Definition: TUScheduler.h:87
clang::clangd::TUScheduler::FileData::Contents
std::string Contents
Latest inputs, passed to TUScheduler::update().
Definition: TUScheduler.cpp:781
Logger.h
clang::clangd::ParseInputs
Information required to run clang, e.g. to parse AST or do code completion.
Definition: ClangdUnit.h:64
clang::clangd::TUScheduler::FileData
Definition: TUScheduler.cpp:779
clang::clangd::TUScheduler::ASTCache::ASTCache
ASTCache(unsigned MaxRetainedASTs)
Definition: TUScheduler.cpp:83
Preamble
const PreambleData * Preamble
Definition: CodeComplete.cpp:1006
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ChangeNamespace.cpp:18
clang::clangd::Deadline::zero
static Deadline zero()
Definition: Threading.h:62
clang::clangd::Context::derive
Context derive(const Key< Type > &Key, typename std::decay< Type >::type Value) const &
Derives a child context It is safe to move or destroy a parent context after calling derive()...
Definition: Context.h:122
clang::clangd::TUScheduler::ASTCache::take
llvm::Optional< std::unique_ptr< ParsedAST > > take(Key K)
Returns the cached value for K, or llvm::None if the value is not in the cache anymore.
Definition: TUScheduler.cpp:115
PCHs
std::shared_ptr< PCHContainerOperations > PCHs
Definition: CodeComplete.cpp:1010
AddTime
steady_clock::time_point AddTime
Definition: TUScheduler.cpp:223
clang::clangd::TUScheduler::FileData::Command
tooling::CompileCommand Command
Definition: TUScheduler.cpp:782
clang::clangd::kFileBeingProcessed
static clang::clangd::Key< std::string > kFileBeingProcessed
Definition: TUScheduler.cpp:67
clang::clangd::TUScheduler::runWithAST
void runWithAST(llvm::StringRef Name, PathRef File, Callback< InputsAndAST > Action)
Schedule an async read of the AST.
Definition: TUScheduler.cpp:856
clang::clangd::Deadline
A point in time we can wait for.
Definition: Threading.h:58
clang::clangd::FileStatus
Clangd extension: indicates the current state of the file in clangd, sent from server via the textDoc...
Definition: Protocol.h:1006
clang::clangd::TUAction::BuildingPreamble
Definition: TUScheduler.h:59
clang::clangd::InputsAndPreamble
Definition: TUScheduler.h:32
clang::tidy::cppcoreguidelines::join
static std::string join(ArrayRef< SpecialMemberFunctionsCheck::SpecialMemberFunctionKind > SMFS, llvm::StringRef AndOr)
Definition: SpecialMemberFunctionsCheck.cpp:82
clang::clangd::TUScheduler::ASTCache
An LRU cache of idle ASTs.
Definition: TUScheduler.cpp:79
clang::clangd::trace::Span
Records an event whose duration is the lifetime of the Span object.
Definition: Trace.h:83
clang::clangd::CompletionItemKind::File
clang::clangd::InputsAndPreamble::Contents
llvm::StringRef Contents
Definition: TUScheduler.h:33
SPAN_ATTACH
#define SPAN_ATTACH(S, Name, Expr)
Attach a key-value pair to a Span event.
Definition: Trace.h:99
clang::clangd::WantDiagnostics::Auto
Diagnostics must not be generated for this snapshot.
clang::clangd::TUScheduler::FileData::Worker
ASTWorkerHandle Worker
Definition: TUScheduler.cpp:783
TUScheduler.h
clang::clangd::TUScheduler::Consistent
The preamble is generated from the current version of the file.
Definition: TUScheduler.h:171
clang::clangd::TUScheduler::ASTCache::getUsedBytes
std::size_t getUsedBytes(Key K)
Returns result of getUsedBytes() for the AST cached by K.
Definition: TUScheduler.cpp:87
clang::clangd::TUScheduler::run
void run(llvm::StringRef Name, llvm::unique_function< void()> Action)
Schedule an async task with no dependencies.
Definition: TUScheduler.cpp:849