mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-10 23:06:23 +00:00
Fix select deschedule environment race for real this time, in light of task killing.
This commit is contained in:
parent
0d817ee869
commit
65cf75af67
@ -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,27 +58,31 @@ 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());
|
||||
do sched.event_loop.callback { c.take().send_deferred(()) }
|
||||
}
|
||||
let sched = Local::take::<Scheduler>();
|
||||
do sched.deschedule_running_task_and_then |sched, task| {
|
||||
let task_handles = task.make_selectable(ports.len());
|
||||
|
||||
// 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(); }
|
||||
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(()) }
|
||||
}
|
||||
}).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.
|
||||
|
Loading…
Reference in New Issue
Block a user