Make failure propagation to dead parents work

The failure will basically go 'through' the dead parent and continue
propagating the failure (as if the child was reparented).
This commit is contained in:
Brian Anderson 2011-09-14 15:26:59 -07:00
parent 6dcd0a9b5e
commit 103197bc42
5 changed files with 81 additions and 3 deletions

View file

@ -273,6 +273,7 @@ void
rust_task::kill() {
if (dead()) {
// Task is already dead, can't kill what's already dead.
fail_parent();
return;
}
@ -308,6 +309,14 @@ rust_task::conclude_failure() {
die();
// Unblock the task so it can unwind.
unblock();
fail_parent();
failed = true;
notify_tasks_waiting_to_join();
yield(4);
}
void
rust_task::fail_parent() {
if (supervisor) {
DLOG(sched, task,
"task %s @0x%" PRIxPTR
@ -318,9 +327,6 @@ rust_task::conclude_failure() {
// FIXME: implement unwinding again.
if (NULL == supervisor && propagate_failure)
sched->fail();
failed = true;
notify_tasks_waiting_to_join();
yield(4);
}
void

View file

@ -158,6 +158,7 @@ rust_task : public kernel_owned<rust_task>, rust_cond
// Fail self, assuming caller-on-stack is this task.
void fail();
void conclude_failure();
void fail_parent();
// Disconnect from our supervisor.
void unsupervise();

View file

@ -0,0 +1,17 @@
// -*- rust -*-
// error-pattern:fail
use std;
import std::task;
import std::comm::chan;
import std::comm::port;
import std::comm::recv;
fn child() { fail; }
fn main() {
let p = port::<int>();
let f = child;
task::spawn(f);
task::yield();
}

View file

@ -0,0 +1,23 @@
// -*- rust -*-
// error-pattern:fail
use std;
import std::task;
import std::comm::port;
import std::comm::recv;
fn grandchild() { fail; }
fn child() {
let p = port::<int>();
let f = grandchild;
task::spawn(f);
let x = recv(p);
}
fn main() {
let p = port::<int>();
let f = child;
task::spawn(f);
let x = recv(p);
}

View file

@ -0,0 +1,31 @@
// -*- rust -*-
// xfail-test
// error-pattern:1 == 2
use std;
import std::task;
import std::comm::chan;
import std::comm::port;
import std::comm::recv;
fn child() { assert (1 == 2); }
fn parent() {
let p = port::<int>();
let f = child;
task::spawn(f);
let x = recv(p);
}
// This task is not linked to the failure chain, but since the other
// tasks are going to fail the kernel, this one will fail too
fn sleeper() {
let p = port::<int>();
let x = recv(p);
}
fn main() {
let f = parent;
let g = sleeper;
task::spawn(f);
task::spawn(g);
}