[llvm] [orc-rt] Add CooperativeFuture/Promise. (PR #172428)
Jameson Nash via llvm-commits
llvm-commits at lists.llvm.org
Wed Dec 17 07:08:47 PST 2025
================
@@ -0,0 +1,270 @@
+//===--------------------- CooperativeFuture.h ------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines a "cooperative" promise/future implementation.
+//
+// CooperativeFuture::get() runs tasks from a CooperativeFutureWorkQueue until
+// the corresponding result is ready. This allows clients to block on a *result*
+// without blocking the underlying thread (which will continue to perform work).
+//
+// Cooperative futures are intended for ORC runtime API clients who want to use
+// blocking patterns with a single thread or fixed-sized thread pool.
+//
+// The CooperativeFuture and CooperativePromise APIs are deliberately similar to
+// std::future and std::promise, but there are some differences. In particular:
+// 1. Constructing a CooperativePromise requires a
+// CooperativeFutureTaskRunner.
+// 2. When building with exceptions turned off, CooperativePromise and
+// CooperativeFuture can only be instantiated with types constructible
+// from Error. This is because CooperativeFutureTaskRunner may return an
+// Error, and CooperativeFuture::get needs a way to return in this case.
+// When exceptions are enabled, CooperativeFuture::get will throw any
+// Error received as an Exception (making its behavior more like
+// std::future).
+//
+// Blocking patterns should never be used inside the ORC runtime itself.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_COOPERATIVEFUTURE_H
+#define ORC_RT_COOPERATIVEFUTURE_H
+
+#include "orc-rt/BitmaskEnum.h"
+#include "orc-rt/Error.h"
+
+#include <atomic>
+#include <cassert>
+#include <utility>
+
+namespace orc_rt {
+
+/// CooperativeFutureTaskRunner provides an interface for CooperativeFuture to
+/// run tasks.
+class CooperativeFutureTaskRunner {
+public:
+ CooperativeFutureTaskRunner() = default;
+ CooperativeFutureTaskRunner(const CooperativeFutureTaskRunner &) = delete;
+ CooperativeFutureTaskRunner(CooperativeFutureTaskRunner &&) = delete;
+ CooperativeFutureTaskRunner &
+ operator=(const CooperativeFutureTaskRunner &) = delete;
+ CooperativeFutureTaskRunner &
+ operator=(CooperativeFutureTaskRunner &&) = delete;
+
+ virtual ~CooperativeFutureTaskRunner();
+
+ // Run the next available task. Should return Error::success if the task was
+ // run, or an Error if no further tasks can be run (since in this case the
+ // future that requested the work will be left without a value, and we want
+ // to report why).
----------------
vtjnash wrote:
FWIW, the main counterexample I ran into when testing this theory against the existing code was `SimpleRemoteEPC` messages. Those are triggered (by set_value) from IO on a secondary thread from the one that they originally got created on (to emulate async IO simplistically). We could import an entire real async IO library here (like libuv) to support the use of purely single-threaded environments, or even just add the the async queue / notify primitive so that the IO reactor thread can integrate properly with the main thread, but that all felt out of scope. My implementation instead allowed for even single-threaded environments to cooperate with threads that aren't cooperative (either by using `run_elsewhere` when scheduling or `run_to_complete` before blocking)
https://github.com/llvm/llvm-project/pull/172428
More information about the llvm-commits
mailing list