rt: Change the rust_port refcounting scheme to avoid races
Hopefully...
This commit is contained in:
parent
e9571850da
commit
dc0b9f44e2
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user