(worker: &Worker, f: F)
| 110 | /// For details about the `'scope` and `'env` lifetimes see [`Scope`]. |
| 111 | #[inline] |
| 112 | pub fn with_scope<'env, F, T>(worker: &Worker, f: F) -> T |
| 113 | where |
| 114 | F: for<'scope> FnOnce(&'scope Scope<'scope, 'env>) -> T, |
| 115 | { |
| 116 | let abort_guard = AbortOnDrop; |
| 117 | // Create a new scope object on the stack. |
| 118 | let scope = Scope { |
| 119 | thread_pool: worker.thread_pool(), |
| 120 | count: AtomicU32::new(1), |
| 121 | completed: worker.new_latch(), |
| 122 | panic: AtomicPtr::new(ptr::null_mut()), |
| 123 | _scope: PhantomData, |
| 124 | _env: PhantomData, |
| 125 | }; |
| 126 | // Panics that occur within the closure should be caught and propagated once |
| 127 | // all spawned work is complete. This is not a safety requirement, it's just |
| 128 | // a nicer behavior than aborting. |
| 129 | let result = match unwind::halt_unwinding(|| f(&scope)) { |
| 130 | Ok(result) => Some(result), |
| 131 | Err(err) => { |
| 132 | scope.store_panic(err); |
| 133 | None |
| 134 | } |
| 135 | }; |
| 136 | // Now that the user has (presumably) spawned some work onto the scope, we |
| 137 | // must wait for it to complete. |
| 138 | // |
| 139 | // SAFETY: This is called only once within this function, and then the scope |
| 140 | // is dropped. |
| 141 | unsafe { scope.complete(worker) }; |
| 142 | // At this point all work on the scope is complete, so it is safe to drop |
| 143 | // the scope. This also means we can relinquish our abort guard (returning |
| 144 | // to the normal panic behavior). |
| 145 | core::mem::forget(abort_guard); |
| 146 | // If the closure or any spawned work did panic, we can now panic. |
| 147 | scope.maybe_propagate_panic(); |
| 148 | // Return the result. |
| 149 | result.unwrap() |
| 150 | } |
| 151 | |
| 152 | impl<'scope, 'env> Scope<'scope, 'env> { |
| 153 | /// Runs a closure or future sometime before the scope completes. |
no test coverage detected