Skip to content

Commit 65cf75a

Browse files
committed
Fix select deschedule environment race for real this time, in light of task killing.
1 parent 0d817ee commit 65cf75a

File tree

1 file changed

+23
-18
lines changed

1 file changed

+23
-18
lines changed

src/libstd/select.rs

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use rt::select::{SelectInner, SelectPortInner};
2020
use rt::local::Local;
2121
use rt::rtio::EventLoop;
2222
use task;
23+
use unstable::finally::Finally;
2324
use vec::{OwnedVector, MutableVector};
2425

2526
/// Trait for message-passing primitives that can be select()ed on.
@@ -57,28 +58,32 @@ pub fn select<A: Select>(ports: &mut [A]) -> uint {
5758
let p = Cell::new(p);
5859
let c = Cell::new(c);
5960

60-
let sched = Local::take::<Scheduler>();
61-
do sched.deschedule_running_task_and_then |sched, task| {
62-
let task_handles = task.make_selectable(ports.len());
63-
64-
for (index, (port, task_handle)) in
65-
ports.mut_iter().zip(task_handles.move_iter()).enumerate() {
66-
// If one of the ports has data by now, it will wake the handle.
67-
if port.block_on(sched, task_handle) {
68-
ready_index = index;
69-
break;
61+
do (|| {
62+
let c = Cell::new(c.take());
63+
let sched = Local::take::<Scheduler>();
64+
do sched.deschedule_running_task_and_then |sched, task| {
65+
let task_handles = task.make_selectable(ports.len());
66+
67+
for (index, (port, task_handle)) in
68+
ports.mut_iter().zip(task_handles.move_iter()).enumerate() {
69+
// If one of the ports has data by now, it will wake the handle.
70+
if port.block_on(sched, task_handle) {
71+
ready_index = index;
72+
break;
73+
}
7074
}
71-
}
7275

73-
let c = Cell::new(c.take());
74-
do sched.event_loop.callback { c.take().send_deferred(()) }
76+
let c = Cell::new(c.take());
77+
do sched.event_loop.callback { c.take().send_deferred(()) }
78+
}
79+
}).finally {
80+
let p = Cell::new(p.take());
81+
// Unkillable is necessary not because getting killed is dangerous here,
82+
// but to force the recv not to use the same kill-flag that we used for
83+
// selecting. Otherwise a user-sender could spuriously wakeup us here.
84+
do task::unkillable { p.take().recv(); }
7585
}
7686

77-
// Unkillable is necessary not because getting killed is dangerous here,
78-
// but to force the recv not to use the same kill-flag that we used for
79-
// selecting. Otherwise a user-sender could spuriously wakeup us here.
80-
do task::unkillable { p.take().recv(); }
81-
8287
// Task resumes. Now unblock ourselves from all the ports we blocked on.
8388
// If the success index wasn't reset, 'take' will just take all of them.
8489
// Iterate in reverse so the 'earliest' index that's ready gets returned.

0 commit comments

Comments
 (0)