Fixed two races.

The first is that the memory_region destructor would complain there is
still an outstanding allocation. This is because circular_buffer from
rust_chan wasn't refing its task, so the task was being destructed too
soon.

The second was where the program could deadlock while joining a
task. The target task would die in the time between checking whether
the task should block and then actually blocking. The fix is to use
the target task's lock.
This commit is contained in:
Eric Holk 2011-07-07 18:18:52 -07:00
parent 2d57b25f6b
commit 4739953b84
3 changed files with 10 additions and 0 deletions

View File

@ -20,6 +20,7 @@ circular_buffer::circular_buffer(rust_task *task, size_t unit_sz) :
_buffer_sz, _unread, this);
A(sched, _buffer, "Failed to allocate buffer.");
task->ref();
}
circular_buffer::~circular_buffer() {
@ -28,6 +29,7 @@ circular_buffer::~circular_buffer() {
W(sched, _unread == 0,
"freeing circular_buffer with %d unread bytes", _unread);
task->free(_buffer);
--task->ref_count;
}
size_t

View File

@ -393,11 +393,16 @@ task_yield(rust_task *task) {
extern "C" CDECL void
task_join(rust_task *task, rust_task *join_task) {
// If the other task is already dying, we don't have to wait for it.
join_task->lock.lock();
if (join_task->dead() == false) {
join_task->tasks_waiting_to_join.push(task);
task->block(join_task, "joining local task");
join_task->lock.unlock();
task->yield(2);
}
else {
join_task->lock.unlock();
}
}
/* Debug builtins for std.dbg. */

View File

@ -118,12 +118,15 @@ void task_start_wrapper(spawn_args *a)
a->f(&rval, task, a->a3, a->a4);
LOG(task, task, "task exited with value %d", rval);
LOG(task, task, "task ref_count: %d", task->ref_count);
A(task->sched, task->ref_count >= 0,
"Task ref_count should not be negative on exit!");
task->die();
task->lock.lock();
task->notify_tasks_waiting_to_join();
task->lock.unlock();
task->yield(1);
}