about summary refs log tree commit diff
path: root/src/rt/rust_upcall.cpp
diff options
context:
space:
mode:
authorMichael Bebenita <mbebenita@mozilla.com>2010-08-17 23:21:29 -0700
committerMichael Bebenita <mbebenita@mozilla.com>2010-08-17 23:49:57 -0700
commit7ff39ea448c60e5ab993bb4a32649e60de13184d (patch)
tree8ef06fded3f193456304245b4339b888897a73db /src/rt/rust_upcall.cpp
parent6e9f0f952d758bae2b530c2c9b780f2addf10207 (diff)
downloadrust-7ff39ea448c60e5ab993bb4a32649e60de13184d.tar.gz
rust-7ff39ea448c60e5ab993bb4a32649e60de13184d.zip
Fixed deadlock by removing channel flushing.
Diffstat (limited to 'src/rt/rust_upcall.cpp')
-rw-r--r--src/rt/rust_upcall.cpp39
1 files changed, 14 insertions, 25 deletions
diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp
index 7f9f0db1c6d..fb85233c570 100644
--- a/src/rt/rust_upcall.cpp
+++ b/src/rt/rust_upcall.cpp
@@ -108,29 +108,7 @@ upcall_new_chan(rust_task *task, rust_port *port) {
 extern "C" CDECL void
 upcall_flush_chan(rust_task *task, rust_chan *chan) {
     LOG_UPCALL_ENTRY(task);
-    rust_dom *dom = task->dom;
-    task->log(rust_log::UPCALL | rust_log::COMM,
-              "flush chan: 0x%" PRIxPTR, chan);
-
-    if (chan->buffer.is_empty()) {
-        return;
-    }
-
-    // We cannot flush if the target port was dropped.
-    if (chan->is_associated() == false) {
-        return;
-    }
-
-    A(dom, chan->is_associated(),
-      "Channel should be associated to a port.");
-
-    A(dom, chan->port->is_proxy() == false,
-      "Channels to remote ports should be flushed automatically.");
-
-    // Block on the port until this channel has been completely drained
-    // by the port.
-    task->block(chan->port);
-    task->yield(2);
+    // Nop.
 }
 
 /**
@@ -149,8 +127,19 @@ extern "C" CDECL void upcall_del_chan(rust_task *task, rust_chan *chan) {
       "Channel's ref count should be zero.");
 
     if (chan->is_associated()) {
-        A(task->dom, chan->buffer.is_empty(),
-          "Channel's buffer should be empty.");
+        // We're trying to delete a channel that another task may be reading
+        // from. We have two options:
+        //
+        // 1. We can flush the channel by blocking in upcall_flush_chan()
+        //    and resuming only when the channel is flushed. The problem
+        //    here is that we can get ourselves in a deadlock if the parent
+        //    task tries to join us.
+        //
+        // 2. We can leave the channel in a "dormnat" state by not freeing
+        //    it and letting the receiver task delete it for us instead.
+        if (chan->buffer.is_empty() == false) {
+            return;
+        }
         chan->disassociate();
     }
     delete chan;