Skip to content

Commit 45ea442

Browse files
committed
---
yaml --- r: 64503 b: refs/heads/snap-stage3 c: 6882508 h: refs/heads/master i: 64501: 5b2a1f8 64499: 64820d9 64495: 36a5c89 v: v3
1 parent d848000 commit 45ea442

File tree

6 files changed

+80
-23
lines changed

6 files changed

+80
-23
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
refs/heads/master: 2d28d645422c1617be58c8ca7ad9a457264ca850
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
4-
refs/heads/snap-stage3: 52ca256d7be99dafa81c531bf1fc6ec2e2a508b9
4+
refs/heads/snap-stage3: 6882508b6f9be4d4537ee863fb42f1ae862045a8
55
refs/heads/try: 7b78b52e602bb3ea8174f9b2006bff3315f03ef9
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b

branches/snap-stage3/src/libstd/rt/kill.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,18 @@ struct KillHandleInner {
3737
#[deriving(Clone)]
3838
pub struct KillHandle(UnsafeAtomicRcBox<KillHandleInner>);
3939

40+
/// Per-task state related to task death, killing, failure, etc.
41+
pub struct Death {
42+
// Shared among this task, its watched children, and any linked tasks who
43+
// might kill it. This is optional so we can take it by-value at exit time.
44+
kill_handle: Option<KillHandle>,
45+
// Handle to a watching parent, if we have one, for exit code propagation.
46+
watching_parent: Option<KillHandle>,
47+
// Action to be done with the exit code. If set, also makes the task wait
48+
// until all its watched children exit before collecting the status.
49+
on_exit: Option<~fn(bool)>,
50+
}
51+
4052
impl KillHandle {
4153
pub fn new() -> KillHandle {
4254
KillHandle(UnsafeAtomicRcBox::new(KillHandleInner {
@@ -126,3 +138,58 @@ impl KillHandle {
126138
}
127139
}
128140

141+
impl Death {
142+
pub fn new() -> Death {
143+
Death {
144+
kill_handle: Some(KillHandle::new()),
145+
watching_parent: None,
146+
on_exit: None,
147+
}
148+
}
149+
150+
pub fn new_child(&self) -> Death {
151+
// FIXME(#7327)
152+
Death {
153+
kill_handle: Some(KillHandle::new()),
154+
watching_parent: self.kill_handle.clone(),
155+
on_exit: None,
156+
}
157+
}
158+
159+
/// Collect failure exit codes from children and propagate them to a parent.
160+
pub fn collect_failure(&mut self, mut success: bool) {
161+
// Step 1. Decide if we need to collect child failures synchronously.
162+
do self.on_exit.take_map |on_exit| {
163+
if success {
164+
// We succeeded, but our children might not. Need to wait for them.
165+
let mut inner = unsafe { self.kill_handle.take_unwrap().unwrap() };
166+
if inner.any_child_failed {
167+
success = false;
168+
} else {
169+
// Lockless access to tombstones protected by unwrap barrier.
170+
success = inner.child_tombstones.take_map_default(true, |f| f());
171+
}
172+
}
173+
on_exit(success);
174+
};
175+
176+
// Step 2. Possibly alert possibly-watching parent to failure status.
177+
// Note that as soon as parent_handle goes out of scope, the parent
178+
// can successfully unwrap its handle and collect our reported status.
179+
do self.watching_parent.take_map |mut parent_handle| {
180+
if success {
181+
// Our handle might be None if we had an exit callback, and
182+
// already unwrapped it. But 'success' being true means no
183+
// child failed, so there's nothing to do (see below case).
184+
do self.kill_handle.take_map |own_handle| {
185+
own_handle.reparent_children_to(&mut parent_handle);
186+
};
187+
} else {
188+
// Can inform watching parent immediately that we failed.
189+
// (Note the importance of non-failing tasks NOT writing
190+
// 'false', which could obscure another task's failure.)
191+
parent_handle.notify_immediate_failure();
192+
}
193+
};
194+
}
195+
}

branches/snap-stage3/src/libstd/rt/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ pub fn run(main: ~fn()) -> int {
280280
let main_cell = Cell::new(main);
281281
let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool,
282282
main_cell.take());
283-
main_task.on_exit = Some(on_exit);
283+
main_task.death.on_exit = Some(on_exit);
284284
scheds[0].enqueue_task(main_task);
285285

286286
// Run each scheduler in a thread.

branches/snap-stage3/src/libstd/rt/task.rs

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use libc::{c_void, uintptr_t};
2020
use ptr;
2121
use prelude::*;
2222
use option::{Option, Some, None};
23+
use rt::kill::Death;
2324
use rt::local::Local;
2425
use rt::logging::StdErrLogger;
2526
use super::local_heap::LocalHeap;
@@ -36,8 +37,8 @@ pub struct Task {
3637
logger: StdErrLogger,
3738
unwinder: Unwinder,
3839
home: Option<SchedHome>,
39-
join_latch: Option<~JoinLatch>,
40-
on_exit: Option<~fn(bool)>,
40+
death: Death,
41+
join_latch: Option<~JoinLatch>, // FIXME(#7544) remove
4142
destroyed: bool,
4243
coroutine: Option<~Coroutine>
4344
}
@@ -86,8 +87,8 @@ impl Task {
8687
logger: StdErrLogger,
8788
unwinder: Unwinder { unwinding: false },
8889
home: Some(home),
90+
death: Death::new(),
8991
join_latch: Some(JoinLatch::new_root()),
90-
on_exit: None,
9192
destroyed: false,
9293
coroutine: Some(~Coroutine::new(stack_pool, start))
9394
}
@@ -104,8 +105,9 @@ impl Task {
104105
logger: StdErrLogger,
105106
home: Some(home),
106107
unwinder: Unwinder { unwinding: false },
108+
// FIXME(#7544) make watching optional
109+
death: self.death.new_child(),
107110
join_latch: Some(self.join_latch.get_mut_ref().new_child()),
108-
on_exit: None,
109111
destroyed: false,
110112
coroutine: Some(~Coroutine::new(stack_pool, start))
111113
}
@@ -123,20 +125,8 @@ impl Task {
123125
}
124126

125127
self.unwinder.try(f);
128+
self.death.collect_failure(!self.unwinder.unwinding);
126129
self.destroy();
127-
128-
// Wait for children. Possibly report the exit status.
129-
let local_success = !self.unwinder.unwinding;
130-
let join_latch = self.join_latch.take_unwrap();
131-
match self.on_exit {
132-
Some(ref on_exit) => {
133-
let success = join_latch.wait(local_success);
134-
(*on_exit)(success);
135-
}
136-
None => {
137-
join_latch.release(local_success);
138-
}
139-
}
140130
}
141131

142132
/// must be called manually before finalization to clean up

branches/snap-stage3/src/libstd/rt/test.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ pub fn run_in_newsched_task(f: ~fn()) {
5151
let mut task = ~Task::new_root(&mut sched.stack_pool,
5252
f.take());
5353
rtdebug!("newsched_task: %x", to_uint(task));
54-
task.on_exit = Some(on_exit);
54+
task.death.on_exit = Some(on_exit);
5555
sched.enqueue_task(task);
5656
sched.run();
5757
}
@@ -109,7 +109,7 @@ pub fn run_in_mt_newsched_task(f: ~fn()) {
109109
};
110110
let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool,
111111
f_cell.take());
112-
main_task.on_exit = Some(on_exit);
112+
main_task.death.on_exit = Some(on_exit);
113113
scheds[0].enqueue_task(main_task);
114114

115115
let mut threads = ~[];
@@ -280,7 +280,7 @@ pub fn spawntask_try(f: ~fn()) -> Result<(), ()> {
280280
f.take())
281281
}
282282
};
283-
new_task.on_exit = Some(on_exit);
283+
new_task.death.on_exit = Some(on_exit);
284284

285285
let sched = Local::take::<Scheduler>();
286286
do sched.switch_running_tasks_and_then(new_task) |sched, old_task| {

branches/snap-stage3/src/libstd/task/spawn.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,7 @@ fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) {
616616
if success { Success } else { Failure }
617617
)
618618
};
619-
task.on_exit = Some(on_exit);
619+
task.death.on_exit = Some(on_exit);
620620
}
621621

622622
rtdebug!("spawn about to take scheduler");

0 commit comments

Comments
 (0)