Symbian platform (C++)
SDK native APIs, runtime and tooling
Loading...
Searching...
No Matches
future.h
Go to the documentation of this file.
1// Copyright 2026 The A11 Authors.
2// Licensed under the Apache License, Version 2.0 (the "License");
3// http://www.apache.org/licenses/LICENSE-2.0
4//
5// Shared stackless adaptation of A11 cpp/a11/concurrency/future.h at
6// fcccb8cb6e1e67d7ba0822ac14cece9ee4c7091b. This first stackless profile
7// keeps A11's shared completion, inline OnReady/Then, cancellation request,
8// and abandoned-promise semantics. Guest event threads reject an unresolved
9// Await; a host with the Boost primitive backend can park its current fiber.
10
11#ifndef SYMBIAN_CONCURRENCY_FUTURE_H_
12#define SYMBIAN_CONCURRENCY_FUTURE_H_
13
14#include <chrono>
15#include <functional>
16#include <memory>
17#include <optional>
18#include <type_traits>
19#include <utility>
20#include <vector>
21
22#include "absl/status/status.h"
23#include "absl/status/statusor.h"
24#include "absl/time/time.h"
25#include "thread/boost_primitives.h"
26
27namespace symbian::concurrency {
28
29#if defined(__SYMBIAN32__)
30class EventExecutor;
31#endif
32
33struct Unit {
34 friend bool operator==(Unit, Unit) = default;
35};
36
37template <typename T>
38class Future;
39
40namespace internal {
41template <typename T>
42struct FutureState {
44 thread::CondVar ready;
45 std::optional<absl::StatusOr<T>> result;
46 std::function<void()> cancel;
47 std::vector<std::function<void(const absl::StatusOr<T>&)>> callbacks;
48};
49} // namespace internal
50
51template <typename T>
52class Promise {
53 public:
54 Promise() : state_(std::make_shared<internal::FutureState<T>>()) {}
55
56 Promise(const Promise&) = delete;
57 Promise& operator=(const Promise&) = delete;
59
61 if (this != &other) {
62 Abandon();
63 state_ = std::move(other.state_);
64 }
65 return *this;
66 }
67
68 ~Promise() { Abandon(); }
69
70 Future<T> future() const { return Future<T>(state_); }
71
72 bool SetCancellationCallback(std::function<void()> cancel) {
73 if (!state_) {
74 return false;
75 }
76 thread::MutexLock lock(&state_->mu);
77 if (state_->result) {
78 return false;
79 }
80 state_->cancel = std::move(cancel);
81 return true;
82 }
83
85 return SetResult(absl::StatusOr<T>(std::move(value)));
86 }
87
88 bool SetError(absl::Status error) {
89 if (error.ok()) {
90 return false;
91 }
92 return SetResult(absl::StatusOr<T>(std::move(error)));
93 }
94
95 bool SetResult(absl::StatusOr<T> result) {
96 auto state = state_;
97 if (!state) {
98 return false;
99 }
100 std::vector<std::function<void(const absl::StatusOr<T>&)>> callbacks;
101 {
102 thread::MutexLock lock(&state->mu);
103 if (state->result) {
104 return false;
105 }
106 state->result.emplace(std::move(result));
107 state->cancel = {};
108 callbacks.swap(state->callbacks);
109 }
110 state->ready.SignalAll();
111 // A11 permits inline completion. No callback runs under the state lock.
112 for (auto& callback : callbacks) {
113 callback(*state->result);
114 }
115 return true;
116 }
117
118 private:
119 void Abandon() {
120 if (state_) {
121 SetError(absl::CancelledError("Promise was abandoned"));
122 state_.reset();
123 }
124 }
125
126 std::shared_ptr<internal::FutureState<T>> state_;
127};
128
129template <typename T>
130class Future {
131 public:
132 Future() = default;
133
134 bool valid() const { return state_ != nullptr; }
135
136 bool IsReady() const {
137 if (!state_) {
138 return false;
139 }
140 thread::MutexLock lock(&state_->mu);
141 return state_->result.has_value();
142 }
143
144 // Cancellation requests producer action; the result is published by the
145 // producer. A ready result makes cancellation an idempotent success.
146 bool Cancel() const {
147 if (!state_) {
148 return false;
149 }
150 std::function<void()> cancel;
151 {
152 thread::MutexLock lock(&state_->mu);
153 if (state_->result) {
154 return true;
155 }
156 cancel = state_->cancel;
157 }
158 if (!cancel) {
159 return false;
160 }
161 cancel();
162 return true;
163 }
164
165 // Stackless operations never block a guest event thread.
166 std::optional<absl::StatusOr<T>> ResultIfReady() const {
167 if (!state_) {
168 return std::nullopt;
169 }
170 thread::MutexLock lock(&state_->mu);
171 return state_->result;
172 }
173
174 // A host or guest fiber parks here. A guest event thread outside a fiber
175 // fails clearly on an unresolved wait. The public deadline remains
176 // absl::Time; its remaining duration is measured by the steady clock.
177 absl::StatusOr<T> Await(absl::Time deadline = absl::InfiniteFuture()) const {
178 if (!state_) {
179 return absl::FailedPreconditionError("Future is invalid");
180 }
181 if (auto ready = ResultIfReady()) {
182 return *ready;
183 }
184 if (!thread::CanParkAwait()) {
185 return absl::FailedPreconditionError(
186 "Await requires a supported fiber context");
187 } else {
188 const bool infinite = deadline == absl::InfiniteFuture();
189 absl::Duration remaining =
190 infinite ? absl::InfiniteDuration() : deadline - absl::Now();
191 thread::MutexLock lock(&state_->mu);
192 while (!state_->result) {
193 if (!infinite && remaining <= absl::ZeroDuration()) {
194 return absl::DeadlineExceededError("Future deadline expired");
195 }
196 if (infinite) {
197 state_->ready.Wait(&state_->mu);
198 continue;
199 }
200 const auto start = std::chrono::steady_clock::now();
201 const bool timed_out =
202 state_->ready.WaitWithTimeout(&state_->mu, remaining);
203 const auto elapsed =
204 std::chrono::duration_cast<std::chrono::nanoseconds>(
205 std::chrono::steady_clock::now() - start);
206 remaining -= absl::Nanoseconds(elapsed.count());
207 if (timed_out && !state_->result) {
208 return absl::DeadlineExceededError("Future deadline expired");
209 }
210 }
211 return *state_->result;
212 }
213 }
214
215 void OnReady(std::function<void(const absl::StatusOr<T>&)> callback) const {
216 if (!callback) {
217 return;
218 }
219 auto state = state_;
220 if (!state) {
221 const absl::StatusOr<T> invalid =
222 absl::FailedPreconditionError("Future is not valid");
223 callback(invalid);
224 return;
225 }
226 const absl::StatusOr<T>* ready = nullptr;
227 {
228 thread::MutexLock lock(&state->mu);
229 if (!state->result) {
230 state->callbacks.push_back(std::move(callback));
231 return;
232 }
233 ready = &*state->result;
234 }
235 callback(*ready);
236 }
237
238 // Guest-only opt-in placement. Include event_executor.h at the call site.
239 // Then() and OnReady() keep their inline A11 behavior.
240#if defined(__SYMBIAN32__)
241 template <typename Fn>
243 typename std::invoke_result_t<Fn, const absl::StatusOr<T>&>::value_type>;
244#endif
245
246 private:
247 explicit Future(std::shared_ptr<internal::FutureState<T>> state)
248 : state_(std::move(state)) {}
249
250 std::shared_ptr<internal::FutureState<T>> state_;
251 friend class Promise<T>;
252};
253
254template <typename T>
256 Promise<T> promise;
257 Future<T> future = promise.future();
258 promise.SetValue(std::move(value));
259 return future;
260}
261
262template <typename T>
263Future<T> FailedFuture(absl::Status error) {
264 Promise<T> promise;
265 Future<T> future = promise.future();
266 promise.SetError(error);
267 return future;
268}
269
271
272inline Task ReadyTask() {
273 return ReadyFuture(Unit{});
274}
275
276inline Task FailedTask(absl::Status error) {
277 return FailedFuture<Unit>(error);
278}
279
280template <typename T, typename Fn>
281auto Then(const Future<T>& future, Fn transform) -> Future<
282 typename std::invoke_result_t<Fn, const absl::StatusOr<T>&>::value_type> {
283 using U =
284 typename std::invoke_result_t<Fn, const absl::StatusOr<T>&>::value_type;
285 if (auto ready = future.ResultIfReady()) {
286 Promise<U> promise;
287 Future<U> continued = promise.future();
288 promise.SetResult(transform(*ready));
289 return continued;
290 }
291 auto promise = std::make_shared<Promise<U>>();
292 Future<U> continued = promise->future();
293 promise->SetCancellationCallback([future] { future.Cancel(); });
294 future.OnReady(
295 [promise = std::move(promise), transform = std::move(transform)](
296 const absl::StatusOr<T>& result) mutable {
297 promise->SetResult(transform(result));
298 });
299 return continued;
300}
301
302} // namespace symbian::concurrency
303
304#endif // SYMBIAN_CONCURRENCY_FUTURE_H_
const std::function< absl::Status()> & start
Definition active_service.cc:12
Definition bounded_channel.h:38
Definition event_executor.h:27
Definition future.h:130
bool IsReady() const
Definition future.h:136
bool Cancel() const
Definition future.h:146
std::optional< absl::StatusOr< T > > ResultIfReady() const
Definition future.h:166
absl::StatusOr< T > Await(absl::Time deadline=absl::InfiniteFuture()) const
Definition future.h:177
bool valid() const
Definition future.h:134
void OnReady(std::function< void(const absl::StatusOr< T > &)> callback) const
Definition future.h:215
Definition future.h:52
Future< T > future() const
Definition future.h:70
Promise()
Definition future.h:54
bool SetError(absl::Status error)
Definition future.h:88
Promise(const Promise &)=delete
bool SetCancellationCallback(std::function< void()> cancel)
Definition future.h:72
Promise & operator=(const Promise &)=delete
Promise(Promise &&) noexcept=default
bool SetValue(T value)
Definition future.h:84
~Promise()
Definition future.h:68
bool SetResult(absl::StatusOr< T > result)
Definition future.h:95
Definition boost_primitives.h:110
Definition boost_primitives.h:95
Definition boost_primitives.h:34
Definition exception_count.cc:8
Definition bounded_channel.h:32
Task FailedTask(absl::Status error)
Definition future.h:276
Future< T > ReadyFuture(T value)
Definition future.h:255
Future< T > FailedFuture(absl::Status error)
Definition future.h:263
Task ReadyTask()
Definition future.h:272
auto Then(const Future< T > &future, Fn transform) -> Future< typename std::invoke_result_t< Fn, const absl::StatusOr< T > & >::value_type >
Definition future.h:281
bool CanParkAwait() noexcept
Definition boost_primitives.h:30
Definition future.h:33
friend bool operator==(Unit, Unit)=default
libusb_context * value
Definition usb.cc:35