|
| 1 | +use crate::job::JobRef; |
1 | 2 | use crate::job::StackJob; |
2 | 3 | use crate::latch::SpinLatch; |
3 | | -use crate::registry::{self, WorkerThread}; |
4 | | -use crate::tlv::{self, Tlv}; |
| 4 | +use crate::registry; |
| 5 | +use crate::tlv; |
5 | 6 | use crate::unwind; |
6 | | -use std::any::Any; |
| 7 | +use std::sync::atomic::{AtomicBool, Ordering}; |
7 | 8 |
|
8 | 9 | use crate::FnContext; |
9 | 10 |
|
@@ -135,68 +136,41 @@ where |
135 | 136 | // Create virtual wrapper for task b; this all has to be |
136 | 137 | // done here so that the stack frame can keep it all live |
137 | 138 | // long enough. |
138 | | - let job_b = StackJob::new(tlv, call_b(oper_b), SpinLatch::new(worker_thread)); |
| 139 | + let job_b_started = AtomicBool::new(false); |
| 140 | + let job_b = StackJob::new( |
| 141 | + tlv, |
| 142 | + |migrated| { |
| 143 | + job_b_started.store(true, Ordering::Relaxed); |
| 144 | + call_b(oper_b)(migrated) |
| 145 | + }, |
| 146 | + SpinLatch::new(worker_thread), |
| 147 | + ); |
139 | 148 | let job_b_ref = job_b.as_job_ref(); |
140 | 149 | let job_b_id = job_b_ref.id(); |
141 | 150 | worker_thread.push(job_b_ref); |
142 | 151 |
|
143 | 152 | // Execute task a; hopefully b gets stolen in the meantime. |
144 | 153 | let status_a = unwind::halt_unwinding(call_a(oper_a, injected)); |
145 | | - let result_a = match status_a { |
146 | | - Ok(v) => v, |
147 | | - Err(err) => join_recover_from_panic(worker_thread, &job_b.latch, err, tlv), |
148 | | - }; |
149 | | - |
150 | | - // Now that task A has finished, try to pop job B from the |
151 | | - // local stack. It may already have been popped by job A; it |
152 | | - // may also have been stolen. There may also be some tasks |
153 | | - // pushed on top of it in the stack, and we will have to pop |
154 | | - // those off to get to it. |
155 | | - while !job_b.latch.probe() { |
156 | | - if let Some(job) = worker_thread.take_local_job() { |
157 | | - if job_b_id == job.id() { |
158 | | - // Found it! Let's run it. |
159 | | - // |
160 | | - // Note that this could panic, but it's ok if we unwind here. |
161 | 154 |
|
162 | | - // Restore the TLV since we might have run some jobs overwriting it when waiting for job b. |
163 | | - tlv::set(tlv); |
164 | | - |
165 | | - let result_b = job_b.run_inline(injected); |
166 | | - return (result_a, result_b); |
167 | | - } else { |
168 | | - worker_thread.execute(job); |
169 | | - } |
170 | | - } else { |
171 | | - // Local deque is empty. Time to steal from other |
172 | | - // threads. |
173 | | - worker_thread.wait_until(&job_b.latch); |
174 | | - debug_assert!(job_b.latch.probe()); |
175 | | - break; |
176 | | - } |
177 | | - } |
| 155 | + // Wait for job B or execute it if it's in the local queue. |
| 156 | + worker_thread.wait_for_jobs::<_, false>( |
| 157 | + &job_b.latch, |
| 158 | + || job_b_started.load(Ordering::Relaxed), |
| 159 | + |job| job.id() == job_b_id, |
| 160 | + |job: JobRef| { |
| 161 | + debug_assert_eq!(job.id(), job_b_id); |
| 162 | + job_b.run_inline(injected); |
| 163 | + }, |
| 164 | + ); |
178 | 165 |
|
179 | 166 | // Restore the TLV since we might have run some jobs overwriting it when waiting for job b. |
180 | 167 | tlv::set(tlv); |
181 | 168 |
|
| 169 | + let result_a = match status_a { |
| 170 | + Ok(v) => v, |
| 171 | + Err(err) => unwind::resume_unwinding(err), |
| 172 | + }; |
| 173 | + |
182 | 174 | (result_a, job_b.into_result()) |
183 | 175 | }) |
184 | 176 | } |
185 | | - |
186 | | -/// If job A panics, we still cannot return until we are sure that job |
187 | | -/// B is complete. This is because it may contain references into the |
188 | | -/// enclosing stack frame(s). |
189 | | -#[cold] // cold path |
190 | | -unsafe fn join_recover_from_panic( |
191 | | - worker_thread: &WorkerThread, |
192 | | - job_b_latch: &SpinLatch<'_>, |
193 | | - err: Box<dyn Any + Send>, |
194 | | - tlv: Tlv, |
195 | | -) -> ! { |
196 | | - worker_thread.wait_until(job_b_latch); |
197 | | - |
198 | | - // Restore the TLV since we might have run some jobs overwriting it when waiting for job b. |
199 | | - tlv::set(tlv); |
200 | | - |
201 | | - unwind::resume_unwinding(err) |
202 | | -} |
0 commit comments