Fix select deschedule environment race for real this time, in light of task killing.

This commit is contained in:
Ben Blum 2013-08-13 17:31:13 -04:00
parent 0d817ee869
commit 65cf75af67

View File

@ -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,6 +58,8 @@ pub fn select<A: Select>(ports: &mut [A]) -> uint {
let p = Cell::new(p);
let c = Cell::new(c);
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());
@ -73,11 +76,13 @@ pub fn select<A: Select>(ports: &mut [A]) -> uint {
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(); }
}
// 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.