diff options
| author | bors <bors@rust-lang.org> | 2013-08-18 19:32:36 -0700 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2013-08-18 19:32:36 -0700 |
| commit | 557ff049f098ab0d53670291fca660eb23549827 (patch) | |
| tree | c45aa57a74b36fc05431a7edaf2744a0842cb629 /src/libstd | |
| parent | 8fff3f40f290df5bcd25bcefdc0e19f74d0af0a5 (diff) | |
| parent | 65cf75af67de10d335391cfd66ee15e462d806f7 (diff) | |
| download | rust-557ff049f098ab0d53670291fca660eb23549827.tar.gz rust-557ff049f098ab0d53670291fca660eb23549827.zip | |
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.
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/select.rs | 41 |
1 files changed, 23 insertions, 18 deletions
diff --git a/src/libstd/select.rs b/src/libstd/select.rs index 6a81be3dc8f..f537a1f6c33 100644 --- a/src/libstd/select.rs +++ b/src/libstd/select.rs @@ -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,28 +58,32 @@ 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()); + 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; + } } - } - let c = Cell::new(c.take()); - do sched.event_loop.callback { c.take().send_deferred(()) } + 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(); } } - // 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. // Iterate in reverse so the 'earliest' index that's ready gets returned. |
