diff options
| author | Rob Arnold <robarnold@cs.cmu.edu> | 2011-06-30 08:29:35 -0700 |
|---|---|---|
| committer | Eric Holk <eholk@mozilla.com> | 2011-07-01 16:59:10 -0700 |
| commit | 73cc624e8e326f54eb0ea8bff70388d62dccd3cb (patch) | |
| tree | d0623428177fdc2f305e749eab9b03a80459d8d9 /src/rt/rust_chan.cpp | |
| parent | 09921cf86f156208741243a7e0ea55b88155ec72 (diff) | |
| download | rust-73cc624e8e326f54eb0ea8bff70388d62dccd3cb.tar.gz rust-73cc624e8e326f54eb0ea8bff70388d62dccd3cb.zip | |
Move the channel destroy code into rust_chan.
This lets native code more easily destroy channels since directly deleting a channel is not always the right way to destroy it.
Diffstat (limited to 'src/rt/rust_chan.cpp')
| -rw-r--r-- | src/rt/rust_chan.cpp | 35 |
1 files changed, 35 insertions, 0 deletions
diff --git a/src/rt/rust_chan.cpp b/src/rt/rust_chan.cpp index a1c71b049ea..3065a55e582 100644 --- a/src/rt/rust_chan.cpp +++ b/src/rt/rust_chan.cpp @@ -116,6 +116,41 @@ rust_chan *rust_chan::clone(maybe_proxy<rust_task> *target) { return new (target_task) rust_chan(target_task, port, unit_sz); } +/** + * Cannot Yield: If the task were to unwind, the dropped ref would still + * appear to be live, causing modify-after-free errors. + */ +void rust_chan::destroy() { + A(task->sched, ref_count == 0, + "Channel's ref count should be zero."); + + if (is_associated()) { + if (port->is_proxy()) { + // Here is a good place to delete the port proxy we allocated + // in upcall_clone_chan. + rust_proxy<rust_port> *proxy = port->as_proxy(); + disassociate(); + delete proxy; + } else { + // 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 (buffer.is_empty() == false) { + return; + } + disassociate(); + } + } + delete this; +} + // // Local Variables: // mode: C++ |
