@@ -6,9 +6,8 @@ struct Condition {
6
6
}
7
7
8
8
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 >
12
11
}
13
12
14
13
@@ -21,7 +20,17 @@ struct PopHandler {
21
20
cond : & Condition ,
22
21
drop {
23
22
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
+ }
25
34
}
26
35
}
27
36
}
@@ -31,23 +40,28 @@ struct HandleBlock {
31
40
handler : @Handler ,
32
41
drop {
33
42
unsafe {
43
+ debug ! ( "HandleBlock: pushing handler to TLS" ) ;
34
44
task:: local_data:: local_data_set ( self . pb . cond . key ,
35
45
self . handler ) ;
36
46
let _pop = PopHandler { cond : self . pb . cond } ;
37
47
// transmutation to avoid copying non-copyable, should
38
48
// be fixable by tracking closure pointees in regionck.
39
49
let f : & fn ( ) = :: cast:: transmute ( self . pb . inner ) ;
50
+ debug ! ( "HandleBlock: invoking protected code" ) ;
40
51
f ( ) ;
52
+ debug ! ( "HandleBlock: returned from protected code" ) ;
41
53
}
42
54
}
43
55
}
44
56
45
57
impl ProtectBlock {
46
58
fn handle < T , U : Copy > ( & self , h : & self /fn ( & T ) ->U ) -> HandleBlock /& self {
47
59
unsafe {
60
+ debug ! ( "ProtectBlock.handle: setting up handler block" ) ;
48
61
let p : * RustClosure = :: cast:: transmute ( & h) ;
62
+ let prev = task:: local_data:: local_data_get ( self . cond . key ) ;
49
63
HandleBlock { pb : self ,
50
- handler : @Handler { handle : * p} }
64
+ handler : @Handler { handle : * p, prev : prev } }
51
65
}
52
66
}
53
67
}
@@ -59,17 +73,23 @@ impl Condition {
59
73
unsafe {
60
74
// transmutation to avoid copying non-copyable, should
61
75
// be fixable by tracking closure pointees in regionck.
76
+ debug ! ( "Condition.protect: setting up protected block" ) ;
62
77
let p : * RustClosure = :: cast:: transmute ( & inner) ;
63
78
ProtectBlock { cond : self ,
64
- inner : * p } }
79
+ inner : * p }
80
+ }
65
81
}
66
82
67
83
fn raise < T , U : Copy > ( t : & T ) -> U {
68
84
unsafe {
69
85
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
+
71
91
Some ( handler) => {
72
- io :: println ( "got handler") ;
92
+ debug ! ( "Condition.raise: found handler") ;
73
93
let f : & fn ( & T ) -> U = :: cast:: transmute ( handler. handle ) ;
74
94
f ( t)
75
95
}
@@ -79,39 +99,81 @@ impl Condition {
79
99
}
80
100
81
101
82
- #[ test]
102
+ #[ cfg ( test) ]
83
103
fn happiness_key ( _x : @Handler ) { }
84
104
85
- #[ test]
105
+ #[ cfg ( test) ]
86
106
fn sadness_key ( _x : @Handler ) { }
87
107
88
- #[ test]
108
+ #[ cfg ( test) ]
89
109
fn trouble ( i : int ) {
90
110
// Condition should work as a const, just limitations in consts.
91
111
let sadness_condition : Condition = Condition { key : sadness_key } ;
92
- io :: println ( " raising") ;
112
+ debug ! ( "trouble: raising conition ") ;
93
113
let j = sadness_condition. raise ( & i) ;
94
- io :: println ( fmt ! ( "handler recovered with %d" , j) ) ;
114
+ debug ! ( "trouble: handler recovered with %d" , j) ;
95
115
}
96
116
97
117
#[ test]
98
- fn test ( ) {
118
+ fn test1 ( ) {
99
119
100
120
let sadness_condition : Condition = Condition { key : sadness_key } ;
101
121
102
122
let mut i = 10 ;
103
123
104
124
let b = do sadness_condition. protect {
105
- io :: println ( " in protected block") ;
125
+ debug ! ( "test1: in protected block") ;
106
126
trouble ( 1 ) ;
107
127
trouble ( 2 ) ;
108
128
trouble ( 3 ) ;
109
129
} ;
110
130
111
131
do b. handle |j| {
132
+ debug ! ( "test1: in handler" ) ;
112
133
i += * j;
113
134
i
114
135
} ;
115
136
116
137
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