Skip to content

Commit dc0b9f4

Browse files
committed
rt: Change the rust_port refcounting scheme to avoid races
Hopefully...
1 parent e957185 commit dc0b9f4

File tree

3 files changed

+26
-21
lines changed

3 files changed

+26
-21
lines changed

src/rt/rust_builtin.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,6 @@ extern "C" CDECL void
497497
del_port(rust_port *port) {
498498
rust_task *task = rust_task_thread::get_task();
499499
LOG(task, comm, "del_port(0x%" PRIxPTR ")", (uintptr_t) port);
500-
A(task->thread, port->get_ref_count() == 0, "Expected port ref_count == 0");
501500
delete port;
502501
}
503502

src/rt/rust_port.cpp

+17-13
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,19 @@ rust_port::~rust_port() {
2020
task->deref();
2121
}
2222

23-
void rust_port::delete_this() {
24-
scoped_lock with(detach_lock);
23+
void rust_port::ref() {
24+
scoped_lock with(ref_lock);
25+
ref_count++;
26+
}
2527

26-
if (task->blocked_on(&detach_cond)) {
27-
// The port owner is waiting for the port to be detached
28-
task->wakeup(&detach_cond);
28+
void rust_port::deref() {
29+
scoped_lock with(ref_lock);
30+
ref_count--;
31+
if (!ref_count) {
32+
if (task->blocked_on(&detach_cond)) {
33+
// The port owner is waiting for the port to be detached
34+
task->wakeup(&detach_cond);
35+
}
2936
}
3037
}
3138

@@ -34,23 +41,20 @@ void rust_port::begin_detach(uintptr_t *yield) {
3441

3542
task->release_port(id);
3643

37-
deref();
44+
scoped_lock with(ref_lock);
45+
ref_count--;
3846

39-
scoped_lock with(detach_lock);
40-
if (get_ref_count() != 0) {
47+
if (ref_count != 0) {
4148
task->block(&detach_cond, "waiting for port detach");
4249
*yield = true;
4350
}
4451
}
4552

4653
void rust_port::end_detach() {
47-
// FIXME: For some reason we can sometimes get here without the
48-
// refcount decreasing to 0. This is definitely a bug
49-
while (get_ref_count() != 0) { }
50-
5154
// Just take the lock to make sure that the thread that signaled
5255
// the detach_cond isn't still holding it
53-
scoped_lock with(detach_lock);
56+
scoped_lock with(ref_lock);
57+
I(task->thread, ref_count == 0);
5458
}
5559

5660
void rust_port::send(void *sptr) {

src/rt/rust_port.h

+9-7
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,17 @@
66
class port_detach_cond : public rust_cond { };
77

88
class rust_port : public kernel_owned<rust_port>, public rust_cond {
9+
private:
10+
// Protects ref_count and detach_cond
11+
lock_and_signal ref_lock;
12+
intptr_t ref_count;
13+
port_detach_cond detach_cond;
14+
915
public:
10-
RUST_ATOMIC_REFCOUNT();
16+
void ref();
17+
void deref();
1118

19+
public:
1220
rust_port_id id;
1321

1422
rust_kernel *kernel;
@@ -18,15 +26,9 @@ class rust_port : public kernel_owned<rust_port>, public rust_cond {
1826

1927
lock_and_signal lock;
2028

21-
private:
22-
// Protects blocking and signaling on detach_cond
23-
lock_and_signal detach_lock;
24-
port_detach_cond detach_cond;
25-
2629
public:
2730
rust_port(rust_task *task, size_t unit_sz);
2831
~rust_port();
29-
void delete_this();
3032

3133
void log_state();
3234
void send(void *sptr);

0 commit comments

Comments
 (0)