Skip to content

Commit 44a6b24

Browse files
committed
---
yaml --- r: 143007 b: refs/heads/try2 c: 0101f35 h: refs/heads/master i: 143005: fd504bf 143003: fc026c4 142999: 80d9199 142991: a2dfae6 142975: 023901f v: v3
1 parent 7277bc4 commit 44a6b24

File tree

2 files changed

+96
-3
lines changed

2 files changed

+96
-3
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ refs/heads/snap-stage3: 78a7676898d9f80ab540c6df5d4c9ce35bb50463
55
refs/heads/try: 519addf6277dbafccbb4159db4b710c37eaa2ec5
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b
8-
refs/heads/try2: e80efe3fda506877b3fb7ff0df5d97dffb6a906f
8+
refs/heads/try2: 0101f35f276d0ef1ab841a179d01d0c66a18b38a
99
refs/heads/dist-snap: ba4081a5a8573875fed17545846f6f6902c8ba8d
1010
refs/tags/release-0.2: c870d2dffb391e14efb05aa27898f1f6333a9596
1111
refs/tags/release-0.3: b5f0d0f648d9a6153664837026ba1be43d3e2503

branches/try2/src/libstd/rt/kill.rs

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
1313
use cast;
1414
use cell::Cell;
15+
use either::{Either, Left, Right};
1516
use option::{Option, Some, None};
1617
use prelude::*;
1718
use rt::task::Task;
@@ -26,6 +27,16 @@ static KILL_RUNNING: uint = 0;
2627
static KILL_KILLED: uint = 1;
2728
static KILL_UNKILLABLE: uint = 2;
2829

30+
struct KillFlag(AtomicUint);
31+
type KillFlagHandle = UnsafeAtomicRcBox<KillFlag>;
32+
33+
/// A handle to a blocked task. Usually this means having the ~Task pointer by
34+
/// ownership, but if the task is killable, a killer can steal it at any time.
35+
pub enum BlockedTask {
36+
Unkillable(~Task),
37+
Killable(KillFlagHandle),
38+
}
39+
2940
// FIXME(#7544)(bblum): think about the cache efficiency of this
3041
struct KillHandleInner {
3142
// Is the task running, blocked, or killed? Possible values:
@@ -35,7 +46,7 @@ struct KillHandleInner {
3546
// This flag is refcounted because it may also be referenced by a blocking
3647
// concurrency primitive, used to wake the task normally, whose reference
3748
// may outlive the handle's if the task is killed.
38-
killed: UnsafeAtomicRcBox<AtomicUint>,
49+
killed: KillFlagHandle,
3950
// Has the task deferred kill signals? This flag guards the above one.
4051
// Possible values:
4152
// * KILL_RUNNING - Not unkillable, no kill pending.
@@ -76,11 +87,93 @@ pub struct Death {
7687
wont_sleep: int,
7788
}
7889

90+
impl Drop for KillFlag {
91+
// Letting a KillFlag with a task inside get dropped would leak the task.
92+
// We could free it here, but the task should get awoken by hand somehow.
93+
fn drop(&self) {
94+
match self.load(Acquire) {
95+
KILL_RUNNING | KILL_KILLED => { },
96+
_ => rtabort!("can't drop kill flag with a blocked task inside!"),
97+
}
98+
}
99+
}
100+
101+
impl BlockedTask {
102+
/// Returns Some if the task was successfully woken; None if already killed.
103+
pub fn wake(self) -> Option<~Task> {
104+
let mut this = self;
105+
match this {
106+
Unkillable(task) => Some(task),
107+
Killable(ref mut flag_arc) => {
108+
let flag = unsafe { &mut **flag_arc.get() };
109+
match flag.swap(KILL_RUNNING, SeqCst) {
110+
KILL_RUNNING => rtabort!("tried to wake an already-running task"),
111+
KILL_KILLED => None, // a killer stole it already
112+
task_ptr => Some(unsafe { cast::transmute(task_ptr) }),
113+
}
114+
}
115+
}
116+
}
117+
118+
/// Create a blocked task, unless the task was already killed.
119+
pub fn try_block(task: ~Task) -> Either<~Task, BlockedTask> {
120+
if task.death.unkillable > 0 { // FIXME(#7544): || self.indestructible
121+
Right(Unkillable(task))
122+
} else {
123+
rtassert!(task.death.kill_handle.is_some());
124+
unsafe {
125+
// FIXME(#7544) optimz
126+
let flag_arc = (*task.death.kill_handle.get_ref().get()).killed.clone();
127+
let flag = &mut **flag_arc.get();
128+
let task_ptr = cast::transmute(task);
129+
// Expect flag to contain RUNNING. If KILLED, it should stay KILLED.
130+
match flag.compare_and_swap(KILL_RUNNING, task_ptr, SeqCst) {
131+
KILL_RUNNING => Right(Killable(flag_arc)),
132+
KILL_KILLED => Left(cast::transmute(task_ptr)),
133+
x => rtabort!("can't block task! kill flag = %?", x),
134+
}
135+
}
136+
}
137+
}
138+
139+
/// Convert to an unsafe uint value. Useful for storing in a pipe's state flag.
140+
#[inline]
141+
pub unsafe fn cast_to_uint(self) -> uint {
142+
// Use the low bit to distinguish the enum variants, to save a second
143+
// allocation in the indestructible case.
144+
match self {
145+
Unkillable(task) => {
146+
let blocked_task_ptr: uint = cast::transmute(task);
147+
rtassert!(blocked_task_ptr & 0x1 == 0);
148+
blocked_task_ptr
149+
},
150+
Killable(flag_arc) => {
151+
let blocked_task_ptr: uint = cast::transmute(~flag_arc);
152+
rtassert!(blocked_task_ptr & 0x1 == 0);
153+
blocked_task_ptr | 0x1
154+
}
155+
}
156+
}
157+
158+
/// Convert from an unsafe uint value. Useful for retrieving a pipe's state flag.
159+
#[inline]
160+
pub unsafe fn cast_from_uint(blocked_task_ptr: uint) -> BlockedTask {
161+
if blocked_task_ptr & 0x1 == 0 {
162+
Unkillable(cast::transmute(blocked_task_ptr))
163+
} else {
164+
let ptr: ~KillFlagHandle = cast::transmute(blocked_task_ptr & !0x1);
165+
match ptr {
166+
~flag_arc => Killable(flag_arc)
167+
}
168+
}
169+
}
170+
}
171+
79172
impl KillHandle {
80173
pub fn new() -> KillHandle {
81174
KillHandle(UnsafeAtomicRcBox::new(KillHandleInner {
82175
// Linked failure fields
83-
killed: UnsafeAtomicRcBox::new(AtomicUint::new(KILL_RUNNING)),
176+
killed: UnsafeAtomicRcBox::new(KillFlag(AtomicUint::new(KILL_RUNNING))),
84177
unkillable: AtomicUint::new(KILL_RUNNING),
85178
// Exit code propagation fields
86179
any_child_failed: false,

0 commit comments

Comments
 (0)