summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clangd/TUScheduler.cpp
blob: 96b29f12fdd1b59515a5efc3e09ccb536ad6f7d2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include "TUScheduler.h"
#include "clang/Frontend/PCHContainerOperations.h"
#include "llvm/Support/Errc.h"

namespace clang {
namespace clangd {
unsigned getDefaultAsyncThreadsCount() {
  unsigned HardwareConcurrency = std::thread::hardware_concurrency();
  // C++ standard says that hardware_concurrency()
  // may return 0, fallback to 1 worker thread in
  // that case.
  if (HardwareConcurrency == 0)
    return 1;
  return HardwareConcurrency;
}

TUScheduler::TUScheduler(unsigned AsyncThreadsCount,
                         bool StorePreamblesInMemory,
                         ASTParsedCallback ASTCallback)

    : Files(StorePreamblesInMemory, std::make_shared<PCHContainerOperations>(),
            std::move(ASTCallback)),
      Threads(AsyncThreadsCount) {}

void TUScheduler::update(
    Context Ctx, PathRef File, ParseInputs Inputs,
    UniqueFunction<void(Context Ctx,
                        llvm::Optional<std::vector<DiagWithFixIts>>)>
        OnUpdated) {
  CachedInputs[File] = Inputs;

  auto Resources = Files.getOrCreateFile(File);
  auto DeferredRebuild = Resources->deferRebuild(std::move(Inputs));

  Threads.addToFront(
      [](Context Ctx, decltype(OnUpdated) OnUpdated,
         decltype(DeferredRebuild) DeferredRebuild) {
        auto Diags = DeferredRebuild(Ctx);
        OnUpdated(std::move(Ctx), Diags);
      },
      std::move(Ctx), std::move(OnUpdated), std::move(DeferredRebuild));
}

void TUScheduler::remove(PathRef File,
                         UniqueFunction<void(llvm::Error)> Action) {
  CachedInputs.erase(File);

  auto Resources = Files.removeIfPresent(File);
  if (!Resources) {
    Action(llvm::make_error<llvm::StringError>(
        "trying to remove non-added document", llvm::errc::invalid_argument));
    return;
  }

  auto DeferredCancel = Resources->deferCancelRebuild();
  Threads.addToFront(
      [](decltype(Action) Action, decltype(DeferredCancel) DeferredCancel) {
        DeferredCancel();
        Action(llvm::Error::success());
      },
      std::move(Action), std::move(DeferredCancel));
}

void TUScheduler::runWithAST(
    PathRef File, UniqueFunction<void(llvm::Expected<InputsAndAST>)> Action) {
  auto Resources = Files.getFile(File);
  if (!Resources) {
    Action(llvm::make_error<llvm::StringError>(
        "trying to get AST for non-added document",
        llvm::errc::invalid_argument));
    return;
  }

  const ParseInputs &Inputs = getInputs(File);
  // We currently block the calling thread until AST is available and run the
  // action on the calling thread to avoid inconsistent states coming from
  // subsequent updates.
  // FIXME(ibiryukov): this should be moved to the worker threads.
  Resources->getAST().get()->runUnderLock([&](ParsedAST *AST) {
    if (AST)
      Action(InputsAndAST{Inputs, *AST});
    else
      Action(llvm::make_error<llvm::StringError>(
          "Could not build AST for the latest file update",
          llvm::errc::invalid_argument));
  });
}

void TUScheduler::runWithPreamble(
    PathRef File,
    UniqueFunction<void(llvm::Expected<InputsAndPreamble>)> Action) {
  std::shared_ptr<CppFile> Resources = Files.getFile(File);
  if (!Resources) {
    Action(llvm::make_error<llvm::StringError>(
        "trying to get preamble for non-added document",
        llvm::errc::invalid_argument));
    return;
  }

  const ParseInputs &Inputs = getInputs(File);
  std::shared_ptr<const PreambleData> Preamble =
      Resources->getPossiblyStalePreamble();
  Threads.addToFront(
      [Resources, Preamble, Inputs](decltype(Action) Action) mutable {
        if (!Preamble)
          Preamble = Resources->getPossiblyStalePreamble();

        Action(InputsAndPreamble{Inputs, Preamble.get()});
      },
      std::move(Action));
}

const ParseInputs &TUScheduler::getInputs(PathRef File) {
  auto It = CachedInputs.find(File);
  assert(It != CachedInputs.end());
  return It->second;
}

std::vector<std::pair<Path, std::size_t>>
TUScheduler::getUsedBytesPerFile() const {
  return Files.getUsedBytesPerFile();
}
} // namespace clangd
} // namespace clang
OpenPOWER on IntegriCloud