Skip to content

Commit be2e4ef

Browse files
committed
Allow failing in arc::exclusive; poison to fail subsequent accesses (fix #3092)
1 parent 190ecc2 commit be2e4ef

File tree

1 file changed

+31
-9
lines changed

1 file changed

+31
-9
lines changed

src/libcore/arc.rs

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,12 @@ fn clone<T: const send>(rc: &arc<T>) -> arc<T> {
8181
}
8282

8383
// An arc over mutable data that is protected by a lock.
84-
type ex_data<T: send> = {lock: sys::little_lock, mut data: T};
84+
type ex_data<T: send> =
85+
{lock: sys::little_lock, mut failed: bool, mut data: T};
8586
type exclusive<T: send> = arc_destruct<ex_data<T>>;
8687

8788
fn exclusive<T:send >(-data: T) -> exclusive<T> {
88-
let data = ~{mut count: 1, data: {lock: sys::little_lock(),
89+
let data = ~{mut count: 1, data: {lock: sys::little_lock(), failed: false,
8990
data: data}};
9091
unsafe {
9192
let ptr = unsafe::reinterpret_cast(data);
@@ -128,12 +129,18 @@ impl<T: send> exclusive<T> {
128129
let ptr: ~arc_data<ex_data<T>> =
129130
unsafe::reinterpret_cast(self.data);
130131
assert ptr.count > 0;
131-
let r = {
132-
let rec: &ex_data<T> = &(*ptr).data;
133-
do rec.lock.lock { f(&mut rec.data) }
134-
};
132+
let ptr2: &arc_data<ex_data<T>> = unsafe::reinterpret_cast(&*ptr);
135133
unsafe::forget(ptr);
136-
r
134+
let rec: &ex_data<T> = &(*ptr2).data;
135+
do rec.lock.lock {
136+
if rec.failed {
137+
fail ~"Poisoned arc::exclusive - another task failed inside!";
138+
}
139+
rec.failed = true;
140+
let result = f(&mut rec.data);
141+
rec.failed = false;
142+
result
143+
}
137144
}
138145
}
139146

@@ -168,12 +175,11 @@ mod tests {
168175
}
169176

170177
#[test]
171-
#[ignore] // this can probably infinite loop too.
172178
fn exclusive_arc() {
173179
let mut futures = ~[];
174180

175181
let num_tasks = 10u;
176-
let count = 1000u;
182+
let count = 10u;
177183

178184
let total = exclusive(~mut 0u);
179185

@@ -194,4 +200,20 @@ mod tests {
194200
assert **total == num_tasks * count
195201
};
196202
}
203+
204+
#[test] #[should_fail] #[ignore(cfg(windows))]
205+
fn exclusive_poison() {
206+
// Tests that if one task fails inside of an exclusive, subsequent
207+
// accesses will also fail.
208+
let x = arc::exclusive(1);
209+
let x2 = x.clone();
210+
do task::try {
211+
do x2.with |one| {
212+
assert *one == 2;
213+
}
214+
};
215+
do x.with |one| {
216+
assert *one == 1;
217+
}
218+
}
197219
}

0 commit comments

Comments
 (0)