libasync_scope_dispatcher/
scope_dispatcher.rs1use core::ptr::{NonNull, null};
6use core::sync::atomic::{self, AtomicBool};
7use fuchsia_async::{EHandle, MonotonicInstant, Scope, Timer, WakeupTime};
8use fuchsia_sync::Mutex;
9use futures::task::AtomicWaker;
10use libasync_dispatcher::{AsAsyncDispatcherRef, AsyncDispatcherRef};
11use libasync_sys::async_dispatcher_t;
12use pin_project_lite::pin_project;
13use std::pin::Pin;
14use std::sync::Arc;
15use std::task::{Context, Poll};
16use zx::Status;
17
18use crate::ops;
19use crate::ops::v1::{PendingWaits, Task, TaskQueue};
20
21#[derive(Debug)]
23#[repr(C)]
24pub struct ScopeDispatcher {
25 dispatcher: async_dispatcher_t,
27 task_queue: Mutex<TaskQueue>,
28 pub(crate) pending_waits: Mutex<PendingWaits>,
29 shutting_down: AtomicBool,
30 shutdown_complete_waker: AtomicWaker,
31 service_waker: AtomicWaker,
32 shutdown_guard: AtomicBool,
33 executor: EHandle,
34 scope: Scope,
35}
36
37unsafe impl Send for ScopeDispatcher {}
39unsafe impl Sync for ScopeDispatcher {}
41
42impl ScopeDispatcher {
43 pub fn new() -> Arc<Self> {
49 Self::new_on_executor(EHandle::local())
50 }
51
52 pub fn new_on_executor(executor: EHandle) -> Arc<Self> {
54 let scope = executor.global_scope().new_child();
55 let scope_handle = scope.as_handle().clone();
56 let dispatcher = async_dispatcher_t { ops: &ops::ASYNC_OPS };
57 let task_queue = Mutex::new(TaskQueue::default());
58 let pending_waits = Mutex::new(PendingWaits::default());
59 let shutting_down = AtomicBool::new(false);
60 let service_waker = AtomicWaker::new();
61 let shutdown_complete_waker = AtomicWaker::new();
62 let shutdown_guard = AtomicBool::new(false);
63 let this = Arc::new(Self {
64 dispatcher,
65 task_queue,
66 pending_waits,
67 shutting_down,
68 shutdown_complete_waker,
69 service_waker,
70 shutdown_guard,
71 executor,
72 scope,
73 });
74
75 scope_handle.spawn(this.clone().service_loop());
76
77 this
78 }
79
80 pub fn as_ptr(&self) -> *const async_dispatcher_t {
82 (self as *const Self).cast()
83 }
84
85 pub fn global_handle(&self) -> &EHandle {
87 &self.executor
88 }
89
90 pub fn as_scope(&self) -> &Scope {
92 &self.scope
93 }
94
95 pub fn is_shutting_down(&self) -> bool {
97 self.shutting_down.load(atomic::Ordering::Acquire)
98 }
99
100 pub fn shutdown(&self) -> ShutdownCompletionFuture<'_> {
103 self.shutting_down.store(true, atomic::Ordering::Release);
105 self.service_waker.wake();
106 ShutdownCompletionFuture(self)
107 }
108
109 pub(crate) unsafe fn from_ptr<'a>(dispatcher_ptr: *mut async_dispatcher_t) -> &'a Self {
116 let this = dispatcher_ptr.cast::<ScopeDispatcher>();
117 unsafe { this.as_ref() }.expect("null dispatcher pointer")
120 }
121
122 pub(crate) unsafe fn arc_from_ptr(dispatcher_ptr: *mut async_dispatcher_t) -> Arc<Self> {
129 let this = dispatcher_ptr.cast::<ScopeDispatcher>();
130 unsafe {
133 Arc::increment_strong_count(this);
134 Arc::from_raw(this)
135 }
136 }
137
138 pub(crate) fn post_task(&self, task: Task) -> Result<(), Status> {
140 if self.is_shutting_down() {
142 return Err(Status::BAD_STATE);
143 }
144 self.task_queue.lock().queue_task(task);
145 self.service_waker.wake();
146 Ok(())
147 }
148
149 pub(crate) fn cancel_task(&self, task: Task) -> Result<(), Status> {
151 if self.task_queue.lock().take_pending_task(&task).is_some() {
153 self.service_waker.wake();
154 Ok(())
155 } else {
156 Err(Status::NOT_FOUND)
157 }
158 }
159
160 async fn service_loop(self: Arc<Self>) {
161 while let Some(next_task) = NextTaskFuture::new(&self).await {
162 next_task.run(self.clone(), Ok(()));
163 }
164 for next_wait in self.pending_waits.lock().get_all_waits() {
171 next_wait.run(self.clone(), null(), Err(Status::CANCELED));
172 }
173 while let Some(next_task) = self.task_queue.lock().next_task(MonotonicInstant::INFINITE) {
174 next_task.run(self.clone(), Err(Status::CANCELED));
175 }
176 self.shutdown_guard.store(true, atomic::Ordering::Release);
177 self.shutdown_complete_waker.wake();
178 }
179}
180
181impl AsAsyncDispatcherRef for ScopeDispatcher {
182 fn as_async_dispatcher_ref(&self) -> AsyncDispatcherRef<'_> {
183 let ptr = unsafe { NonNull::new_unchecked(self.as_ptr().cast_mut()) };
186 unsafe { AsyncDispatcherRef::from_raw(ptr) }
189 }
190}
191
192impl Drop for ScopeDispatcher {
193 fn drop(&mut self) {
194 assert!(
195 self.shutdown_guard.load(atomic::Ordering::Acquire),
196 "Dispatcher not properly shut down before dropping. Call ScopeDispatcher::shutdown()."
197 );
198 }
199}
200
201#[must_use = "a future that is never awaited on will never run"]
203pub struct ShutdownCompletionFuture<'a>(&'a ScopeDispatcher);
204
205impl<'a> Future for ShutdownCompletionFuture<'a> {
206 type Output = ();
207
208 fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
209 self.0.shutdown_complete_waker.register(ctx.waker());
210 if self.0.shutdown_guard.load(atomic::Ordering::Acquire) {
211 Poll::Ready(())
212 } else {
213 Poll::Pending
214 }
215 }
216}
217
218pin_project! {
219 #[must_use = "a future that is never awaited on will never run"]
220 struct NextTaskFuture<'a> {
221 dispatcher: &'a Arc<ScopeDispatcher>,
222 #[pin]
223 next_timeout: Timer,
224 }
225}
226
227impl<'a> NextTaskFuture<'a> {
228 fn new(dispatcher: &'a Arc<ScopeDispatcher>) -> Self {
229 let next_timeout = MonotonicInstant::INFINITE.into_timer();
230 Self { dispatcher, next_timeout }
231 }
232}
233
234impl<'a> Future for NextTaskFuture<'a> {
235 type Output = Option<Task>;
236
237 fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
238 let mut task_queue = self.dispatcher.task_queue.lock();
239 if self.dispatcher.shutting_down.load(atomic::Ordering::Acquire) {
242 return Poll::Ready(None);
243 }
244 let now = self.dispatcher.executor.now();
245 if let Some(task) = task_queue.next_task(now) {
246 Poll::Ready(Some(task))
247 } else {
248 let next_deadline = if let Some(task) = task_queue.peek_next_task() {
249 task.deadline().unwrap_or(MonotonicInstant::INFINITE)
250 } else {
251 MonotonicInstant::INFINITE
252 };
253 self.dispatcher.service_waker.register(ctx.waker());
254 let mut this = self.project();
255 this.next_timeout.as_mut().reset(next_deadline);
256 let _: Poll<()> = this.next_timeout.poll(ctx);
259 Poll::Pending
260 }
261 }
262}