Skip to content

Commit acf2d20

Browse files
committed
core: add previous-handler save and restore for proper nesting.
1 parent 754704e commit acf2d20

File tree

1 file changed

+78
-16
lines changed

1 file changed

+78
-16
lines changed

src/libcore/condition.rs

Lines changed: 78 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@ struct Condition {
66
}
77

88
struct Handler {
9-
// Handler should link to previous handler and
10-
// reinstall it when popped.
11-
handle: RustClosure
9+
handle: RustClosure,
10+
prev: Option<@Handler>
1211
}
1312

1413

@@ -21,7 +20,17 @@ struct PopHandler {
2120
cond: &Condition,
2221
drop {
2322
unsafe {
24-
task::local_data::local_data_pop(self.cond.key);
23+
debug!("PopHandler: popping handler from TLS");
24+
match task::local_data::local_data_pop(self.cond.key) {
25+
None => (),
26+
Some(h) => {
27+
match h.prev {
28+
None => (),
29+
Some(p) =>
30+
task::local_data::local_data_set(self.cond.key, p)
31+
}
32+
}
33+
}
2534
}
2635
}
2736
}
@@ -31,23 +40,28 @@ struct HandleBlock {
3140
handler: @Handler,
3241
drop {
3342
unsafe {
43+
debug!("HandleBlock: pushing handler to TLS");
3444
task::local_data::local_data_set(self.pb.cond.key,
3545
self.handler);
3646
let _pop = PopHandler { cond: self.pb.cond };
3747
// transmutation to avoid copying non-copyable, should
3848
// be fixable by tracking closure pointees in regionck.
3949
let f : &fn() = ::cast::transmute(self.pb.inner);
50+
debug!("HandleBlock: invoking protected code");
4051
f();
52+
debug!("HandleBlock: returned from protected code");
4153
}
4254
}
4355
}
4456

4557
impl ProtectBlock {
4658
fn handle<T, U: Copy>(&self, h: &self/fn(&T) ->U) -> HandleBlock/&self {
4759
unsafe {
60+
debug!("ProtectBlock.handle: setting up handler block");
4861
let p : *RustClosure = ::cast::transmute(&h);
62+
let prev = task::local_data::local_data_get(self.cond.key);
4963
HandleBlock { pb: self,
50-
handler: @Handler{handle: *p} }
64+
handler: @Handler{handle: *p, prev: prev} }
5165
}
5266
}
5367
}
@@ -59,17 +73,23 @@ impl Condition {
5973
unsafe {
6074
// transmutation to avoid copying non-copyable, should
6175
// be fixable by tracking closure pointees in regionck.
76+
debug!("Condition.protect: setting up protected block");
6277
let p : *RustClosure = ::cast::transmute(&inner);
6378
ProtectBlock { cond: self,
64-
inner: *p } }
79+
inner: *p }
80+
}
6581
}
6682

6783
fn raise<T, U: Copy>(t:&T) -> U {
6884
unsafe {
6985
match task::local_data::local_data_get(self.key) {
70-
None => fail,
86+
None => {
87+
debug!("Condition.raise: found no handler");
88+
fail
89+
}
90+
7191
Some(handler) => {
72-
io::println("got handler");
92+
debug!("Condition.raise: found handler");
7393
let f : &fn(&T) -> U = ::cast::transmute(handler.handle);
7494
f(t)
7595
}
@@ -79,39 +99,81 @@ impl Condition {
7999
}
80100

81101

82-
#[test]
102+
#[cfg(test)]
83103
fn happiness_key(_x: @Handler) { }
84104

85-
#[test]
105+
#[cfg(test)]
86106
fn sadness_key(_x: @Handler) { }
87107

88-
#[test]
108+
#[cfg(test)]
89109
fn trouble(i: int) {
90110
// Condition should work as a const, just limitations in consts.
91111
let sadness_condition : Condition = Condition { key: sadness_key };
92-
io::println("raising");
112+
debug!("trouble: raising conition");
93113
let j = sadness_condition.raise(&i);
94-
io::println(fmt!("handler recovered with %d", j));
114+
debug!("trouble: handler recovered with %d", j);
95115
}
96116

97117
#[test]
98-
fn test() {
118+
fn test1() {
99119

100120
let sadness_condition : Condition = Condition { key: sadness_key };
101121

102122
let mut i = 10;
103123

104124
let b = do sadness_condition.protect {
105-
io::println("in protected block");
125+
debug!("test1: in protected block");
106126
trouble(1);
107127
trouble(2);
108128
trouble(3);
109129
};
110130

111131
do b.handle |j| {
132+
debug!("test1: in handler");
112133
i += *j;
113134
i
114135
};
115136

116137
assert i == 16;
117-
}
138+
}
139+
#[cfg(test)]
140+
fn nested_test_inner() {
141+
let sadness_condition : Condition = Condition { key: sadness_key };
142+
143+
let mut inner_trapped = false;
144+
145+
let b = do sadness_condition.protect {
146+
debug!("nested_test_inner: in protected block");
147+
trouble(1);
148+
};
149+
150+
do b.handle |_j:&int| {
151+
debug!("nested_test_inner: in handler");
152+
inner_trapped = true;
153+
0
154+
};
155+
156+
assert inner_trapped;
157+
}
158+
159+
#[test]
160+
fn nested_test_outer() {
161+
162+
let sadness_condition : Condition = Condition { key: sadness_key };
163+
164+
let mut outer_trapped = false;
165+
166+
let b = do sadness_condition.protect {
167+
debug!("nested_test_outer: in protected block");
168+
nested_test_inner();
169+
trouble(1);
170+
};
171+
172+
do b.handle |_j:&int| {
173+
debug!("nested_test_outer: in handler");
174+
outer_trapped = true;
175+
0
176+
};
177+
178+
assert outer_trapped;
179+
}

0 commit comments

Comments
 (0)