auto merge of #8565 : bblum/rust/select-bugfix, r=brson

@brson grilled me about how this bugfix worked the first time around, and it occurred to me that it didn't in the case where the task is unwinding. Now it will.
This commit is contained in:
bors 2013-08-18 19:32:36 -07:00
commit 557ff049f0

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.