aboutsummaryrefslogtreecommitdiff
path: root/src/rt
diff options
context:
space:
mode:
authorMichael Bebenita <[email protected]>2010-08-17 23:21:29 -0700
committerMichael Bebenita <[email protected]>2010-08-17 23:49:57 -0700
commit7ff39ea448c60e5ab993bb4a32649e60de13184d (patch)
tree8ef06fded3f193456304245b4339b888897a73db /src/rt
parentMade the lock_free_queue lock (temporarily, until fixed). (diff)
downloadrust-7ff39ea448c60e5ab993bb4a32649e60de13184d.tar.xz
rust-7ff39ea448c60e5ab993bb4a32649e60de13184d.zip
Fixed deadlock by removing channel flushing.
Diffstat (limited to 'src/rt')
-rw-r--r--src/rt/rust_port.cpp13
-rw-r--r--src/rt/rust_upcall.cpp39
2 files changed, 20 insertions, 32 deletions
diff --git a/src/rt/rust_port.cpp b/src/rt/rust_port.cpp
index fa7790b6..458283fb 100644
--- a/src/rt/rust_port.cpp
+++ b/src/rt/rust_port.cpp
@@ -23,6 +23,12 @@ rust_port::~rust_port() {
while (chans.is_empty() == false) {
rust_chan *chan = chans.peek();
chan->disassociate();
+
+ if (chan->ref_count == 0) {
+ task->log(rust_log::COMM,
+ "chan: 0x%" PRIxPTR " is dormant, freeing", chan);
+ delete chan;
+ }
}
delete remote_channel;
@@ -33,13 +39,6 @@ bool rust_port::receive(void *dptr) {
rust_chan *chan = chans[i];
if (chan->buffer.is_empty() == false) {
chan->buffer.dequeue(dptr);
- if (chan->buffer.is_empty() && chan->task->blocked()) {
- task->log(rust_log::COMM,
- "chan: 0x%" PRIxPTR
- " is flushing, wakeup task: 0x%" PRIxPTR,
- chan, chan->task);
- chan->task->wakeup(this);
- }
task->log(rust_log::COMM, "<=== read data ===");
return true;
}
diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp
index 7f9f0db1..fb85233c 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;