rt: Change the rust_port refcounting scheme to avoid races

Hopefully...
This commit is contained in:
Brian Anderson 2012-03-06 15:31:21 -08:00
parent e9571850da
commit dc0b9f44e2
3 changed files with 27 additions and 22 deletions

View File

@ -497,7 +497,6 @@ extern "C" CDECL void
del_port(rust_port *port) {
rust_task *task = rust_task_thread::get_task();
LOG(task, comm, "del_port(0x%" PRIxPTR ")", (uintptr_t) port);
A(task->thread, port->get_ref_count() == 0, "Expected port ref_count == 0");
delete port;
}

View File

@ -20,12 +20,19 @@ rust_port::~rust_port() {
task->deref();
}
void rust_port::delete_this() {
scoped_lock with(detach_lock);
void rust_port::ref() {
scoped_lock with(ref_lock);
ref_count++;
}
if (task->blocked_on(&detach_cond)) {
// The port owner is waiting for the port to be detached
task->wakeup(&detach_cond);
void rust_port::deref() {
scoped_lock with(ref_lock);
ref_count--;
if (!ref_count) {
if (task->blocked_on(&detach_cond)) {
// The port owner is waiting for the port to be detached
task->wakeup(&detach_cond);
}
}
}
@ -34,23 +41,20 @@ void rust_port::begin_detach(uintptr_t *yield) {
task->release_port(id);
deref();
scoped_lock with(ref_lock);
ref_count--;
scoped_lock with(detach_lock);
if (get_ref_count() != 0) {
if (ref_count != 0) {
task->block(&detach_cond, "waiting for port detach");
*yield = true;
}
}
void rust_port::end_detach() {
// FIXME: For some reason we can sometimes get here without the
// refcount decreasing to 0. This is definitely a bug
while (get_ref_count() != 0) { }
// Just take the lock to make sure that the thread that signaled
// the detach_cond isn't still holding it
scoped_lock with(detach_lock);
scoped_lock with(ref_lock);
I(task->thread, ref_count == 0);
}
void rust_port::send(void *sptr) {

View File

@ -6,9 +6,17 @@
class port_detach_cond : public rust_cond { };
class rust_port : public kernel_owned<rust_port>, public rust_cond {
public:
RUST_ATOMIC_REFCOUNT();
private:
// Protects ref_count and detach_cond
lock_and_signal ref_lock;
intptr_t ref_count;
port_detach_cond detach_cond;
public:
void ref();
void deref();
public:
rust_port_id id;
rust_kernel *kernel;
@ -18,15 +26,9 @@ public:
lock_and_signal lock;
private:
// Protects blocking and signaling on detach_cond
lock_and_signal detach_lock;
port_detach_cond detach_cond;
public:
rust_port(rust_task *task, size_t unit_sz);
~rust_port();
void delete_this();
void log_state();
void send(void *sptr);