about summary refs log tree commit diff
path: root/src/libstd/select.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstd/select.rs')
-rw-r--r--src/libstd/select.rs35
1 files changed, 21 insertions, 14 deletions
diff --git a/src/libstd/select.rs b/src/libstd/select.rs
index 4f78ade3f08..01b953051db 100644
--- a/src/libstd/select.rs
+++ b/src/libstd/select.rs
@@ -10,18 +10,16 @@
 
 #[allow(missing_doc)];
 
-use cell::Cell;
 use comm;
 use container::Container;
 use iter::{Iterator, DoubleEndedIterator};
+use kinds::Send;
+use ops::Drop;
 use option::*;
-// use either::{Either, Left, Right};
-// use rt::kill::BlockedTask;
 use rt::local::Local;
 use rt::rtio::EventLoop;
 use rt::sched::Scheduler;
 use rt::shouldnt_be_public::{SelectInner, SelectPortInner};
-use unstable::finally::Finally;
 use vec::{OwnedVector, MutableVector};
 
 /// Trait for message-passing primitives that can be select()ed on.
@@ -32,6 +30,18 @@ pub trait Select : SelectInner { }
 // that implement Select on different types to use select().)
 pub trait SelectPort<T> : SelectPortInner<T> { }
 
+/// A helper type that throws away a value on a port.
+struct PortGuard<T> {
+    port: Option<comm::PortOne<T>>,
+}
+
+#[unsafe_destructor]
+impl<T:Send> Drop for PortGuard<T> {
+    fn drop(&mut self) {
+        let _ = self.port.take_unwrap().recv();
+    }
+}
+
 /// Receive a message from any one of many ports at once. Returns the index of the
 /// port whose data is ready. (If multiple are ready, returns the lowest index.)
 pub fn select<A: Select>(ports: &mut [A]) -> uint {
@@ -56,11 +66,13 @@ pub fn select<A: Select>(ports: &mut [A]) -> uint {
     // after letting the task get woken up. The and_then closure needs to delay
     // the task from resuming until all ports have become blocked_on.
     let (p,c) = comm::oneshot();
-    let p = Cell::new(p);
-    let c = Cell::new(c);
 
-    (|| {
-        let mut c = Some(c.take());
+    {
+        let _guard = PortGuard {
+            port: Some(p),
+        };
+
+        let mut c = Some(c);
         let sched: ~Scheduler = Local::take();
         sched.deschedule_running_task_and_then(|sched, task| {
             let task_handles = task.make_selectable(ports.len());
@@ -79,12 +91,7 @@ pub fn select<A: Select>(ports: &mut [A]) -> uint {
                 c.send_deferred(())
             }
         })
-    }).finally(|| {
-        // 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.
-        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.