Added some locking to ports to prevent the case where two threads simultaneously wake up a task blocked on a certain port.

This commit is contained in:
Eric Holk 2011-06-21 15:10:55 -07:00 committed by Graydon Hoare
parent cb00befff0
commit 4d99bf9af2
3 changed files with 9 additions and 13 deletions

View file

@ -31,6 +31,7 @@ rust_chan::~rust_chan() {
void rust_chan::associate(maybe_proxy<rust_port> *port) { void rust_chan::associate(maybe_proxy<rust_port> *port) {
this->port = port; this->port = port;
if (port->is_proxy() == false) { if (port->is_proxy() == false) {
scoped_lock sync(port->referent()->lock);
LOG(task, task, LOG(task, task,
"associating chan: 0x%" PRIxPTR " with port: 0x%" PRIxPTR, "associating chan: 0x%" PRIxPTR " with port: 0x%" PRIxPTR,
this, port); this, port);
@ -49,6 +50,7 @@ void rust_chan::disassociate() {
A(task->dom, is_associated(), "Channel must be associated with a port."); A(task->dom, is_associated(), "Channel must be associated with a port.");
if (port->is_proxy() == false) { if (port->is_proxy() == false) {
scoped_lock sync(port->referent()->lock);
LOG(task, task, LOG(task, task,
"disassociating chan: 0x%" PRIxPTR " from port: 0x%" PRIxPTR, "disassociating chan: 0x%" PRIxPTR " from port: 0x%" PRIxPTR,
this, port->referent()); this, port->referent());
@ -81,6 +83,7 @@ void rust_chan::send(void *sptr) {
buffer.dequeue(NULL); buffer.dequeue(NULL);
} else { } else {
rust_port *target_port = port->referent(); rust_port *target_port = port->referent();
scoped_lock sync(target_port->lock);
if (target_port->task->blocked_on(target_port)) { if (target_port->task->blocked_on(target_port)) {
DLOG(dom, comm, "dequeued in rendezvous_ptr"); DLOG(dom, comm, "dequeued in rendezvous_ptr");
buffer.dequeue(target_port->task->rendezvous_ptr); buffer.dequeue(target_port->task->rendezvous_ptr);

View file

@ -13,6 +13,8 @@ public:
// Data sent to this port from remote tasks is buffered in this channel. // Data sent to this port from remote tasks is buffered in this channel.
rust_chan *remote_channel; rust_chan *remote_channel;
lock_and_signal lock;
rust_port(rust_task *task, size_t unit_sz); rust_port(rust_task *task, size_t unit_sz);
~rust_port(); ~rust_port();
void log_state(); void log_state();

View file

@ -170,10 +170,7 @@ rust_task::start(uintptr_t spawnee_fn,
ctx.call((void *)task_start_wrapper, a, sp); ctx.call((void *)task_start_wrapper, a, sp);
yield_timer.reset(0); yield_timer.reset(0);
{ transition(&dom->newborn_tasks, &dom->running_tasks);
scoped_lock sync(dom->scheduler_lock);
transition(&dom->newborn_tasks, &dom->running_tasks);
}
} }
void void
@ -408,6 +405,7 @@ rust_task::free(void *p, bool is_gc)
void void
rust_task::transition(rust_task_list *src, rust_task_list *dst) { rust_task::transition(rust_task_list *src, rust_task_list *dst) {
scoped_lock sync(dom->scheduler_lock);
DLOG(dom, task, DLOG(dom, task,
"task %s " PTR " state change '%s' -> '%s' while in '%s'", "task %s " PTR " state change '%s' -> '%s' while in '%s'",
name, (uintptr_t)this, src->name, dst->name, state->name); name, (uintptr_t)this, src->name, dst->name, state->name);
@ -424,10 +422,7 @@ rust_task::block(rust_cond *on, const char* name) {
A(dom, cond == NULL, "Cannot block an already blocked task."); A(dom, cond == NULL, "Cannot block an already blocked task.");
A(dom, on != NULL, "Cannot block on a NULL object."); A(dom, on != NULL, "Cannot block on a NULL object.");
{ transition(&dom->running_tasks, &dom->blocked_tasks);
scoped_lock sync(dom->scheduler_lock);
transition(&dom->running_tasks, &dom->blocked_tasks);
}
cond = on; cond = on;
cond_name = name; cond_name = name;
} }
@ -439,10 +434,7 @@ rust_task::wakeup(rust_cond *from) {
(uintptr_t) cond, (uintptr_t) from); (uintptr_t) cond, (uintptr_t) from);
A(dom, cond == from, "Cannot wake up blocked task on wrong condition."); A(dom, cond == from, "Cannot wake up blocked task on wrong condition.");
{ transition(&dom->blocked_tasks, &dom->running_tasks);
scoped_lock sync(dom->scheduler_lock);
transition(&dom->blocked_tasks, &dom->running_tasks);
}
I(dom, cond == from); I(dom, cond == from);
cond = NULL; cond = NULL;
cond_name = "none"; cond_name = "none";
@ -450,7 +442,6 @@ rust_task::wakeup(rust_cond *from) {
void void
rust_task::die() { rust_task::die() {
scoped_lock sync(dom->scheduler_lock);
transition(&dom->running_tasks, &dom->dead_tasks); transition(&dom->running_tasks, &dom->dead_tasks);
} }