diff options
| author | Ben Blum <bblum@andrew.cmu.edu> | 2013-08-13 17:31:13 -0400 |
|---|---|---|
| committer | Ben Blum <bblum@andrew.cmu.edu> | 2013-08-15 15:57:31 -0400 |
| commit | 65cf75af67de10d335391cfd66ee15e462d806f7 (patch) | |
| tree | badb39e50709a4e9a296e33bf570747d9ddecfb0 /src/libstd | |
| parent | 0d817ee869387322dec4d3f7d407dcc9f91c2632 (diff) | |
| download | rust-65cf75af67de10d335391cfd66ee15e462d806f7.tar.gz rust-65cf75af67de10d335391cfd66ee15e462d806f7.zip | |
Fix select deschedule environment race for real this time, in light of task killing.
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/select.rs | 41 |
1 files changed, 23 insertions, 18 deletions
diff --git a/src/libstd/select.rs b/src/libstd/select.rs index a92339e2562..8209ce42003 100644 --- a/src/libstd/select.rs +++ b/src/libstd/select.rs @@ -20,6 +20,7 @@ use rt::select::{SelectInner, SelectPortInner}; use rt::local::Local; use rt::rtio::EventLoop; use task; +use unstable::finally::Finally; use vec::{OwnedVector, MutableVector}; /// Trait for message-passing primitives that can be select()ed on. @@ -57,28 +58,32 @@ pub fn select<A: Select>(ports: &mut [A]) -> uint { let p = Cell::new(p); let c = Cell::new(c); - let sched = Local::take::<Scheduler>(); - do sched.deschedule_running_task_and_then |sched, task| { - let task_handles = task.make_selectable(ports.len()); - - for (index, (port, task_handle)) in - ports.mut_iter().zip(task_handles.move_iter()).enumerate() { - // If one of the ports has data by now, it will wake the handle. - if port.block_on(sched, task_handle) { - ready_index = index; - break; + do (|| { + let c = Cell::new(c.take()); + let sched = Local::take::<Scheduler>(); + do sched.deschedule_running_task_and_then |sched, task| { + let task_handles = task.make_selectable(ports.len()); + + for (index, (port, task_handle)) in + ports.mut_iter().zip(task_handles.move_iter()).enumerate() { + // If one of the ports has data by now, it will wake the handle. + if port.block_on(sched, task_handle) { + ready_index = index; + break; + } } - } - let c = Cell::new(c.take()); - do sched.event_loop.callback { c.take().send_deferred(()) } + let c = Cell::new(c.take()); + do sched.event_loop.callback { c.take().send_deferred(()) } + } + }).finally { + let p = Cell::new(p.take()); + // Unkillable is necessary not because getting killed is dangerous here, + // but to force the recv not to use the same kill-flag that we used for + // selecting. Otherwise a user-sender could spuriously wakeup us here. + do task::unkillable { p.take().recv(); } } - // Unkillable is necessary not because getting killed is dangerous here, - // but to force the recv not to use the same kill-flag that we used for - // selecting. Otherwise a user-sender could spuriously wakeup us here. - do task::unkillable { p.take().recv(); } - // Task resumes. Now unblock ourselves from all the ports we blocked on. // If the success index wasn't reset, 'take' will just take all of them. // Iterate in reverse so the 'earliest' index that's ready gets returned. |
