Skip to content

Commit 52255f8

Browse files
committed
Enable condvars on ARCs
1 parent 3a403e3 commit 52255f8

File tree

1 file changed

+104
-24
lines changed

1 file changed

+104
-24
lines changed

src/libstd/arc.rs

Lines changed: 104 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,34 @@
55

66
import unsafe::{shared_mutable_state, clone_shared_mutable_state,
77
get_shared_mutable_state, get_shared_immutable_state};
8-
import sync::{condvar, mutex, rwlock};
8+
import sync;
9+
import sync::{mutex, rwlock};
910

1011
export arc, clone, get;
11-
export mutex_arc, rw_arc;
12+
export condvar, mutex_arc, rw_arc;
13+
14+
/// As sync::condvar, a mechanism for unlock-and-descheduling and signalling.
15+
struct condvar { is_mutex: bool; failed: &mut bool; cond: &sync::condvar; }
16+
17+
impl &condvar {
18+
/// Atomically exit the associated ARC and block until a signal is sent.
19+
fn wait() {
20+
assert !*self.failed;
21+
self.cond.wait();
22+
// This is why we need to wrap sync::condvar.
23+
check_poison(self.is_mutex, *self.failed);
24+
}
25+
/// Wake up a blocked task. Returns false if there was no blocked task.
26+
fn signal() -> bool {
27+
assert !*self.failed;
28+
self.cond.signal()
29+
}
30+
/// Wake up all blocked tasks. Returns the number of tasks woken.
31+
fn broadcast() -> uint {
32+
assert !*self.failed;
33+
self.cond.broadcast()
34+
}
35+
}
1236

1337
/****************************************************************************
1438
* Immutable ARC
@@ -95,26 +119,28 @@ impl<T: send> &mutex_arc<T> {
95119
// unsafe. See borrow_rwlock, far below.
96120
do (&state.lock).lock {
97121
check_poison(true, state.failed);
98-
state.failed = true;
99-
let result = blk(&mut state.data);
100-
state.failed = false;
101-
result
122+
let _z = poison_on_fail(&mut state.failed);
123+
blk(&mut state.data)
102124
}
103125
}
104-
/* FIXME(#3145): Make this compile; borrowck doesn't like it..?
105126
/// As access(), but with a condvar, as sync::mutex.lock_cond().
106127
#[inline(always)]
107-
unsafe fn access_cond<U>(blk: fn(x: &mut T, condvar) -> U) -> U {
128+
unsafe fn access_cond<U>(blk: fn(x: &x/mut T, c: &c/condvar) -> U) -> U {
108129
let state = unsafe { get_shared_mutable_state(&self.x) };
109130
do (&state.lock).lock_cond |cond| {
110131
check_poison(true, state.failed);
111-
state.failed = true;
112-
let result = blk(&mut state.data, cond);
113-
state.failed = false;
114-
result
132+
let _z = poison_on_fail(&mut state.failed);
133+
/*
134+
blk(&mut state.data,
135+
&condvar { is_mutex: true, failed: &mut state.failed,
136+
cond: cond })
137+
*/
138+
// XXX: Working around two seeming region bugs here
139+
let fref = unsafe { unsafe::reinterpret_cast(&mut state.failed) };
140+
let cvar = condvar { is_mutex: true, failed: fref, cond: cond };
141+
blk(&mut state.data, unsafe { unsafe::reinterpret_cast(&cvar) } )
115142
}
116143
}
117-
*/
118144
}
119145

120146
// Common code for {mutex.access,rwlock.write}{,_cond}.
@@ -129,6 +155,15 @@ fn check_poison(is_mutex: bool, failed: bool) {
129155
}
130156
}
131157

158+
struct poison_on_fail {
159+
failed: &mut bool;
160+
new(failed: &mut bool) { self.failed = failed; }
161+
drop {
162+
/* assert !*self.failed; -- might be false in case of cond.wait() */
163+
if task::failing() { *self.failed = true; }
164+
}
165+
}
166+
132167
/****************************************************************************
133168
* R/W lock protected ARC
134169
****************************************************************************/
@@ -175,26 +210,28 @@ impl<T: const send> &rw_arc<T> {
175210
let state = unsafe { get_shared_mutable_state(&self.x) };
176211
do borrow_rwlock(state).write {
177212
check_poison(false, state.failed);
178-
state.failed = true;
179-
let result = blk(&mut state.data);
180-
state.failed = false;
181-
result
213+
let _z = poison_on_fail(&mut state.failed);
214+
blk(&mut state.data)
182215
}
183216
}
184-
/* FIXME(#3145): Make this compile; borrowck doesn't like it..?
185217
/// As write(), but with a condvar, as sync::rwlock.write_cond().
186218
#[inline(always)]
187-
fn write_cond<U>(blk: fn(x: &mut T, condvar) -> U) -> U {
219+
fn write_cond<U>(blk: fn(x: &x/mut T, c: &c/condvar) -> U) -> U {
188220
let state = unsafe { get_shared_mutable_state(&self.x) };
189221
do borrow_rwlock(state).write_cond |cond| {
190222
check_poison(false, state.failed);
191-
state.failed = true;
192-
let result = blk(&mut state.data, cond);
193-
state.failed = false;
194-
result
223+
let _z = poison_on_fail(&mut state.failed);
224+
/*
225+
blk(&mut state.data,
226+
&condvar { is_mutex: false, failed: &mut state.failed,
227+
cond: cond })
228+
*/
229+
// XXX: Working around two seeming region bugs here
230+
let fref = unsafe { unsafe::reinterpret_cast(&mut state.failed) };
231+
let cvar = condvar { is_mutex: false, failed: fref, cond: cond };
232+
blk(&mut state.data, unsafe { unsafe::reinterpret_cast(&cvar) } )
195233
}
196234
}
197-
*/
198235
/**
199236
* Access the underlying data immutably. May run concurrently with other
200237
* reading tasks.
@@ -254,6 +291,49 @@ mod tests {
254291
log(info, arc_v);
255292
}
256293

294+
#[test]
295+
fn test_mutex_arc_condvar() {
296+
let arc = ~mutex_arc(false);
297+
let arc2 = ~arc.clone();
298+
let (c,p) = pipes::oneshot();
299+
let (c,p) = (~mut some(c), ~mut some(p));
300+
do task::spawn {
301+
// wait until parent gets in
302+
pipes::recv_one(option::swap_unwrap(p));
303+
do arc2.access_cond |state, cond| {
304+
*state = true;
305+
cond.signal();
306+
}
307+
}
308+
do arc.access_cond |state, cond| {
309+
pipes::send_one(option::swap_unwrap(c), ());
310+
assert !*state;
311+
while !*state {
312+
cond.wait();
313+
}
314+
}
315+
}
316+
#[test] #[should_fail] #[ignore(cfg(windows))]
317+
fn test_arc_condvar_poison() {
318+
let arc = ~mutex_arc(1);
319+
let arc2 = ~arc.clone();
320+
let (c,p) = pipes::stream();
321+
322+
do task::spawn_unlinked {
323+
let _ = p.recv();
324+
do arc2.access_cond |one, cond| {
325+
cond.signal();
326+
assert *one == 0; // Parent should fail when it wakes up.
327+
}
328+
}
329+
330+
do arc.access_cond |one, cond| {
331+
c.send(());
332+
while *one == 1 {
333+
cond.wait();
334+
}
335+
}
336+
}
257337
#[test] #[should_fail] #[ignore(cfg(windows))]
258338
fn test_mutex_arc_poison() {
259339
let arc = ~mutex_arc(1);

0 commit comments

Comments
 (0)