]> git.lizzy.rs Git - rust.git/commitdiff
Fix an apparent race in pipes.
authorEric Holk <eric.holk@gmail.com>
Fri, 3 Aug 2012 01:55:31 +0000 (18:55 -0700)
committerEric Holk <eric.holk@gmail.com>
Fri, 3 Aug 2012 02:27:07 +0000 (19:27 -0700)
Also removed some unsafety in pipes and added vec::consume_mut.

src/libcore/pipes.rs
src/libcore/vec.rs

index 7fb1aabb1fe42d70e5e333f52e07637a2fad3c07..fd42ad73d3d1a7c03dadf140e04d46ed789cff38 100644 (file)
@@ -117,6 +117,8 @@ unsafe fn mark_blocked(this: *rust_task) -> state {
     }
 
     unsafe fn unblock() {
+        assert self.state != blocked || self.blocked_task != none;
+        self.blocked_task = none;
         alt swap_state_acq(self.state, empty) {
           empty | blocked { }
           terminated { self.state = terminated; }
@@ -322,7 +324,7 @@ fn send<T: send, Tbuffer: send>(-p: send_packet_buffered<T, Tbuffer>,
             rustrt::task_signal_event(
                 task, ptr::addr_of(p.header) as *libc::c_void);
           }
-          none { fail ~"blocked packet has no task" }
+          none { debug!{"just kidding!"} }
         }
 
         // The receiver will eventually clean this up.
@@ -878,23 +880,28 @@ fn chan() -> chan<T> {
 
     fn try_recv() -> option<T> {
         let mut result = none;
-        while result == none && self.ports.len() > 0 {
-            let i = wait_many(self.ports.map(|p| p.header()));
-            // dereferencing an unsafe pointer nonsense to appease the
-            // borrowchecker.
-            alt move unsafe {(*ptr::addr_of(self.ports[i])).try_recv()} {
-              some(m) {
-                  result = some(move_it!{m});
-              }
-              none {
-                // Remove this port.
-                let mut ports = ~[];
-                self.ports <-> ports;
-                vec::consume(ports,
-                             |j, x| if i != j { vec::push(self.ports, x) });
-              }
+        // we have to swap the ports array so we aren't borrowing
+        // aliasable mutable memory.
+        let mut ports = ~[];
+        ports <-> self.ports;
+        while result == none && ports.len() > 0 {
+            let i = wait_many(ports.map(|p| p.header()));
+            alt move ports[i].try_recv() {
+                some(m) {
+                    result = some(move m);
+                }
+                none {
+                    // Remove this port.
+                    let mut ports_ = ~[];
+                    ports <-> ports_;
+                    vec::consume(ports_,
+                                 |j, x| if i != j {
+                                     vec::push(ports, x)
+                                 });
+                }
             }
         }
+        ports <-> self.ports;
         result
     }
 
index c02560bf6c36c8970476f238fdd28f38c20f2008..2606bdf72f8224c3a94758203e0aa2ce18bf626c 100644 (file)
@@ -6,7 +6,7 @@
 
 export append;
 export append_one;
-export consume;
+export consume, consume_mut;
 export init_op;
 export is_empty;
 export is_not_empty;
@@ -490,6 +490,17 @@ fn consume<T>(+v: ~[T], f: fn(uint, +T)) unsafe {
     unsafe::set_len(v, 0);
 }
 
+fn consume_mut<T>(+v: ~[mut T], f: fn(uint, +T)) unsafe {
+    do as_buf(v) |p, ln| {
+        for uint::range(0, ln) |i| {
+            let x <- *ptr::offset(p, i);
+            f(i, x);
+        }
+    }
+
+    unsafe::set_len(v, 0);
+}
+
 /// Remove the last element from a vector and return it
 fn pop<T>(&v: ~[const T]) -> T {
     let ln = len(v);