      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207

    use crossbeam_queue::SegQueue;
    use latch::Latch;
    use std::any::Any;
    use std::cell::UnsafeCell;
    use std::mem;
    use unwind;

    pub(super) enum JobResult<T> {
        None,
        Ok(T),
        Panic(Box<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 Self);
    }

    /// 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.
    #[derive(Copy, Clone, Debug, PartialEq, Eq)]
    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,
        {
            let fn_ptr: unsafe fn(*const T) = <T as Job>::execute;

            // erase types:
            JobRef {
                pointer: data as *const (),
                execute_fn: mem::transmute(fn_ptr),
            }
        }

        #[inline]
        pub(super) unsafe fn execute(&self) {
            (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>>,
    }

    impl<L, F, R> StackJob<L, F, R>
    where
        L: Latch + Sync,
        F: FnOnce(bool) -> R + Send,
        R: Send,
    {
        pub(super) fn new(func: F, latch: L) -> StackJob<L, F, R> {
            StackJob {
                latch,
                func: UnsafeCell::new(Some(func)),
                result: UnsafeCell::new(JobResult::None),
            }
        }

        pub(super) unsafe fn as_job_ref(&self) -> JobRef {
            JobRef::new(self)
        }

        pub(super) unsafe fn run_inline(self, stolen: bool) -> R {
            self.func.into_inner().unwrap()(stolen)
        }

        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 Self) {
            let this = &*this;
            let abort = unwind::AbortIfPanic;
            let func = (*this.func.get()).take().unwrap();
            (*this.result.get()) = match unwind::halt_unwinding(|| func(true)) {
                Ok(x) => JobResult::Ok(x),
                Err(x) => JobResult::Panic(x),
            };
            this.latch.set();
            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() + Send,
    {
        job: UnsafeCell<Option<BODY>>,
    }

    impl<BODY> HeapJob<BODY>
    where
        BODY: FnOnce() + Send,
    {
        pub(super) fn new(func: BODY) -> Self {
            HeapJob {
                job: UnsafeCell::new(Some(func)),
            }
        }

        /// 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(self: Box<Self>) -> JobRef {
            let this: *const Self = mem::transmute(self);
            JobRef::new(this)
        }
    }

    impl<BODY> Job for HeapJob<BODY>
    where
        BODY: FnOnce() + Send,
    {
        unsafe fn execute(this: *const Self) {
            let this: Box<Self> = mem::transmute(this);
            let job = (*this.job.get()).take().unwrap();
            job();
        }
    }

    impl<T> JobResult<T> {
        /// 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: SegQueue<JobRef>,
    }

    impl JobFifo {
        pub(super) fn new() -> Self {
            JobFifo {
                inner: SegQueue::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);
            JobRef::new(self)
        }
    }

    impl Job for JobFifo {
        unsafe fn execute(this: *const Self) {
            // We "execute" a queue by executing its first job, FIFO.
            (*this).inner.pop().expect("job in fifo queue").execute()
        }
    }

# Help

## Keyboard Shortcuts

`?`
  Show this help dialog
`S`
  Focus the search field
`↑`
  Move up in search results
`↓`
  Move down in search results
`↹`
  Switch tab
`⏎`
  Go to active search result
`+`
  Expand all sections
`-`
  Collapse all sections

## Search Tricks

Prefix searches with a type followed by a colon (e.g., `fn:`) to restrict the search to a given type.

Accepted types are: `fn`, `mod`, `struct`, `enum`, `trait`, `type`, `macro`, and `const`.

Search functions by type signature (e.g., `vec -> usize` or `* -> vec`)

Search multiple things at once by splitting your query with comma (e.g., `str,u8` or `String,struct:Vec,test`)