| use std::any::Any; | 
 | use std::cell::UnsafeCell; | 
 | use std::mem; | 
 | use std::sync::Arc; | 
 |  | 
 | use crossbeam_deque::{Injector, Steal}; | 
 |  | 
 | use crate::latch::Latch; | 
 | use crate::tlv::Tlv; | 
 | use crate::{tlv, unwind}; | 
 |  | 
 | pub(super) enum JobResult<T> { | 
 |     None, | 
 |     Ok(T), | 
 |     Panic(Box<dyn Any + Send>), | 
 | } | 
 |  | 
 | /// A `Job` is used to advertise work for other threads that they may | 
 | /// want to steal. In accordance with time honored tradition, jobs are | 
 | /// arranged in a deque, so that thieves can take from the top of the | 
 | /// deque while the main worker manages the bottom of the deque. This | 
 | /// deque is managed by the `thread_pool` module. | 
 | pub(super) trait Job { | 
 |     /// Unsafe: this may be called from a different thread than the one | 
 |     /// which scheduled the job, so the implementer must ensure the | 
 |     /// appropriate traits are met, whether `Send`, `Sync`, or both. | 
 |     unsafe fn execute(this: *const ()); | 
 | } | 
 |  | 
 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] | 
 | pub(super) struct JobRefId { | 
 |     pointer: usize, | 
 | } | 
 |  | 
 | /// Effectively a Job trait object. Each JobRef **must** be executed | 
 | /// exactly once, or else data may leak. | 
 | /// | 
 | /// Internally, we store the job's data in a `*const ()` pointer. The | 
 | /// true type is something like `*const StackJob<...>`, but we hide | 
 | /// it. We also carry the "execute fn" from the `Job` trait. | 
 | pub(super) struct JobRef { | 
 |     pointer: *const (), | 
 |     execute_fn: unsafe fn(*const ()), | 
 | } | 
 |  | 
 | unsafe impl Send for JobRef {} | 
 | unsafe impl Sync for JobRef {} | 
 |  | 
 | impl JobRef { | 
 |     /// Unsafe: caller asserts that `data` will remain valid until the | 
 |     /// job is executed. | 
 |     pub(super) unsafe fn new<T>(data: *const T) -> JobRef | 
 |     where | 
 |         T: Job, | 
 |     { | 
 |         // erase types: | 
 |         JobRef { pointer: data as *const (), execute_fn: <T as Job>::execute } | 
 |     } | 
 |  | 
 |     #[inline] | 
 |     pub(super) fn id(&self) -> JobRefId { | 
 |         JobRefId { pointer: self.pointer.expose_provenance() } | 
 |     } | 
 |  | 
 |     #[inline] | 
 |     pub(super) unsafe fn execute(self) { | 
 |         unsafe { (self.execute_fn)(self.pointer) } | 
 |     } | 
 | } | 
 |  | 
 | /// A job that will be owned by a stack slot. This means that when it | 
 | /// executes it need not free any heap data, the cleanup occurs when | 
 | /// the stack frame is later popped. The function parameter indicates | 
 | /// `true` if the job was stolen -- executed on a different thread. | 
 | pub(super) struct StackJob<L, F, R> | 
 | where | 
 |     L: Latch + Sync, | 
 |     F: FnOnce(bool) -> R + Send, | 
 |     R: Send, | 
 | { | 
 |     pub(super) latch: L, | 
 |     func: UnsafeCell<Option<F>>, | 
 |     result: UnsafeCell<JobResult<R>>, | 
 |     tlv: Tlv, | 
 | } | 
 |  | 
 | impl<L, F, R> StackJob<L, F, R> | 
 | where | 
 |     L: Latch + Sync, | 
 |     F: FnOnce(bool) -> R + Send, | 
 |     R: Send, | 
 | { | 
 |     pub(super) fn new(tlv: Tlv, func: F, latch: L) -> StackJob<L, F, R> { | 
 |         StackJob { | 
 |             latch, | 
 |             func: UnsafeCell::new(Some(func)), | 
 |             result: UnsafeCell::new(JobResult::None), | 
 |             tlv, | 
 |         } | 
 |     } | 
 |  | 
 |     pub(super) unsafe fn as_job_ref(&self) -> JobRef { | 
 |         unsafe { JobRef::new(self) } | 
 |     } | 
 |  | 
 |     pub(super) unsafe fn run_inline(&self, stolen: bool) { | 
 |         unsafe { | 
 |             let func = (*self.func.get()).take().unwrap(); | 
 |             *(self.result.get()) = match unwind::halt_unwinding(|| func(stolen)) { | 
 |                 Ok(x) => JobResult::Ok(x), | 
 |                 Err(x) => JobResult::Panic(x), | 
 |             }; | 
 |             Latch::set(&self.latch); | 
 |         } | 
 |     } | 
 |  | 
 |     pub(super) unsafe fn into_result(self) -> R { | 
 |         self.result.into_inner().into_return_value() | 
 |     } | 
 | } | 
 |  | 
 | impl<L, F, R> Job for StackJob<L, F, R> | 
 | where | 
 |     L: Latch + Sync, | 
 |     F: FnOnce(bool) -> R + Send, | 
 |     R: Send, | 
 | { | 
 |     unsafe fn execute(this: *const ()) { | 
 |         let this = unsafe { &*(this as *const Self) }; | 
 |         tlv::set(this.tlv); | 
 |         let abort = unwind::AbortIfPanic; | 
 |         let func = unsafe { (*this.func.get()).take().unwrap() }; | 
 |         unsafe { | 
 |             (*this.result.get()) = JobResult::call(func); | 
 |         } | 
 |         unsafe { | 
 |             Latch::set(&this.latch); | 
 |         } | 
 |         mem::forget(abort); | 
 |     } | 
 | } | 
 |  | 
 | /// Represents a job stored in the heap. Used to implement | 
 | /// `scope`. Unlike `StackJob`, when executed, `HeapJob` simply | 
 | /// invokes a closure, which then triggers the appropriate logic to | 
 | /// signal that the job executed. | 
 | /// | 
 | /// (Probably `StackJob` should be refactored in a similar fashion.) | 
 | pub(super) struct HeapJob<BODY> | 
 | where | 
 |     BODY: FnOnce(JobRefId) + Send, | 
 | { | 
 |     job: BODY, | 
 |     tlv: Tlv, | 
 | } | 
 |  | 
 | impl<BODY> HeapJob<BODY> | 
 | where | 
 |     BODY: FnOnce(JobRefId) + Send, | 
 | { | 
 |     pub(super) fn new(tlv: Tlv, job: BODY) -> Box<Self> { | 
 |         Box::new(HeapJob { job, tlv }) | 
 |     } | 
 |  | 
 |     /// Creates a `JobRef` from this job -- note that this hides all | 
 |     /// lifetimes, so it is up to you to ensure that this JobRef | 
 |     /// doesn't outlive any data that it closes over. | 
 |     pub(super) unsafe fn into_job_ref(self: Box<Self>) -> JobRef { | 
 |         unsafe { JobRef::new(Box::into_raw(self)) } | 
 |     } | 
 |  | 
 |     /// Creates a static `JobRef` from this job. | 
 |     pub(super) fn into_static_job_ref(self: Box<Self>) -> JobRef | 
 |     where | 
 |         BODY: 'static, | 
 |     { | 
 |         unsafe { self.into_job_ref() } | 
 |     } | 
 | } | 
 |  | 
 | impl<BODY> Job for HeapJob<BODY> | 
 | where | 
 |     BODY: FnOnce(JobRefId) + Send, | 
 | { | 
 |     unsafe fn execute(this: *const ()) { | 
 |         let pointer = this.expose_provenance(); | 
 |         let this = unsafe { Box::from_raw(this as *mut Self) }; | 
 |         tlv::set(this.tlv); | 
 |         (this.job)(JobRefId { pointer }); | 
 |     } | 
 | } | 
 |  | 
 | /// Represents a job stored in an `Arc` -- like `HeapJob`, but may | 
 | /// be turned into multiple `JobRef`s and called multiple times. | 
 | pub(super) struct ArcJob<BODY> | 
 | where | 
 |     BODY: Fn(JobRefId) + Send + Sync, | 
 | { | 
 |     job: BODY, | 
 | } | 
 |  | 
 | impl<BODY> ArcJob<BODY> | 
 | where | 
 |     BODY: Fn(JobRefId) + Send + Sync, | 
 | { | 
 |     pub(super) fn new(job: BODY) -> Arc<Self> { | 
 |         Arc::new(ArcJob { job }) | 
 |     } | 
 |  | 
 |     /// Creates a `JobRef` from this job -- note that this hides all | 
 |     /// lifetimes, so it is up to you to ensure that this JobRef | 
 |     /// doesn't outlive any data that it closes over. | 
 |     pub(super) unsafe fn as_job_ref(this: &Arc<Self>) -> JobRef { | 
 |         unsafe { JobRef::new(Arc::into_raw(Arc::clone(this))) } | 
 |     } | 
 |  | 
 |     /// Creates a static `JobRef` from this job. | 
 |     pub(super) fn as_static_job_ref(this: &Arc<Self>) -> JobRef | 
 |     where | 
 |         BODY: 'static, | 
 |     { | 
 |         unsafe { Self::as_job_ref(this) } | 
 |     } | 
 | } | 
 |  | 
 | impl<BODY> Job for ArcJob<BODY> | 
 | where | 
 |     BODY: Fn(JobRefId) + Send + Sync, | 
 | { | 
 |     unsafe fn execute(this: *const ()) { | 
 |         let pointer = this.expose_provenance(); | 
 |         let this = unsafe { Arc::from_raw(this as *mut Self) }; | 
 |         (this.job)(JobRefId { pointer }); | 
 |     } | 
 | } | 
 |  | 
 | impl<T> JobResult<T> { | 
 |     fn call(func: impl FnOnce(bool) -> T) -> Self { | 
 |         match unwind::halt_unwinding(|| func(true)) { | 
 |             Ok(x) => JobResult::Ok(x), | 
 |             Err(x) => JobResult::Panic(x), | 
 |         } | 
 |     } | 
 |  | 
 |     /// Convert the `JobResult` for a job that has finished (and hence | 
 |     /// its JobResult is populated) into its return value. | 
 |     /// | 
 |     /// NB. This will panic if the job panicked. | 
 |     pub(super) fn into_return_value(self) -> T { | 
 |         match self { | 
 |             JobResult::None => unreachable!(), | 
 |             JobResult::Ok(x) => x, | 
 |             JobResult::Panic(x) => unwind::resume_unwinding(x), | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | /// Indirect queue to provide FIFO job priority. | 
 | pub(super) struct JobFifo { | 
 |     inner: Injector<JobRef>, | 
 | } | 
 |  | 
 | impl JobFifo { | 
 |     pub(super) fn new() -> Self { | 
 |         JobFifo { inner: Injector::new() } | 
 |     } | 
 |  | 
 |     pub(super) unsafe fn push(&self, job_ref: JobRef) -> JobRef { | 
 |         // A little indirection ensures that spawns are always prioritized in FIFO order. The | 
 |         // jobs in a thread's deque may be popped from the back (LIFO) or stolen from the front | 
 |         // (FIFO), but either way they will end up popping from the front of this queue. | 
 |         self.inner.push(job_ref); | 
 |         unsafe { JobRef::new(self) } | 
 |     } | 
 | } | 
 |  | 
 | impl Job for JobFifo { | 
 |     unsafe fn execute(this: *const ()) { | 
 |         // We "execute" a queue by executing its first job, FIFO. | 
 |         let this = unsafe { &*(this as *const Self) }; | 
 |         loop { | 
 |             match this.inner.steal() { | 
 |                 Steal::Success(job_ref) => break unsafe { job_ref.execute() }, | 
 |                 Steal::Empty => panic!("FIFO is empty"), | 
 |                 Steal::Retry => {} | 
 |             } | 
 |         } | 
 |     } | 
 | } |