summaryrefslogtreecommitdiff
path: root/clang-tools-extra/clangd/Threading.cpp
blob: 94bb76c5f1f1280a2cef379f99307a67b909aaa0 (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
#include "Threading.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/Threading.h"
#include <thread>

namespace clang {
namespace clangd {

CancellationFlag::CancellationFlag()
    : WasCancelled(std::make_shared<std::atomic<bool>>(false)) {}

Semaphore::Semaphore(std::size_t MaxLocks) : FreeSlots(MaxLocks) {}

void Semaphore::lock() {
  std::unique_lock<std::mutex> Lock(Mutex);
  SlotsChanged.wait(Lock, [&]() { return FreeSlots > 0; });
  --FreeSlots;
}

void Semaphore::unlock() {
  std::unique_lock<std::mutex> Lock(Mutex);
  ++FreeSlots;
  Lock.unlock();

  SlotsChanged.notify_one();
}

AsyncTaskRunner::~AsyncTaskRunner() { waitForAll(); }

void AsyncTaskRunner::waitForAll() {
  std::unique_lock<std::mutex> Lock(Mutex);
  TasksReachedZero.wait(Lock, [&]() { return InFlightTasks == 0; });
}

void AsyncTaskRunner::runAsync(UniqueFunction<void()> Action) {
  {
    std::unique_lock<std::mutex> Lock(Mutex);
    ++InFlightTasks;
  }

  auto CleanupTask = llvm::make_scope_exit([this]() {
    std::unique_lock<std::mutex> Lock(Mutex);
    int NewTasksCnt = --InFlightTasks;
    Lock.unlock();

    if (NewTasksCnt == 0)
      TasksReachedZero.notify_one();
  });

  std::thread(
      [](decltype(Action) Action, decltype(CleanupTask)) {
        Action();
        // Make sure function stored by Action is destroyed before CleanupTask
        // is run.
        Action = nullptr;
      },
      std::move(Action), std::move(CleanupTask))
      .detach();
}
} // namespace clangd
} // namespace clang