brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.7 KiB · f33b0b5 Raw
105 lines · c
1//===--- Cancellation.h -------------------------------------------*-C++-*-===//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// Cancellation mechanism for long-running tasks.9//10// This manages interactions between:11//12// 1. Client code that starts some long-running work, and maybe cancels later.13//14//   std::pair<Context, Canceler> Task = cancelableTask();15//   {16//     WithContext Cancelable(std::move(Task.first));17//     Expected18//     deepThoughtAsync([](int answer){ errs() << answer; });19//   }20//   // ...some time later...21//   if (User.fellAsleep())22//     Task.second();23//24//  (This example has an asynchronous computation, but synchronous examples25//  work similarly - the Canceler should be invoked from another thread).26//27// 2. Library code that executes long-running work, and can exit early if the28//   result is not needed.29//30//   void deepThoughtAsync(std::function<void(int)> Callback) {31//     runAsync([Callback]{32//       int A = ponder(6);33//       if (isCancelled())34//         return;35//       int B = ponder(9);36//       if (isCancelled())37//         return;38//       Callback(A * B);39//     });40//   }41//42//   (A real example may invoke the callback with an error on cancellation,43//   the CancelledError is provided for this purpose).44//45// Cancellation has some caveats:46//   - the work will only stop when/if the library code next checks for it.47//     Code outside clangd such as Sema will not do this.48//   - it's inherently racy: client code must be prepared to accept results49//     even after requesting cancellation.50//   - it's Context-based, so async work must be dispatched to threads in51//     ways that preserve the context. (Like runAsync() or TUScheduler).52//53// FIXME: We could add timestamps to isCancelled() and CancelledError.54//        Measuring the start -> cancel -> acknowledge -> finish timeline would55//        help find where libraries' cancellation should be improved.56 57#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_SUPPORT_CANCELLATION_H58#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_SUPPORT_CANCELLATION_H59 60#include "support/Context.h"61#include "llvm/Support/Error.h"62#include <functional>63#include <system_error>64 65namespace clang {66namespace clangd {67 68/// A canceller requests cancellation of a task, when called.69/// Calling it again has no effect.70using Canceler = std::function<void()>;71 72/// Defines a new task whose cancellation may be requested.73/// The returned Context defines the scope of the task.74/// When the context is active, isCancelled() is 0 until the Canceler is75/// invoked, and equal to Reason afterwards.76/// Conventionally, Reason may be the LSP error code to return.77std::pair<Context, Canceler> cancelableTask(int Reason = 1);78 79/// If the current context is within a cancelled task, returns the reason.80/// (If the context is within multiple nested tasks, true if any are cancelled).81/// Always zero if there is no active cancelable task.82/// This isn't free (context lookup) - don't call it in a tight loop.83int isCancelled(const Context &Ctx = Context::current());84 85/// Conventional error when no result is returned due to cancellation.86class CancelledError : public llvm::ErrorInfo<CancelledError> {87public:88  static char ID;89  const int Reason;90 91  CancelledError(int Reason) : Reason(Reason) {}92 93  void log(llvm::raw_ostream &OS) const override {94    OS << "Task was cancelled.";95  }96  std::error_code convertToErrorCode() const override {97    return std::make_error_code(std::errc::operation_canceled);98  }99};100 101} // namespace clangd102} // namespace clang103 104#endif105