Proper locking with blocked_on()/wakeup() in rust_port. Closes #2787. Closes #1923.

This commit is contained in:
Ben Blum
2012-07-11 20:00:58 -04:00
parent b897696a3a
commit 343e9de8ef
5 changed files with 24 additions and 22 deletions

View File

@@ -26,9 +26,11 @@ void rust_port::deref() {
scoped_lock with(ref_lock); scoped_lock with(ref_lock);
ref_count--; ref_count--;
if (!ref_count) { if (!ref_count) {
// The port owner is waiting for the port to be detached (if it
// hasn't already been killed)
scoped_lock with(task->lifecycle_lock);
if (task->blocked_on(&detach_cond)) { if (task->blocked_on(&detach_cond)) {
// The port owner is waiting for the port to be detached task->wakeup_inner(&detach_cond);
task->wakeup(&detach_cond);
} }
} }
} }
@@ -64,26 +66,26 @@ void rust_port::send(void *sptr) {
assert(!buffer.is_empty() && assert(!buffer.is_empty() &&
"rust_chan::transmit with nothing to send."); "rust_chan::transmit with nothing to send.");
{
scoped_lock with(task->lifecycle_lock);
if (task->blocked_on(this)) { if (task->blocked_on(this)) {
KLOG(kernel, comm, "dequeued in rendezvous_ptr"); KLOG(kernel, comm, "dequeued in rendezvous_ptr");
buffer.dequeue(task->rendezvous_ptr); buffer.dequeue(task->rendezvous_ptr);
task->rendezvous_ptr = 0; task->rendezvous_ptr = 0;
task->wakeup(this); task->wakeup_inner(this);
did_rendezvous = true; did_rendezvous = true;
} }
} }
}
if (!did_rendezvous) { if (!did_rendezvous) {
// If the task wasn't waiting specifically on this port, // If the task wasn't waiting specifically on this port,
// it may be waiting on a group of ports // it may be waiting on a group of ports
rust_port_selector *port_selector = task->get_port_selector(); rust_port_selector *port_selector = task->get_port_selector();
// This check is not definitive. The port selector will take a lock // The port selector will check if the task is blocked, not us.
// and check again whether the task is still blocked.
if (task->blocked_on(port_selector)) {
port_selector->msg_sent_on(this); port_selector->msg_sent_on(this);
} }
}
} }
void rust_port::receive(void *dptr, uintptr_t *yield) { void rust_port::receive(void *dptr, uintptr_t *yield) {

View File

@@ -75,7 +75,7 @@ rust_port_selector::msg_sent_on(rust_port *port) {
// Prevent two ports from trying to wake up the task // Prevent two ports from trying to wake up the task
// simultaneously // simultaneously
scoped_lock with(rendezvous_lock); scoped_lock with(task->lifecycle_lock);
if (task->blocked_on(this)) { if (task->blocked_on(this)) {
for (size_t i = 0; i < n_ports; i++) { for (size_t i = 0; i < n_ports; i++) {
@@ -85,7 +85,7 @@ rust_port_selector::msg_sent_on(rust_port *port) {
n_ports = 0; n_ports = 0;
*task->rendezvous_ptr = (uintptr_t) port; *task->rendezvous_ptr = (uintptr_t) port;
task->rendezvous_ptr = NULL; task->rendezvous_ptr = NULL;
task->wakeup(this); task->wakeup_inner(this);
return; return;
} }
} }

View File

@@ -9,7 +9,6 @@ class rust_port_selector : public rust_cond {
private: private:
rust_port **ports; rust_port **ports;
size_t n_ports; size_t n_ports;
lock_and_signal rendezvous_lock;
public: public:
rust_port_selector(); rust_port_selector();

View File

@@ -243,7 +243,7 @@ rust_task::must_fail_from_being_killed_inner() {
// Only run this on the rust stack // Only run this on the rust stack
void void
rust_task::yield(bool *killed) { rust_task::yield(bool *killed) {
// FIXME (#2787): clean this up // FIXME (#2875): clean this up
if (must_fail_from_being_killed()) { if (must_fail_from_being_killed()) {
{ {
scoped_lock with(lifecycle_lock); scoped_lock with(lifecycle_lock);
@@ -346,12 +346,11 @@ void rust_task::assert_is_running()
assert(state == task_state_running); assert(state == task_state_running);
} }
// FIXME (#2851, #2787): This is only used by rust_port/rust_port selector, // FIXME (#2851) Remove this code when rust_port goes away?
// and is inherently racy. Get rid of it.
bool bool
rust_task::blocked_on(rust_cond *on) rust_task::blocked_on(rust_cond *on)
{ {
scoped_lock with(lifecycle_lock); lifecycle_lock.must_have_lock();
return cond == on; return cond == on;
} }

View File

@@ -226,8 +226,11 @@ private:
char const *file, char const *file,
size_t line); size_t line);
friend class rust_port;
friend class rust_port_selector;
bool block_inner(rust_cond *on, const char* name); bool block_inner(rust_cond *on, const char* name);
void wakeup_inner(rust_cond *from); void wakeup_inner(rust_cond *from);
bool blocked_on(rust_cond *cond);
public: public:
@@ -243,7 +246,6 @@ public:
void *args); void *args);
void start(); void start();
void assert_is_running(); void assert_is_running();
bool blocked_on(rust_cond *cond); // FIXME (#2851) Get rid of this.
void *malloc(size_t sz, const char *tag, type_desc *td=0); void *malloc(size_t sz, const char *tag, type_desc *td=0);
void *realloc(void *data, size_t sz); void *realloc(void *data, size_t sz);
@@ -435,7 +437,7 @@ rust_task::call_on_rust_stack(void *args, void *fn_ptr) {
bool had_reentered_rust_stack = reentered_rust_stack; bool had_reentered_rust_stack = reentered_rust_stack;
{ {
// FIXME (#2787) This must be racy. Figure it out. // FIXME (#2875) This must be racy. Figure it out.
scoped_lock with(lifecycle_lock); scoped_lock with(lifecycle_lock);
reentered_rust_stack = true; reentered_rust_stack = true;
} }