diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index 14b18a992520..9f2bb2d46528 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -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; } diff --git a/src/rt/rust_port.cpp b/src/rt/rust_port.cpp index e3b057264a36..e37829f2df2d 100644 --- a/src/rt/rust_port.cpp +++ b/src/rt/rust_port.cpp @@ -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) { diff --git a/src/rt/rust_port.h b/src/rt/rust_port.h index 38e8f2400234..454b1dcce45b 100644 --- a/src/rt/rust_port.h +++ b/src/rt/rust_port.h @@ -6,9 +6,17 @@ class port_detach_cond : public rust_cond { }; class rust_port : public kernel_owned, 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);