about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorBen Blum <bblum@andrew.cmu.edu>2012-07-11 20:00:58 -0400
committerBen Blum <bblum@andrew.cmu.edu>2012-07-12 18:08:36 -0400
commit343e9de8ef4ee9727f027c896ce99f09611b9603 (patch)
tree203e9084453699cb8b7175a75438cfd5c9ed8d00 /src
parentb897696a3abde84e57cda3f6e4267be3b647835c (diff)
downloadrust-343e9de8ef4ee9727f027c896ce99f09611b9603.tar.gz
rust-343e9de8ef4ee9727f027c896ce99f09611b9603.zip
Proper locking with blocked_on()/wakeup() in rust_port. Closes #2787. Closes #1923.
Diffstat (limited to 'src')
-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, 24 insertions, 22 deletions
diff --git a/src/rt/rust_port.cpp b/src/rt/rust_port.cpp
index f1a40508aca..919dadd4044 100644
--- a/src/rt/rust_port.cpp
+++ b/src/rt/rust_port.cpp
@@ -26,9 +26,11 @@ 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)) {
-            // The port owner is waiting for the port to be detached
-            task->wakeup(&detach_cond);
+            task->wakeup_inner(&detach_cond);
         }
     }
 }
@@ -64,12 +66,15 @@ void rust_port::send(void *sptr) {
         assert(!buffer.is_empty() &&
                "rust_chan::transmit with nothing to send.");
 
-        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;
+        {
+            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;
+            }
         }
     }
 
@@ -78,11 +83,8 @@ void rust_port::send(void *sptr) {
         // it may be waiting on a group of ports
 
         rust_port_selector *port_selector = task->get_port_selector();
-        // 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);
-        }
+        // The port selector will check if the task is blocked, not us.
+        port_selector->msg_sent_on(this);
     }
 }
 
diff --git a/src/rt/rust_port_selector.cpp b/src/rt/rust_port_selector.cpp
index 7b3b45788f7..52f9e0c3a01 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(rendezvous_lock);
+    scoped_lock with(task->lifecycle_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(this);
+                task->wakeup_inner(this);
                 return;
             }
         }
diff --git a/src/rt/rust_port_selector.h b/src/rt/rust_port_selector.h
index 8dbf0c40329..73f2a9e4a0c 100644
--- a/src/rt/rust_port_selector.h
+++ b/src/rt/rust_port_selector.h
@@ -9,7 +9,6 @@ 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 fa05a713745..3d88c05b3ff 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 (#2787): clean this up
+    // FIXME (#2875): clean this up
     if (must_fail_from_being_killed()) {
         {
             scoped_lock with(lifecycle_lock);
@@ -346,12 +346,11 @@ void rust_task::assert_is_running()
     assert(state == task_state_running);
 }
 
-// FIXME (#2851, #2787): This is only used by rust_port/rust_port selector,
-// and is inherently racy. Get rid of it.
+// FIXME (#2851) Remove this code when rust_port goes away?
 bool
 rust_task::blocked_on(rust_cond *on)
 {
-    scoped_lock with(lifecycle_lock);
+    lifecycle_lock.must_have_lock();
     return cond == on;
 }
 
diff --git a/src/rt/rust_task.h b/src/rt/rust_task.h
index ba327822c37..1d87a0ed56c 100644
--- a/src/rt/rust_task.h
+++ b/src/rt/rust_task.h
@@ -226,8 +226,11 @@ 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:
 
@@ -243,7 +246,6 @@ 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);
@@ -435,7 +437,7 @@ rust_task::call_on_rust_stack(void *args, void *fn_ptr) {
 
     bool had_reentered_rust_stack = reentered_rust_stack;
     {
-        // FIXME (#2787) This must be racy. Figure it out.
+        // FIXME (#2875) This must be racy. Figure it out.
         scoped_lock with(lifecycle_lock);
         reentered_rust_stack = true;
     }