Handle failure conditions correctly in pipes.
This commit is contained in:
parent
d07e537fc3
commit
26e6eb3d14
6 changed files with 48 additions and 19 deletions
|
@ -47,7 +47,7 @@ extern mod rustrt {
|
||||||
#[rust_stack]
|
#[rust_stack]
|
||||||
fn task_clear_event_reject(task: *rust_task);
|
fn task_clear_event_reject(task: *rust_task);
|
||||||
|
|
||||||
fn task_wait_event(this: *rust_task) -> *libc::c_void;
|
fn task_wait_event(this: *rust_task, killed: &mut bool) -> *libc::c_void;
|
||||||
fn task_signal_event(target: *rust_task, event: *libc::c_void);
|
fn task_signal_event(target: *rust_task, event: *libc::c_void);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +57,16 @@ unsafe fn uniquify<T>(x: *T) -> ~T {
|
||||||
unsafe { unsafe::reinterpret_cast(x) }
|
unsafe { unsafe::reinterpret_cast(x) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn wait_event(this: *rust_task) -> *libc::c_void {
|
||||||
|
let mut killed = false;
|
||||||
|
|
||||||
|
let res = rustrt::task_wait_event(this, &mut killed);
|
||||||
|
if killed && !task::failing() {
|
||||||
|
fail "killed"
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
fn swap_state_acq(&dst: state, src: state) -> state {
|
fn swap_state_acq(&dst: state, src: state) -> state {
|
||||||
unsafe {
|
unsafe {
|
||||||
reinterpret_cast(rusti::atomic_xchng_acq(
|
reinterpret_cast(rusti::atomic_xchng_acq(
|
||||||
|
@ -113,23 +123,23 @@ fn recv<T: send>(-p: recv_packet<T>) -> option<T> {
|
||||||
let this = rustrt::rust_get_task();
|
let this = rustrt::rust_get_task();
|
||||||
rustrt::task_clear_event_reject(this);
|
rustrt::task_clear_event_reject(this);
|
||||||
p.header.blocked_task = some(this);
|
p.header.blocked_task = some(this);
|
||||||
|
let mut first = true;
|
||||||
loop {
|
loop {
|
||||||
|
rustrt::task_clear_event_reject(this);
|
||||||
let old_state = swap_state_acq(p.header.state,
|
let old_state = swap_state_acq(p.header.state,
|
||||||
blocked);
|
blocked);
|
||||||
#debug("%?", old_state);
|
#debug("%?", old_state);
|
||||||
alt old_state {
|
alt old_state {
|
||||||
empty {
|
empty {
|
||||||
#debug("no data available on %?, going to sleep.", p_);
|
#debug("no data available on %?, going to sleep.", p_);
|
||||||
rustrt::task_wait_event(this);
|
wait_event(this);
|
||||||
#debug("woke up, p.state = %?", p.header.state);
|
#debug("woke up, p.state = %?", p.header.state);
|
||||||
if p.header.state == full {
|
}
|
||||||
let mut payload = none;
|
blocked {
|
||||||
payload <-> (*p).payload;
|
if first {
|
||||||
p.header.state = terminated;
|
fail "blocking on already blocked packet"
|
||||||
ret some(option::unwrap(payload))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
blocked { fail "blocking on already blocked packet" }
|
|
||||||
full {
|
full {
|
||||||
let mut payload = none;
|
let mut payload = none;
|
||||||
payload <-> (*p).payload;
|
payload <-> (*p).payload;
|
||||||
|
@ -141,11 +151,12 @@ fn recv<T: send>(-p: recv_packet<T>) -> option<T> {
|
||||||
ret none;
|
ret none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
first = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if messages are available.
|
/// Returns true if messages are available.
|
||||||
fn peek<T: send>(p: recv_packet<T>) -> bool {
|
pure fn peek<T: send>(p: recv_packet<T>) -> bool {
|
||||||
alt p.header().state {
|
alt p.header().state {
|
||||||
empty { false }
|
empty { false }
|
||||||
blocked { fail "peeking on blocked packet" }
|
blocked { fail "peeking on blocked packet" }
|
||||||
|
@ -236,7 +247,7 @@ fn wait_many(pkts: ~[&a.packet_header]) -> uint {
|
||||||
|
|
||||||
while !data_avail {
|
while !data_avail {
|
||||||
#debug("sleeping on %? packets", pkts.len());
|
#debug("sleeping on %? packets", pkts.len());
|
||||||
let event = rustrt::task_wait_event(this) as *packet_header;
|
let event = wait_event(this) as *packet_header;
|
||||||
let pos = vec::position(pkts, |p| ptr::addr_of(*p) == event);
|
let pos = vec::position(pkts, |p| ptr::addr_of(*p) == event);
|
||||||
|
|
||||||
alt pos {
|
alt pos {
|
||||||
|
@ -356,7 +367,7 @@ class recv_packet<T: send> {
|
||||||
option::unwrap(p)
|
option::unwrap(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn header() -> &self.packet_header {
|
pure fn header() -> &self.packet_header {
|
||||||
alt self.p {
|
alt self.p {
|
||||||
some(packet) {
|
some(packet) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -46,6 +46,7 @@ export future_result;
|
||||||
export future_task;
|
export future_task;
|
||||||
export unsupervise;
|
export unsupervise;
|
||||||
export run_listener;
|
export run_listener;
|
||||||
|
export run_with;
|
||||||
|
|
||||||
export spawn;
|
export spawn;
|
||||||
export spawn_with;
|
export spawn_with;
|
||||||
|
|
|
@ -930,11 +930,11 @@ task_clear_event_reject(rust_task *task) {
|
||||||
// Waits on an event, returning the pointer to the event that unblocked this
|
// Waits on an event, returning the pointer to the event that unblocked this
|
||||||
// task.
|
// task.
|
||||||
extern "C" void *
|
extern "C" void *
|
||||||
task_wait_event(rust_task *task) {
|
task_wait_event(rust_task *task, bool *killed) {
|
||||||
// TODO: we should assert that the passed in task is the currently running
|
// TODO: we should assert that the passed in task is the currently running
|
||||||
// task. We wouldn't want to wait some other task.
|
// task. We wouldn't want to wait some other task.
|
||||||
|
|
||||||
return task->wait_event();
|
return task->wait_event(killed);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void
|
extern "C" void
|
||||||
|
|
|
@ -713,16 +713,14 @@ rust_task::allow_kill() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
rust_task::wait_event() {
|
rust_task::wait_event(bool *killed) {
|
||||||
scoped_lock with(state_lock);
|
scoped_lock with(state_lock);
|
||||||
|
|
||||||
if(!event_reject) {
|
if(!event_reject) {
|
||||||
block_locked(&event_cond, "waiting on event");
|
block_locked(&event_cond, "waiting on event");
|
||||||
bool killed = false;
|
|
||||||
state_lock.unlock();
|
state_lock.unlock();
|
||||||
yield(&killed);
|
yield(killed);
|
||||||
state_lock.lock();
|
state_lock.lock();
|
||||||
// TODO: what is the right thing to do if we are killed?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
event_reject = false;
|
event_reject = false;
|
||||||
|
|
|
@ -316,7 +316,7 @@ public:
|
||||||
this->event_reject = false;
|
this->event_reject = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *wait_event();
|
void *wait_event(bool *killed);
|
||||||
void signal_event(void *event);
|
void signal_event(void *event);
|
||||||
|
|
||||||
void cleanup_after_turn();
|
void cleanup_after_turn();
|
||||||
|
|
|
@ -26,5 +26,24 @@ fn main() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
sleep(iotask, 1000);
|
sleep(iotask, 100);
|
||||||
|
|
||||||
|
let b = task::builder();
|
||||||
|
task::unsupervise(b);
|
||||||
|
task::run(b, failtest);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the right thing happens during failure.
|
||||||
|
fn failtest() {
|
||||||
|
let iotask = uv::global_loop::get();
|
||||||
|
|
||||||
|
let (c, p) = oneshot::init();
|
||||||
|
|
||||||
|
do task::spawn_with(c) |_c| {
|
||||||
|
fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
#error("%?", recv(p));
|
||||||
|
// make sure we get killed if we missed it in the receive.
|
||||||
|
loop { task::yield() }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue