Skip to content

Commit

Permalink
Move the channel destroy code into rust_chan.
Browse files Browse the repository at this point in the history
This lets native code more easily destroy channels since directly deleting a
channel is not always the right way to destroy it.
  • Loading branch information
robarnold authored and Eric Holk committed Jul 1, 2011
1 parent 09921cf commit 73cc624
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 29 deletions.
35 changes: 35 additions & 0 deletions src/rt/rust_chan.cpp
Expand Up @@ -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++
Expand Down
3 changes: 3 additions & 0 deletions src/rt/rust_chan.h
Expand Up @@ -21,6 +21,9 @@ class rust_chan : public rc_base<rust_chan>,
void send(void *sptr);

rust_chan *clone(maybe_proxy<rust_task> *target);

// Called whenever the channel's ref count drops to zero.
void destroy();
};

//
Expand Down
30 changes: 1 addition & 29 deletions src/rt/rust_upcall.cpp
Expand Up @@ -126,35 +126,7 @@ void upcall_del_chan(rust_task *task, rust_chan *chan) {
scoped_lock with(task->kernel->scheduler_lock);

LOG(task, comm, "upcall del_chan(0x%" PRIxPTR ")", (uintptr_t) chan);

A(task->sched, chan->ref_count == 0,
"Channel's ref count should be zero.");

if (chan->is_associated()) {
if (chan->port->is_proxy()) {
// Here is a good place to delete the port proxy we allocated
// in upcall_clone_chan.
rust_proxy<rust_port> *proxy = chan->port->as_proxy();
chan->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 "dormant" 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;
chan->destroy();
}

/**
Expand Down

0 comments on commit 73cc624

Please sign in to comment.