brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.0 KiB · f42db89 Raw
144 lines · cpp
1//===--- Threading.cpp - Abstractions for multithreading ------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "support/Threading.h"10#include "support/Trace.h"11#include "llvm/ADT/ScopeExit.h"12#include "llvm/Support/Threading.h"13#include "llvm/Support/thread.h"14#include <atomic>15#include <optional>16#include <thread>17#ifdef __USE_POSIX18#include <pthread.h>19#elif defined(__APPLE__)20#include <sys/resource.h>21#elif defined(_WIN32)22#include <windows.h>23#endif24 25namespace clang {26namespace clangd {27 28void Notification::notify() {29  {30    std::lock_guard<std::mutex> Lock(Mu);31    Notified = true;32    // Broadcast with the lock held. This ensures that it's safe to destroy33    // a Notification after wait() returns, even from another thread.34    CV.notify_all();35  }36}37 38bool Notification::wait(Deadline D) const {39  std::unique_lock<std::mutex> Lock(Mu);40  return clangd::wait(Lock, CV, D, [&] { return Notified; });41}42 43Semaphore::Semaphore(std::size_t MaxLocks) : FreeSlots(MaxLocks) {}44 45bool Semaphore::try_lock() {46  std::unique_lock<std::mutex> Lock(Mutex);47  if (FreeSlots > 0) {48    --FreeSlots;49    return true;50  }51  return false;52}53 54void Semaphore::lock() {55  trace::Span Span("WaitForFreeSemaphoreSlot");56  // trace::Span can also acquire locks in ctor and dtor, we make sure it57  // happens when Semaphore's own lock is not held.58  {59    std::unique_lock<std::mutex> Lock(Mutex);60    SlotsChanged.wait(Lock, [&]() { return FreeSlots > 0; });61    --FreeSlots;62  }63}64 65void Semaphore::unlock() {66  std::unique_lock<std::mutex> Lock(Mutex);67  ++FreeSlots;68  Lock.unlock();69 70  SlotsChanged.notify_one();71}72 73AsyncTaskRunner::~AsyncTaskRunner() { wait(); }74 75bool AsyncTaskRunner::wait(Deadline D) const {76  std::unique_lock<std::mutex> Lock(Mutex);77  return clangd::wait(Lock, TasksReachedZero, D,78                      [&] { return InFlightTasks == 0; });79}80 81void AsyncTaskRunner::runAsync(const llvm::Twine &Name,82                               llvm::unique_function<void()> Action) {83  {84    std::lock_guard<std::mutex> Lock(Mutex);85    ++InFlightTasks;86  }87 88  auto CleanupTask = llvm::make_scope_exit([this]() {89    std::lock_guard<std::mutex> Lock(Mutex);90    int NewTasksCnt = --InFlightTasks;91    if (NewTasksCnt == 0) {92      // Note: we can't unlock here because we don't want the object to be93      // destroyed before we notify.94      TasksReachedZero.notify_one();95    }96  });97 98  auto Task = [Name = Name.str(), Action = std::move(Action),99               Cleanup = std::move(CleanupTask)]() mutable {100    llvm::set_thread_name(Name);101    Action();102    // Make sure function stored by ThreadFunc is destroyed before Cleanup runs.103    Action = nullptr;104  };105 106  // Ensure our worker threads have big enough stacks to run clang.107  llvm::thread Thread(108      /*clang::DesiredStackSize*/ std::optional<unsigned>(8 << 20),109      std::move(Task));110  Thread.detach();111}112 113Deadline timeoutSeconds(std::optional<double> Seconds) {114  using namespace std::chrono;115  if (!Seconds)116    return Deadline::infinity();117  return steady_clock::now() +118         duration_cast<steady_clock::duration>(duration<double>(*Seconds));119}120 121void wait(std::unique_lock<std::mutex> &Lock, std::condition_variable &CV,122          Deadline D) {123  if (D == Deadline::zero())124    return;125  if (D == Deadline::infinity())126    return CV.wait(Lock);127  CV.wait_until(Lock, D.time());128}129 130bool PeriodicThrottler::operator()() {131  Rep Now = Stopwatch::now().time_since_epoch().count();132  Rep OldNext = Next.load(std::memory_order_acquire);133  if (Now < OldNext)134    return false;135  // We're ready to run (but may be racing other threads).136  // Work out the updated target time, and run if we successfully bump it.137  Rep NewNext = Now + Period;138  return Next.compare_exchange_strong(OldNext, NewNext,139                                      std::memory_order_acq_rel);140}141 142} // namespace clangd143} // namespace clang144