Symbian platform (C++)
SDK native APIs, runtime and tooling
Loading...
Searching...
No Matches
boost_primitives.h
Go to the documentation of this file.
1// Copyright 2026 The Action Engine Authors.
2// Licensed under the Apache License, Version 2.0 (the "License");
3// http://www.apache.org/licenses/LICENSE-2.0
4//
5// Guest ARM-fiber adaptation of cpp/thread/thread/boost_primitives.h at
6// fcccb8cb6e1e67d7ba0822ac14cece9ee4c7091b. Only the creating event
7// thread pumps guest fibers. OS-thread callers retain normal blocking locks.
8
9#ifndef THREAD_BOOST_PRIMITIVES_H_
10#define THREAD_BOOST_PRIMITIVES_H_
11
12#include <algorithm>
13#include <atomic>
14#include <chrono>
15#include <condition_variable>
16#include <cstdint>
17#include <deque>
18#include <mutex>
19#include <thread>
20
21#include "absl/base/thread_annotations.h"
22#include "absl/time/clock.h"
23#include "absl/time/time.h"
24#include "thread/fiber.h"
25
26namespace thread {
27
28inline constexpr bool kCanParkAwait = true;
29
30inline bool CanParkAwait() noexcept {
31 return Fiber::Current() != nullptr;
32}
33
34class ABSL_LOCKABLE Mutex {
35 public:
36 Mutex() = default;
37 Mutex(const Mutex&) = delete;
38 Mutex& operator=(const Mutex&) = delete;
39
40 void Lock() noexcept ABSL_EXCLUSIVE_LOCK_FUNCTION() {
41 Fiber* fiber = Fiber::Current();
42 if (fiber == nullptr) {
43 mu_.lock();
44 return;
45 }
46 while (!mu_.try_lock()) {
47 fiber->scheduler_.PreparePark(
48 fiber, std::chrono::steady_clock::time_point::max());
49 {
50 std::lock_guard guard(waiters_mu_);
51 waiters_.push_back(fiber);
52 // Unlock may have preceded registration. Retry under the waiter
53 // guard so the fiber cannot miss the only wakeup.
54 if (mu_.try_lock()) {
55 waiters_.pop_back();
56 fiber->scheduler_.CancelPark(fiber);
57 return;
58 }
59 }
60 fiber->scheduler_.Suspend(fiber);
61 std::lock_guard guard(waiters_mu_);
62 auto it = std::find(waiters_.begin(), waiters_.end(), fiber);
63 if (it != waiters_.end()) {
64 waiters_.erase(it);
65 }
66 }
67 }
68
69 void Unlock() noexcept ABSL_UNLOCK_FUNCTION() {
70 Fiber* fiber = nullptr;
71 {
72 std::lock_guard guard(waiters_mu_);
73 mu_.unlock();
74 if (!waiters_.empty()) {
75 fiber = waiters_.front();
76 waiters_.pop_front();
77 }
78 }
79 if (fiber != nullptr) {
80 fiber->scheduler_.Wake(fiber);
81 }
82 }
83
84 void lock() noexcept ABSL_EXCLUSIVE_LOCK_FUNCTION() { Lock(); }
85
86 void unlock() noexcept ABSL_UNLOCK_FUNCTION() { Unlock(); }
87
88 private:
89 friend class CondVar;
90 std::mutex mu_;
91 std::mutex waiters_mu_;
92 std::deque<Fiber*> waiters_;
93};
94
95class ABSL_SCOPED_LOCKABLE MutexLock {
96 public:
97 explicit MutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) {
98 mu_->Lock();
99 }
100
101 MutexLock(const MutexLock&) = delete;
102 MutexLock& operator=(const MutexLock&) = delete;
103
104 ~MutexLock() ABSL_UNLOCK_FUNCTION() { mu_->Unlock(); }
105
106 private:
107 Mutex* mu_;
108};
109
110class CondVar {
111 public:
112 CondVar() = default;
113 CondVar(const CondVar&) = delete;
114 CondVar& operator=(const CondVar&) = delete;
115
116 void Wait(Mutex* mu) noexcept {
117 if (Fiber::Current() != nullptr) {
118 WaitWithTimeout(mu, absl::InfiniteDuration());
119 return;
120 }
121 std::unique_lock<std::mutex> lock(mu->mu_, std::adopt_lock);
122 cv_.wait(lock);
123 lock.release();
124 }
125
126 bool WaitWithDeadline(Mutex* mu, absl::Time deadline) noexcept {
127 if (deadline == absl::InfiniteFuture()) {
128 Wait(mu);
129 return false;
130 }
131 return WaitWithTimeout(mu, deadline - absl::Now());
132 }
133
134 bool WaitWithTimeout(Mutex* mu, absl::Duration remaining) noexcept {
135 if (Fiber* fiber = Fiber::Current()) {
136 if (remaining <= absl::ZeroDuration()) {
137 return true;
138 }
139 const bool infinite = remaining == absl::InfiniteDuration();
140 while (infinite || remaining > absl::ZeroDuration()) {
141 const auto start = std::chrono::steady_clock::now();
142 auto deadline = std::chrono::steady_clock::time_point::max();
143 if (!infinite) {
144 const absl::Duration safe = remaining < absl::Hours(24 * 365)
145 ? remaining
146 : absl::Hours(24 * 365);
147 deadline =
148 start + std::chrono::nanoseconds(absl::ToInt64Nanoseconds(safe));
149 }
150 Waiter waiter{fiber, false};
151 {
152 std::lock_guard guard(waiters_mu_);
153 fiber->scheduler_.PreparePark(fiber, deadline);
154 waiters_.push_back(&waiter);
155 }
156 mu->Unlock();
157 fiber->scheduler_.Suspend(fiber);
158 bool signalled = false;
159 {
160 std::lock_guard guard(waiters_mu_);
161 auto it = std::find(waiters_.begin(), waiters_.end(), &waiter);
162 if (it != waiters_.end()) {
163 waiters_.erase(it);
164 }
165 signalled = waiter.signalled;
166 }
167 mu->Lock();
168 if (signalled) {
169 return false;
170 }
171 if (!infinite) {
172 const auto elapsed =
173 std::chrono::duration_cast<std::chrono::nanoseconds>(
174 std::chrono::steady_clock::now() - start);
175 remaining -= absl::Nanoseconds(elapsed.count());
176 }
177 }
178 return true;
179 }
180 if (remaining == absl::InfiniteDuration()) {
181 Wait(mu);
182 return false;
183 }
184 if (remaining <= absl::ZeroDuration()) {
185 return true;
186 }
187 const std::uint32_t observed = generation_.load(std::memory_order_acquire);
188 std::unique_lock<std::mutex> lock(mu->mu_, std::adopt_lock);
189 bool signalled = false;
190 while (remaining > absl::ZeroDuration()) {
191 // Convert the accepted wall deadline once. Short steady-clock slices
192 // avoid overflowing libc++/pthread timer ranges on distant deadlines.
193 const absl::Duration slice =
194 remaining < absl::Hours(1) ? remaining : absl::Hours(1);
195 const auto start = std::chrono::steady_clock::now();
196 cv_.wait_for(lock,
197 std::chrono::nanoseconds(absl::ToInt64Nanoseconds(slice)));
198 if (generation_.load(std::memory_order_acquire) != observed) {
199 signalled = true;
200 break;
201 }
202 const auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(
203 std::chrono::steady_clock::now() - start);
204 remaining -= absl::Nanoseconds(elapsed.count());
205 }
206 lock.release();
207 return !signalled;
208 }
209
210 void Signal() noexcept {
211 generation_.fetch_add(1, std::memory_order_release);
212 Scheduler* scheduler = nullptr;
213 bool notify = false;
214 {
215 std::lock_guard guard(waiters_mu_);
216 if (!waiters_.empty()) {
217 Waiter* waiter = waiters_.front();
218 waiters_.pop_front();
219 waiter->signalled = true;
220 scheduler = &waiter->fiber->scheduler_;
221 notify = scheduler->WakeWithoutNotify(waiter->fiber);
222 }
223 }
224 if (notify) {
225 scheduler->NotifyReady();
226 }
227 cv_.notify_one();
228 }
229
230 void SignalAll() noexcept {
231 generation_.fetch_add(1, std::memory_order_release);
232 std::deque<Scheduler*> schedulers;
233 {
234 std::lock_guard guard(waiters_mu_);
235 while (!waiters_.empty()) {
236 Waiter* waiter = waiters_.front();
237 waiters_.pop_front();
238 waiter->signalled = true;
239 Scheduler* scheduler = &waiter->fiber->scheduler_;
240 if (scheduler->WakeWithoutNotify(waiter->fiber)) {
241 schedulers.push_back(scheduler);
242 }
243 }
244 }
245 for (Scheduler* scheduler : schedulers) {
246 scheduler->NotifyReady();
247 }
248 cv_.notify_all();
249 }
250
251 private:
252 struct Waiter {
253 Fiber* fiber;
254 bool signalled;
255 };
256
257 std::mutex waiters_mu_;
258 std::deque<Waiter*> waiters_;
259 std::atomic<std::uint32_t> generation_{0};
260 std::condition_variable cv_;
261};
262
263inline void SleepFor(absl::Duration duration) {
264 if (Fiber::Current() != nullptr) {
265 Fiber::SleepFor(duration);
266 return;
267 }
268 if (duration <= absl::ZeroDuration()) {
269 std::this_thread::yield();
270 return;
271 }
272 while (duration > absl::ZeroDuration()) {
273 const absl::Duration slice =
274 duration < absl::Hours(1) ? duration : absl::Hours(1);
275 std::this_thread::sleep_for(
276 std::chrono::nanoseconds(absl::ToInt64Nanoseconds(slice)));
277 duration -= slice;
278 }
279}
280
281} // namespace thread
282
283#endif // THREAD_BOOST_PRIMITIVES_H_
const std::function< absl::Status()> & start
Definition active_service.cc:12
Definition boost_primitives.h:110
bool WaitWithTimeout(Mutex *mu, absl::Duration remaining) noexcept
Definition boost_primitives.h:134
void Signal() noexcept
Definition boost_primitives.h:210
CondVar()=default
Definition boost_primitives.cc:55
CondVar(const CondVar &)=delete
void Wait(Mutex *mu) noexcept
Definition boost_primitives.h:116
void SignalAll() noexcept
Definition boost_primitives.h:230
bool WaitWithDeadline(Mutex *mu, absl::Time deadline) noexcept
Definition boost_primitives.h:126
CondVar & operator=(const CondVar &)=delete
Definition fiber.h:82
static Fiber * Current() noexcept
Definition fiber.cc:270
static void SleepFor(absl::Duration duration)
Definition fiber.cc:311
Definition boost_primitives.h:95
~MutexLock() ABSL_UNLOCK_FUNCTION()
Definition boost_primitives.h:104
MutexLock(Mutex *mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
Definition boost_primitives.h:97
MutexLock(const MutexLock &)=delete
MutexLock & operator=(const MutexLock &)=delete
Definition boost_primitives.h:34
void lock() noexcept ABSL_EXCLUSIVE_LOCK_FUNCTION()
Definition boost_primitives.h:84
void Lock() noexcept ABSL_EXCLUSIVE_LOCK_FUNCTION()
Definition boost_primitives.h:40
Mutex & operator=(const Mutex &)=delete
void Unlock() noexcept ABSL_UNLOCK_FUNCTION()
Definition boost_primitives.h:69
void unlock() noexcept ABSL_UNLOCK_FUNCTION()
Definition boost_primitives.h:86
Mutex(const Mutex &)=delete
Definition fiber.h:46
Definition channel.h:29
void SleepFor(absl::Duration duration)
Definition boost_primitives.h:263
constexpr bool kCanParkAwait
Definition boost_primitives.h:28
bool CanParkAwait() noexcept
Definition boost_primitives.h:30