Skip to content

Commit 557ff04

Browse files
committed
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.
2 parents 8fff3f4 + 65cf75a commit 557ff04

File tree

1 file changed

+23
-18
lines changed

1 file changed

+23
-18
lines changed

src/libstd/select.rs

+23-18
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)