Skip to content

Commit 343e9de

Browse files
committed
Proper locking with blocked_on()/wakeup() in rust_port. Closes #2787. Closes #1923.
1 parent b897696 commit 343e9de

5 files changed

+24
-22
lines changed

src/rt/rust_port.cpp

+15-13
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@ void rust_port::deref() {
2626
scoped_lock with(ref_lock);
2727
ref_count--;
2828
if (!ref_count) {
29+
// The port owner is waiting for the port to be detached (if it
30+
// hasn't already been killed)
31+
scoped_lock with(task->lifecycle_lock);
2932
if (task->blocked_on(&detach_cond)) {
30-
// The port owner is waiting for the port to be detached
31-
task->wakeup(&detach_cond);
33+
task->wakeup_inner(&detach_cond);
3234
}
3335
}
3436
}
@@ -64,12 +66,15 @@ void rust_port::send(void *sptr) {
6466
assert(!buffer.is_empty() &&
6567
"rust_chan::transmit with nothing to send.");
6668

67-
if (task->blocked_on(this)) {
68-
KLOG(kernel, comm, "dequeued in rendezvous_ptr");
69-
buffer.dequeue(task->rendezvous_ptr);
70-
task->rendezvous_ptr = 0;
71-
task->wakeup(this);
72-
did_rendezvous = true;
69+
{
70+
scoped_lock with(task->lifecycle_lock);
71+
if (task->blocked_on(this)) {
72+
KLOG(kernel, comm, "dequeued in rendezvous_ptr");
73+
buffer.dequeue(task->rendezvous_ptr);
74+
task->rendezvous_ptr = 0;
75+
task->wakeup_inner(this);
76+
did_rendezvous = true;
77+
}
7378
}
7479
}
7580

@@ -78,11 +83,8 @@ void rust_port::send(void *sptr) {
7883
// it may be waiting on a group of ports
7984

8085
rust_port_selector *port_selector = task->get_port_selector();
81-
// This check is not definitive. The port selector will take a lock
82-
// and check again whether the task is still blocked.
83-
if (task->blocked_on(port_selector)) {
84-
port_selector->msg_sent_on(this);
85-
}
86+
// The port selector will check if the task is blocked, not us.
87+
port_selector->msg_sent_on(this);
8688
}
8789
}
8890

src/rt/rust_port_selector.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ rust_port_selector::msg_sent_on(rust_port *port) {
7575

7676
// Prevent two ports from trying to wake up the task
7777
// simultaneously
78-
scoped_lock with(rendezvous_lock);
78+
scoped_lock with(task->lifecycle_lock);
7979

8080
if (task->blocked_on(this)) {
8181
for (size_t i = 0; i < n_ports; i++) {
@@ -85,7 +85,7 @@ rust_port_selector::msg_sent_on(rust_port *port) {
8585
n_ports = 0;
8686
*task->rendezvous_ptr = (uintptr_t) port;
8787
task->rendezvous_ptr = NULL;
88-
task->wakeup(this);
88+
task->wakeup_inner(this);
8989
return;
9090
}
9191
}

src/rt/rust_port_selector.h

-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ class rust_port_selector : public rust_cond {
99
private:
1010
rust_port **ports;
1111
size_t n_ports;
12-
lock_and_signal rendezvous_lock;
1312

1413
public:
1514
rust_port_selector();

src/rt/rust_task.cpp

+3-4
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ rust_task::must_fail_from_being_killed_inner() {
243243
// Only run this on the rust stack
244244
void
245245
rust_task::yield(bool *killed) {
246-
// FIXME (#2787): clean this up
246+
// FIXME (#2875): clean this up
247247
if (must_fail_from_being_killed()) {
248248
{
249249
scoped_lock with(lifecycle_lock);
@@ -346,12 +346,11 @@ void rust_task::assert_is_running()
346346
assert(state == task_state_running);
347347
}
348348

349-
// FIXME (#2851, #2787): This is only used by rust_port/rust_port selector,
350-
// and is inherently racy. Get rid of it.
349+
// FIXME (#2851) Remove this code when rust_port goes away?
351350
bool
352351
rust_task::blocked_on(rust_cond *on)
353352
{
354-
scoped_lock with(lifecycle_lock);
353+
lifecycle_lock.must_have_lock();
355354
return cond == on;
356355
}
357356

src/rt/rust_task.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,11 @@ rust_task : public kernel_owned<rust_task>
226226
char const *file,
227227
size_t line);
228228

229+
friend class rust_port;
230+
friend class rust_port_selector;
229231
bool block_inner(rust_cond *on, const char* name);
230232
void wakeup_inner(rust_cond *from);
233+
bool blocked_on(rust_cond *cond);
231234

232235
public:
233236

@@ -243,7 +246,6 @@ rust_task : public kernel_owned<rust_task>
243246
void *args);
244247
void start();
245248
void assert_is_running();
246-
bool blocked_on(rust_cond *cond); // FIXME (#2851) Get rid of this.
247249

248250
void *malloc(size_t sz, const char *tag, type_desc *td=0);
249251
void *realloc(void *data, size_t sz);
@@ -435,7 +437,7 @@ rust_task::call_on_rust_stack(void *args, void *fn_ptr) {
435437

436438
bool had_reentered_rust_stack = reentered_rust_stack;
437439
{
438-
// FIXME (#2787) This must be racy. Figure it out.
440+
// FIXME (#2875) This must be racy. Figure it out.
439441
scoped_lock with(lifecycle_lock);
440442
reentered_rust_stack = true;
441443
}

0 commit comments

Comments
 (0)