1use std::any::{Any, TypeId};
2use std::fmt;
3use std::future::Future;
4use std::marker::PhantomData;
5use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
6use std::pin::Pin;
7use std::rc::Rc;
8use std::sync::atomic::{AtomicBool, AtomicI32, AtomicU64, AtomicU8, AtomicUsize, Ordering};
9use std::sync::{Arc, Condvar, Mutex, MutexGuard, PoisonError};
10use std::task::{Context, Poll, Waker};
11use std::time::Duration;
12
13use super::dispatcher::DispatcherLocal;
14use super::dispatcher_priority_queue::NOT_QUEUED;
15use super::{
16 CancellationTokenSource, Dispatcher, DispatcherFrame, DispatcherPriority, DispatcherTimer,
17 FerroSynchronizationContext,
18};
19use crate::reactive::{Disposable, IDisposable};
20
21pub type DispatcherException = Box<dyn Any + Send + 'static>;
24
25pub(crate) type SendCallback = Box<dyn FnOnce() -> Box<dyn Any + Send> + Send>;
27
28pub(crate) type LocalCallback = Box<dyn FnOnce() -> Option<Box<dyn Any>>>;
31
32type EventHandler = Arc<dyn Fn() + Send + Sync>;
33
34#[repr(i32)]
36#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
37pub enum DispatcherOperationStatus {
38 Pending = 0,
39 Aborted = 1,
40 Completed = 2,
41 Executing = 3,
42}
43
44impl DispatcherOperationStatus {
45 fn from_u8(value: u8) -> Self {
46 match value {
47 0 => Self::Pending,
48 1 => Self::Aborted,
49 2 => Self::Completed,
50 _ => Self::Executing,
51 }
52 }
53}
54
55#[derive(Clone, Copy, Debug, PartialEq, Eq)]
57pub struct OperationCanceledError;
58
59impl fmt::Display for OperationCanceledError {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 f.write_str("The dispatcher operation was canceled")
62 }
63}
64
65impl std::error::Error for OperationCanceledError {}
66
67#[derive(Default)]
68struct OperationInner {
69 callback: Option<SendCallback>,
70 result: Option<Box<dyn Any + Send>>,
71 panic: Option<DispatcherException>,
72 wakers: Vec<Waker>,
73 aborted: Vec<(u64, EventHandler)>,
74 completed: Vec<(u64, EventHandler)>,
75 next_handler_id: u64,
76}
77
78static NEXT_OPERATION_ID: AtomicU64 = AtomicU64::new(1);
79
80pub(crate) fn next_operation_id() -> u64 {
83 NEXT_OPERATION_ID.fetch_add(1, Ordering::Relaxed)
84}
85
86#[derive(Clone, Copy, Debug, PartialEq, Eq)]
88pub(crate) enum WaitOutcome {
89 Finished,
91 TimedOut,
93}
94
95pub(crate) struct OperationCore {
98 id: u64,
99 dispatcher: Arc<Dispatcher>,
100 throw_on_ui_thread: bool,
101 is_local: bool,
104 local_storage_used: AtomicBool,
106 status: AtomicU8,
107 priority: AtomicI32,
108 queue_slot: AtomicUsize,
109 inner: Mutex<OperationInner>,
110 finished: Condvar,
111}
112
113impl OperationCore {
114 fn new(
115 dispatcher: &Arc<Dispatcher>,
116 priority: DispatcherPriority,
117 throw_on_ui_thread: bool,
118 callback: Option<SendCallback>,
119 ) -> Arc<Self> {
120 let is_local = callback.is_none();
121 Arc::new(Self {
122 id: next_operation_id(),
123 dispatcher: dispatcher.clone(),
124 throw_on_ui_thread,
125 is_local,
126 local_storage_used: AtomicBool::new(is_local),
127 status: AtomicU8::new(DispatcherOperationStatus::Pending as u8),
128 priority: AtomicI32::new(priority.value()),
129 queue_slot: AtomicUsize::new(NOT_QUEUED),
130 inner: Mutex::new(OperationInner { callback, ..OperationInner::default() }),
131 finished: Condvar::new(),
132 })
133 }
134
135 pub(crate) fn new_send(
137 dispatcher: &Arc<Dispatcher>,
138 priority: DispatcherPriority,
139 throw_on_ui_thread: bool,
140 callback: SendCallback,
141 ) -> Arc<Self> {
142 Self::new(dispatcher, priority, throw_on_ui_thread, Some(callback))
143 }
144
145 pub(crate) fn new_local(
150 dispatcher: &Arc<Dispatcher>,
151 priority: DispatcherPriority,
152 throw_on_ui_thread: bool,
153 callback: LocalCallback,
154 ) -> Arc<Self> {
155 dispatcher.verify_access();
156 let core = Self::new(dispatcher, priority, throw_on_ui_thread, None);
157 match dispatcher.try_local() {
158 Some(local) => {
159 local.jobs.borrow_mut().insert(core.id, callback);
160 }
161 None => core.local_storage_used.store(false, Ordering::Relaxed),
162 }
163 core
164 }
165
166 fn lock(&self) -> MutexGuard<'_, OperationInner> {
167 self.inner.lock().unwrap_or_else(PoisonError::into_inner)
168 }
169
170 #[inline]
171 pub(crate) fn status(&self) -> DispatcherOperationStatus {
172 DispatcherOperationStatus::from_u8(self.status.load(Ordering::SeqCst))
173 }
174
175 #[inline]
176 pub(crate) fn set_status(&self, status: DispatcherOperationStatus) {
177 self.status.store(status as u8, Ordering::SeqCst);
178 }
179
180 #[inline]
181 pub(crate) fn dispatcher(&self) -> &Arc<Dispatcher> {
182 &self.dispatcher
183 }
184
185 #[inline]
186 pub(crate) fn priority(&self) -> DispatcherPriority {
187 let value = self.priority.load(Ordering::SeqCst);
188 if value == DispatcherPriority::INVALID.value() {
189 DispatcherPriority::INVALID
190 } else {
191 DispatcherPriority::from_value(value)
192 }
193 }
194
195 pub(crate) fn set_priority(self: &Arc<Self>, value: DispatcherPriority) {
196 self.priority.store(value.value(), Ordering::SeqCst);
197 self.dispatcher.set_priority(self, value);
198 }
199
200 #[inline]
201 pub(crate) fn queue_slot(&self) -> usize {
202 self.queue_slot.load(Ordering::Relaxed)
203 }
204
205 #[inline]
206 pub(crate) fn set_queue_slot(&self, slot: usize) {
207 self.queue_slot.store(slot, Ordering::Relaxed);
208 }
209
210 #[inline]
211 pub(crate) fn is_queued(&self) -> bool {
212 self.queue_slot() != NOT_QUEUED
213 }
214
215 fn add_handler(self: &Arc<Self>, aborted: bool, handler: EventHandler) -> u64 {
216 let mut inner = self.lock();
217 inner.next_handler_id += 1;
218 let id = inner.next_handler_id;
219 if aborted {
220 inner.aborted.push((id, handler));
221 } else {
222 inner.completed.push((id, handler));
223 }
224 id
225 }
226
227 fn remove_handler(&self, aborted: bool, id: u64) {
228 let removed = {
229 let mut inner = self.lock();
230 let list = if aborted { &mut inner.aborted } else { &mut inner.completed };
231 list.iter().position(|(handler_id, _)| *handler_id == id).map(|index| list.remove(index))
232 };
233 drop(removed);
234 }
235
236 pub(crate) fn add_aborted(self: &Arc<Self>, handler: EventHandler) -> u64 {
237 self.add_handler(true, handler)
238 }
239
240 pub(crate) fn add_completed(self: &Arc<Self>, handler: EventHandler) -> u64 {
241 self.add_handler(false, handler)
242 }
243
244 pub(crate) fn remove_aborted(&self, id: u64) {
245 self.remove_handler(true, id);
246 }
247
248 pub(crate) fn remove_completed(&self, id: u64) {
249 self.remove_handler(false, id);
250 }
251
252 pub(crate) fn abort(self: &Arc<Self>) -> bool {
253 if self.dispatcher.abort(self) {
254 self.call_abort_callbacks();
255 return true;
256 }
257
258 false
259 }
260
261 pub(crate) fn call_abort_callbacks(&self) {
263 debug_assert_eq!(self.status(), DispatcherOperationStatus::Aborted);
264 let (callback, wakers, handlers) = {
265 let mut inner = self.lock();
266 let result = (inner.callback.take(), std::mem::take(&mut inner.wakers), inner.aborted.clone());
267 self.finished.notify_all();
268 result
269 };
270 drop(callback);
272 self.discard_local_storage();
273 for waker in wakers {
274 waker.wake();
275 }
276 for (_, handler) in handlers {
277 handler();
278 }
279 }
280
281 fn call_completed_callbacks(&self) {
282 let (wakers, handlers) = {
283 let mut inner = self.lock();
284 let result = (std::mem::take(&mut inner.wakers), inner.completed.clone());
285 self.finished.notify_all();
286 result
287 };
288 for waker in wakers {
289 waker.wake();
290 }
291 for (_, handler) in handlers {
292 handler();
293 }
294 }
295
296 fn discard_local_storage(&self) {
297 if self.is_local && self.local_storage_used.swap(false, Ordering::SeqCst) {
298 self.dispatcher.discard_local_operation(self.id);
299 }
300 }
301
302 pub(crate) fn execute(&self) {
305 debug_assert_eq!(self.status(), DispatcherOperationStatus::Executing);
306 let local = self.dispatcher.try_local();
307 if let Some(local) = &local {
308 local.executing_depth.set(local.executing_depth.get() + 1);
309 }
310
311 let outcome = catch_unwind(AssertUnwindSafe(|| {
312 let _restore = FerroSynchronizationContext::ensure_with_dispatcher(&self.dispatcher, self.priority());
315 self.invoke_core(local.as_deref())
316 }));
317
318 let completed = catch_unwind(AssertUnwindSafe(|| self.call_completed_callbacks()));
320
321 if let Some(local) = &local {
322 let depth = local.executing_depth.get() - 1;
323 local.executing_depth.set(depth);
324 if depth == 0 {
325 local.seen_exceptions.borrow_mut().clear();
328 }
329 }
330
331 match outcome {
332 Ok(None) => {}
333 Ok(Some(payload)) | Err(payload) => resume_unwind(payload),
334 }
335 if let Err(payload) = completed {
336 resume_unwind(payload);
337 }
338 }
339
340 fn invoke_core(&self, local: Option<&DispatcherLocal>) -> Option<DispatcherException> {
343 enum Value {
344 Send(Box<dyn Any + Send>),
345 Local(Option<Box<dyn Any>>),
346 Missing,
347 }
348
349 let result = if self.is_local {
350 let job = local.and_then(|local| local.jobs.borrow_mut().remove(&self.id));
351 match job {
352 Some(job) => catch_unwind(AssertUnwindSafe(|| Value::Local(job()))),
353 None => Ok(Value::Missing),
354 }
355 } else {
356 let job = self.lock().callback.take();
357 match job {
358 Some(job) => catch_unwind(AssertUnwindSafe(|| Value::Send(job()))),
359 None => Ok(Value::Missing),
360 }
361 };
362
363 match result {
364 Ok(value) => {
365 let mut local_result = None;
366 {
367 let mut inner = self.lock();
368 self.set_status(DispatcherOperationStatus::Completed);
369 match value {
370 Value::Send(value) => inner.result = Some(value),
371 Value::Local(value) => local_result = value,
372 Value::Missing => {}
373 }
374 }
375 match (local_result, local) {
376 (Some(value), Some(local)) => {
377 local.results.borrow_mut().insert(self.id, value);
378 }
379 _ => self.local_storage_used.store(false, Ordering::SeqCst),
380 }
381 None
382 }
383 Err(payload) => {
384 self.local_storage_used.store(false, Ordering::SeqCst);
385 if self.throw_on_ui_thread {
386 self.set_status(DispatcherOperationStatus::Completed);
387 if self.dispatcher.try_catch_when(&payload) {
388 None
389 } else {
390 Some(payload)
391 }
392 } else {
393 let mut inner = self.lock();
394 self.set_status(DispatcherOperationStatus::Completed);
395 inner.panic = Some(payload);
396 None
397 }
398 }
399 }
400 }
401
402 fn block_until_finished(&self) {
405 let mut inner = self.lock();
406 while matches!(self.status(), DispatcherOperationStatus::Pending | DispatcherOperationStatus::Executing) {
407 inner = self.finished.wait(inner).unwrap_or_else(PoisonError::into_inner);
408 }
409 }
410
411 fn is_finished(&self) -> bool {
412 matches!(self.status(), DispatcherOperationStatus::Completed | DispatcherOperationStatus::Aborted)
413 }
414
415 pub(crate) fn wait(self: &Arc<Self>) {
416 self.wait_with_limit(None, false);
417 }
418
419 pub(crate) fn wait_with_limit(self: &Arc<Self>, timeout: Option<Duration>, abort_on_timeout: bool) -> WaitOutcome {
427 let dispatcher = &self.dispatcher;
428 let on_dispatcher_thread = dispatcher.check_access();
429
430 if matches!(self.status(), DispatcherOperationStatus::Pending | DispatcherOperationStatus::Executing)
431 && timeout != Some(Duration::ZERO)
432 && on_dispatcher_thread
433 {
434 if self.status() == DispatcherOperationStatus::Executing {
435 panic!("A thread cannot wait on operations already running on the same thread.");
441 }
442
443 let deadline = timeout.map(|timeout| dispatcher.now().saturating_add(duration_to_ms(timeout)));
444 let cts = CancellationTokenSource::new();
445 let cancel = cts.clone();
446 let finished_handler: EventHandler = Arc::new(move || cancel.cancel());
447 let completed = self.add_completed(finished_handler.clone());
448 let aborted = self.add_aborted(finished_handler);
449
450 let result = catch_unwind(AssertUnwindSafe(|| {
451 while self.status() == DispatcherOperationStatus::Pending {
452 let remaining = match deadline {
453 Some(deadline) => {
454 let remaining = deadline - dispatcher.now();
455 if remaining <= 0 {
456 break;
457 }
458 Some(remaining)
459 }
460 None => None,
461 };
462 if dispatcher.supports_run_loops() {
463 if self.priority() >= DispatcherPriority::MINIMUM_FOREGROUND_PRIORITY {
464 dispatcher.run_jobs_with_cancellation(Some(self.priority()), &cts.token());
465 } else {
466 self.push_operation_frame(remaining);
467 }
468 } else {
469 dispatcher.run_jobs_with_cancellation(
470 Some(DispatcherPriority::MINIMUM_ACTIVE_VALUE),
471 &cts.token(),
472 );
473 }
474 }
475 }));
476
477 self.remove_completed(completed);
479 self.remove_aborted(aborted);
480 if let Err(payload) = result {
481 resume_unwind(payload);
482 }
483 }
484
485 if self.is_finished() {
486 return WaitOutcome::Finished;
487 }
488
489 if on_dispatcher_thread {
490 if abort_on_timeout {
492 self.abort();
493 }
494 return WaitOutcome::TimedOut;
495 }
496
497 match timeout {
498 None => {
499 self.block_until_finished();
500 WaitOutcome::Finished
501 }
502 Some(timeout) => {
503 if self.block_until_finished_or_timeout(timeout) {
504 return WaitOutcome::Finished;
505 }
506 if !abort_on_timeout {
507 return WaitOutcome::TimedOut;
508 }
509 if self.abort() {
510 return WaitOutcome::TimedOut;
511 }
512 self.block_until_finished();
515 WaitOutcome::Finished
516 }
517 }
518 }
519
520 fn block_until_finished_or_timeout(&self, timeout: Duration) -> bool {
523 let inner = self.lock();
524 let (_inner, _result) = self
525 .finished
526 .wait_timeout_while(inner, timeout, |_| {
527 matches!(self.status(), DispatcherOperationStatus::Pending | DispatcherOperationStatus::Executing)
528 })
529 .unwrap_or_else(PoisonError::into_inner);
530 self.is_finished()
531 }
532
533 fn push_operation_frame(self: &Arc<Self>, timeout_ms: Option<i64>) {
539 let frame = DispatcherFrame::with_dispatcher(&self.dispatcher, false);
540
541 let exit_frame = frame.clone();
543 let handler: EventHandler = Arc::new(move || exit_frame.set_continue(false));
544 let aborted = self.add_aborted(handler.clone());
545 let completed = self.add_completed(handler);
546
547 let wait_timer = timeout_ms.filter(|timeout| *timeout > 0).map(|timeout| {
550 let exit_frame = frame.clone();
551 DispatcherTimer::with_callback_and_dispatcher(
552 Duration::from_millis(timeout.min(i32::MAX as i64) as u64),
553 DispatcherPriority::SEND,
554 &self.dispatcher,
555 move |timer| {
556 timer.stop();
557 exit_frame.set_continue(false);
558 },
559 )
560 });
561
562 if self.status() != DispatcherOperationStatus::Pending {
566 frame.set_continue(false);
567 }
568
569 let result = catch_unwind(AssertUnwindSafe(|| self.dispatcher.push_frame(&frame)));
570 if let Some(wait_timer) = wait_timer {
571 wait_timer.stop();
572 }
573 self.remove_aborted(aborted);
574 self.remove_completed(completed);
575 if let Err(payload) = result {
576 resume_unwind(payload);
577 }
578 }
579
580 fn take_outcome<R: 'static>(&self) -> Result<R, OperationCanceledError> {
583 debug_assert!(self.is_finished());
584 if self.status() == DispatcherOperationStatus::Aborted {
585 return Err(OperationCanceledError);
586 }
587
588 let (panic, result) = {
589 let mut inner = self.lock();
590 (inner.panic.take(), inner.result.take())
591 };
592 if let Some(payload) = panic {
593 resume_unwind(payload);
594 }
595
596 let value: Option<Box<dyn Any>> = if !self.is_local {
597 result.map(|value| value as Box<dyn Any>)
598 } else if TypeId::of::<R>() == TypeId::of::<()>() {
599 Some(Box::new(()))
600 } else {
601 if !self.dispatcher.check_access() {
602 panic!("The result of a local dispatcher operation can only be read on the dispatcher thread.");
603 }
604 let value = self.dispatcher.try_local().and_then(|local| local.results.borrow_mut().remove(&self.id));
605 self.local_storage_used.store(false, Ordering::SeqCst);
606 value
607 };
608
609 match value.and_then(|value| value.downcast::<R>().ok()) {
610 Some(value) => Ok(*value),
611 None => panic!("The result of the dispatcher operation has already been taken."),
612 }
613 }
614}
615
616impl Drop for OperationCore {
617 fn drop(&mut self) {
618 self.discard_local_storage();
619 }
620}
621
622pub struct DispatcherOperation<R = ()> {
634 core: Arc<OperationCore>,
635 _result: PhantomData<fn() -> R>,
636}
637
638impl<R> Clone for DispatcherOperation<R> {
639 fn clone(&self) -> Self {
640 Self { core: self.core.clone(), _result: PhantomData }
641 }
642}
643
644impl<R> fmt::Debug for DispatcherOperation<R> {
645 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
646 write!(f, "DispatcherOperation #{} [{}] {:?}", self.core.id, self.core.priority(), self.core.status())
647 }
648}
649
650impl<R: 'static> DispatcherOperation<R> {
651 pub(crate) fn from_core(core: Arc<OperationCore>) -> Self {
652 Self { core, _result: PhantomData }
653 }
654
655 pub(crate) fn core(&self) -> &Arc<OperationCore> {
656 &self.core
657 }
658
659 pub(crate) fn new_send(
661 dispatcher: &Arc<Dispatcher>,
662 priority: DispatcherPriority,
663 callback: impl FnOnce() -> R + Send + 'static,
664 ) -> Self
665 where
666 R: Send,
667 {
668 let callback: SendCallback = Box::new(move || Box::new(callback()) as Box<dyn Any + Send>);
669 Self::from_core(OperationCore::new_send(dispatcher, priority, false, callback))
670 }
671
672 pub(crate) fn new_local(
675 dispatcher: &Arc<Dispatcher>,
676 priority: DispatcherPriority,
677 callback: impl FnOnce() -> R + 'static,
678 ) -> Self {
679 Self::from_core(OperationCore::new_local(dispatcher, priority, false, box_local_callback(callback)))
680 }
681
682 pub fn status(&self) -> DispatcherOperationStatus {
684 self.core.status()
685 }
686
687 pub fn dispatcher(&self) -> &Arc<Dispatcher> {
689 self.core.dispatcher()
690 }
691
692 pub fn priority(&self) -> DispatcherPriority {
693 self.core.priority()
694 }
695
696 pub fn set_priority(&self, value: DispatcherPriority) {
699 self.core.set_priority(value);
700 }
701
702 pub fn aborted(&self, handler: impl Fn() + Send + Sync + 'static) -> Rc<dyn IDisposable> {
706 let id = self.core.add_aborted(Arc::new(handler));
707 let core = self.core.clone();
708 Disposable::create(move || core.remove_aborted(id))
709 }
710
711 pub fn completed(&self, handler: impl Fn() + Send + Sync + 'static) -> Rc<dyn IDisposable> {
715 let id = self.core.add_completed(Arc::new(handler));
716 let core = self.core.clone();
717 Disposable::create(move || core.remove_completed(id))
718 }
719
720 pub fn abort(&self) -> bool {
723 self.core.abort()
724 }
725
726 pub fn wait(&self) -> Result<(), OperationCanceledError> {
738 self.core.wait();
739 if self.core.status() == DispatcherOperationStatus::Aborted {
740 return Err(OperationCanceledError);
741 }
742 let panic = self.core.lock().panic.take();
743 if let Some(payload) = panic {
744 resume_unwind(payload);
745 }
746 Ok(())
747 }
748
749 pub fn wait_with_timeout(&self, timeout: Duration) -> Result<bool, OperationCanceledError> {
765 if self.core.wait_with_limit(Some(timeout), false) == WaitOutcome::TimedOut {
766 return Ok(false);
767 }
768 self.wait().map(|()| true)
769 }
770
771 pub fn result(&self) -> Result<R, OperationCanceledError> {
782 if !self.core.is_finished() {
783 if self.core.dispatcher.check_access() {
784 panic!("Synchronous wait is only supported on non-UI threads");
785 }
786 self.core.block_until_finished();
787 }
788 self.core.take_outcome()
789 }
790
791 pub(crate) fn take_result(&self) -> Result<R, OperationCanceledError> {
793 self.core.take_outcome()
794 }
795}
796
797impl<R: 'static> Future for DispatcherOperation<R> {
798 type Output = Result<R, OperationCanceledError>;
799
800 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
801 {
802 let mut inner = self.core.lock();
803 if !self.core.is_finished() {
806 if !inner.wakers.iter().any(|waker| waker.will_wake(cx.waker())) {
807 inner.wakers.push(cx.waker().clone());
808 }
809 return Poll::Pending;
810 }
811 }
812 Poll::Ready(self.core.take_outcome())
813 }
814}
815
816pub(crate) fn box_local_callback<R: 'static>(callback: impl FnOnce() -> R + 'static) -> LocalCallback {
817 Box::new(move || {
818 let value = callback();
819 if TypeId::of::<R>() == TypeId::of::<()>() {
820 None
821 } else {
822 Some(Box::new(value) as Box<dyn Any>)
823 }
824 })
825}
826
827pub(crate) fn duration_to_ms(duration: Duration) -> i64 {
829 i64::try_from(duration.as_millis()).unwrap_or(i64::MAX)
830}