diff clang-tools-extra/clangd/support/Threading.cpp @ 173:0572611fdcc8 llvm10 llvm12

reorgnization done
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 11:55:54 +0900
parents
children 2e18cbf3894f
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/clang-tools-extra/clangd/support/Threading.cpp	Mon May 25 11:55:54 2020 +0900
@@ -0,0 +1,120 @@
+#include "support/Threading.h"
+#include "support/Trace.h"
+#include "llvm/ADT/ScopeExit.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/Threading.h"
+#include <atomic>
+#include <thread>
+#ifdef __USE_POSIX
+#include <pthread.h>
+#elif defined(__APPLE__)
+#include <sys/resource.h>
+#elif defined(_WIN32)
+#include <windows.h>
+#endif
+
+namespace clang {
+namespace clangd {
+
+void Notification::notify() {
+  {
+    std::lock_guard<std::mutex> Lock(Mu);
+    Notified = true;
+    // Broadcast with the lock held. This ensures that it's safe to destroy
+    // a Notification after wait() returns, even from another thread.
+    CV.notify_all();
+  }
+}
+
+void Notification::wait() const {
+  std::unique_lock<std::mutex> Lock(Mu);
+  CV.wait(Lock, [this] { return Notified; });
+}
+
+Semaphore::Semaphore(std::size_t MaxLocks) : FreeSlots(MaxLocks) {}
+
+bool Semaphore::try_lock() {
+  std::unique_lock<std::mutex> Lock(Mutex);
+  if (FreeSlots > 0) {
+    --FreeSlots;
+    return true;
+  }
+  return false;
+}
+
+void Semaphore::lock() {
+  trace::Span Span("WaitForFreeSemaphoreSlot");
+  // trace::Span can also acquire locks in ctor and dtor, we make sure it
+  // happens when Semaphore's own lock is not held.
+  {
+    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() { wait(); }
+
+bool AsyncTaskRunner::wait(Deadline D) const {
+  std::unique_lock<std::mutex> Lock(Mutex);
+  return clangd::wait(Lock, TasksReachedZero, D,
+                      [&] { return InFlightTasks == 0; });
+}
+
+void AsyncTaskRunner::runAsync(const llvm::Twine &Name,
+                               llvm::unique_function<void()> Action) {
+  {
+    std::lock_guard<std::mutex> Lock(Mutex);
+    ++InFlightTasks;
+  }
+
+  auto CleanupTask = llvm::make_scope_exit([this]() {
+    std::lock_guard<std::mutex> Lock(Mutex);
+    int NewTasksCnt = --InFlightTasks;
+    if (NewTasksCnt == 0) {
+      // Note: we can't unlock here because we don't want the object to be
+      // destroyed before we notify.
+      TasksReachedZero.notify_one();
+    }
+  });
+
+  auto Task = [Name = Name.str(), Action = std::move(Action),
+               Cleanup = std::move(CleanupTask)]() mutable {
+    llvm::set_thread_name(Name);
+    Action();
+    // Make sure function stored by ThreadFunc is destroyed before Cleanup runs.
+    Action = nullptr;
+  };
+
+  // Ensure our worker threads have big enough stacks to run clang.
+  llvm::llvm_execute_on_thread_async(std::move(Task),
+                                     /*clang::DesiredStackSize*/ 8 << 20);
+}
+
+Deadline timeoutSeconds(llvm::Optional<double> Seconds) {
+  using namespace std::chrono;
+  if (!Seconds)
+    return Deadline::infinity();
+  return steady_clock::now() +
+         duration_cast<steady_clock::duration>(duration<double>(*Seconds));
+}
+
+void wait(std::unique_lock<std::mutex> &Lock, std::condition_variable &CV,
+          Deadline D) {
+  if (D == Deadline::zero())
+    return;
+  if (D == Deadline::infinity())
+    return CV.wait(Lock);
+  CV.wait_until(Lock, D.time());
+}
+
+} // namespace clangd
+} // namespace clang