about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBen Blum <bblum@andrew.cmu.edu>2012-07-12 19:43:22 -0400
committerBen Blum <bblum@andrew.cmu.edu>2012-07-12 19:49:49 -0400
commita10f52c5793b358a16e3e98db4b16c65ba8e254b (patch)
tree67e53933ce262ab82e2179841f9fc400db72a840
parent5724c6454950617c292daba89cdb9a3b4c862430 (diff)
downloadrust-a10f52c5793b358a16e3e98db4b16c65ba8e254b.tar.gz
rust-a10f52c5793b358a16e3e98db4b16c65ba8e254b.zip
Revert linked failure (rust_port locking)
This reverts commit 343e9de8ef4ee9727f027c896ce99f09611b9603.
-rw-r--r--src/rt/rust_port.cpp28
-rw-r--r--src/rt/rust_port_selector.cpp4
-rw-r--r--src/rt/rust_port_selector.h1
-rw-r--r--src/rt/rust_task.cpp7
-rw-r--r--src/rt/rust_task.h6
5 files changed, 22 insertions, 24 deletions
diff --git a/src/rt/rust_port.cpp b/src/rt/rust_port.cpp
index 919dadd4044..f1a40508aca 100644
--- a/src/rt/rust_port.cpp
+++ b/src/rt/rust_port.cpp
@@ -26,11 +26,9 @@ void rust_port::deref() {
     scoped_lock with(ref_lock);
     ref_count--;
     if (!ref_count) {
-        // The port owner is waiting for the port to be detached (if it
-        // hasn't already been killed)
-        scoped_lock with(task->lifecycle_lock);
         if (task->blocked_on(&detach_cond)) {
-            task->wakeup_inner(&detach_cond);
+            // The port owner is waiting for the port to be detached
+            task->wakeup(&detach_cond);
         }
     }
 }
@@ -66,15 +64,12 @@ void rust_port::send(void *sptr) {
         assert(!buffer.is_empty() &&
                "rust_chan::transmit with nothing to send.");
 
-        {
-            scoped_lock with(task->lifecycle_lock);
-            if (task->blocked_on(this)) {
-                KLOG(kernel, comm, "dequeued in rendezvous_ptr");
-                buffer.dequeue(task->rendezvous_ptr);
-                task->rendezvous_ptr = 0;
-                task->wakeup_inner(this);
-                did_rendezvous = true;
-            }
+        if (task->blocked_on(this)) {
+            KLOG(kernel, comm, "dequeued in rendezvous_ptr");
+            buffer.dequeue(task->rendezvous_ptr);
+            task->rendezvous_ptr = 0;
+            task->wakeup(this);
+            did_rendezvous = true;
         }
     }
 
@@ -83,8 +78,11 @@ void rust_port::send(void *sptr) {
         // it may be waiting on a group of ports
 
         rust_port_selector *port_selector = task->get_port_selector();
-        // The port selector will check if the task is blocked, not us.
-        port_selector->msg_sent_on(this);
+        // This check is not definitive. The port selector will take a lock
+        // and check again whether the task is still blocked.
+        if (task->blocked_on(port_selector)) {
+            port_selector->msg_sent_on(this);
+        }
     }
 }
 
diff --git a/src/rt/rust_port_selector.cpp b/src/rt/rust_port_selector.cpp
index 52f9e0c3a01..7b3b45788f7 100644
--- a/src/rt/rust_port_selector.cpp
+++ b/src/rt/rust_port_selector.cpp
@@ -75,7 +75,7 @@ rust_port_selector::msg_sent_on(rust_port *port) {
 
     // Prevent two ports from trying to wake up the task
     // simultaneously
-    scoped_lock with(task->lifecycle_lock);
+    scoped_lock with(rendezvous_lock);
 
     if (task->blocked_on(this)) {
         for (size_t i = 0; i < n_ports; i++) {
@@ -85,7 +85,7 @@ rust_port_selector::msg_sent_on(rust_port *port) {
                 n_ports = 0;
                 *task->rendezvous_ptr = (uintptr_t) port;
                 task->rendezvous_ptr = NULL;
-                task->wakeup_inner(this);
+                task->wakeup(this);
                 return;
             }
         }
diff --git a/src/rt/rust_port_selector.h b/src/rt/rust_port_selector.h
index 73f2a9e4a0c..8dbf0c40329 100644
--- a/src/rt/rust_port_selector.h
+++ b/src/rt/rust_port_selector.h
@@ -9,6 +9,7 @@ class rust_port_selector : public rust_cond {
  private:
     rust_port **ports;
     size_t n_ports;
+    lock_and_signal rendezvous_lock;
 
  public:
     rust_port_selector();
diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp
index 3d88c05b3ff..fa05a713745 100644
--- a/src/rt/rust_task.cpp
+++ b/src/rt/rust_task.cpp
@@ -243,7 +243,7 @@ rust_task::must_fail_from_being_killed_inner() {
 // Only run this on the rust stack
 void
 rust_task::yield(bool *killed) {
-    // FIXME (#2875): clean this up
+    // FIXME (#2787): clean this up
     if (must_fail_from_being_killed()) {
         {
             scoped_lock with(lifecycle_lock);
@@ -346,11 +346,12 @@ void rust_task::assert_is_running()
     assert(state == task_state_running);
 }
 
-// FIXME (#2851) Remove this code when rust_port goes away?
+// FIXME (#2851, #2787): This is only used by rust_port/rust_port selector,
+// and is inherently racy. Get rid of it.
 bool
 rust_task::blocked_on(rust_cond *on)
 {
-    lifecycle_lock.must_have_lock();
+    scoped_lock with(lifecycle_lock);
     return cond == on;
 }
 
diff --git a/src/rt/rust_task.h b/src/rt/rust_task.h
index 1d87a0ed56c..ba327822c37 100644
--- a/src/rt/rust_task.h
+++ b/src/rt/rust_task.h
@@ -226,11 +226,8 @@ private:
                                char const *file,
                                size_t line);
 
-    friend class rust_port;
-    friend class rust_port_selector;
     bool block_inner(rust_cond *on, const char* name);
     void wakeup_inner(rust_cond *from);
-    bool blocked_on(rust_cond *cond);
 
 public:
 
@@ -246,6 +243,7 @@ public:
                void *args);
     void start();
     void assert_is_running();
+    bool blocked_on(rust_cond *cond); // FIXME (#2851) Get rid of this.
 
     void *malloc(size_t sz, const char *tag, type_desc *td=0);
     void *realloc(void *data, size_t sz);
@@ -437,7 +435,7 @@ rust_task::call_on_rust_stack(void *args, void *fn_ptr) {
 
     bool had_reentered_rust_stack = reentered_rust_stack;
     {
-        // FIXME (#2875) This must be racy. Figure it out.
+        // FIXME (#2787) This must be racy. Figure it out.
         scoped_lock with(lifecycle_lock);
         reentered_rust_stack = true;
     }