Skip to content

Commit 2270552

Browse files
committed
---
yaml --- r: 23245 b: refs/heads/master c: a57d3e0 h: refs/heads/master i: 23243: 9c04bb4 v: v3
1 parent 8e5cb93 commit 2270552

File tree

2 files changed

+28
-22
lines changed

2 files changed

+28
-22
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
refs/heads/master: 5f64d5df339a4794d19d5be0f5291f6bfef38ec1
2+
refs/heads/master: a57d3e0c152a293885f65cdf44d4b98a5e2f71cc
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
44
refs/heads/snap-stage3: cd6f24f9d14ac90d167386a56e7a6ac1f0318195
55
refs/heads/try: ffbe0e0e00374358b789b0037bcb3a577cd218be

trunk/src/libstd/sync.rs

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ type signal_end = pipes::chan_one<()>;
2828
struct waitqueue { head: pipes::port<signal_end>;
2929
tail: pipes::chan<signal_end>; }
3030

31+
fn new_waitqueue() -> waitqueue {
32+
let (block_tail, block_head) = pipes::stream();
33+
waitqueue { head: block_head, tail: block_tail }
34+
}
35+
3136
// Signals one live task from the queue.
3237
#[doc(hidden)]
3338
fn signal_waitqueue(q: &waitqueue) -> bool {
@@ -70,18 +75,15 @@ enum sem<Q: send> = Exclusive<sem_inner<Q>>;
7075

7176
#[doc(hidden)]
7277
fn new_sem<Q: send>(count: int, +q: Q) -> sem<Q> {
73-
let (wait_tail, wait_head) = pipes::stream();
7478
sem(exclusive(sem_inner {
75-
mut count: count,
76-
waiters: waitqueue { head: wait_head, tail: wait_tail },
77-
blocked: q }))
79+
mut count: count, waiters: new_waitqueue(), blocked: q }))
7880
}
7981
#[doc(hidden)]
80-
fn new_sem_and_signal(count: int, num_condvars: uint) -> sem<~[waitqueue]> {
81-
let mut queues = ~[];
82+
fn new_sem_and_signal(count: int, num_condvars: uint)
83+
-> sem<~[mut waitqueue]> {
84+
let mut queues = ~[mut];
8285
for num_condvars.times {
83-
let (block_tail, block_head) = pipes::stream();
84-
vec::push(queues, waitqueue { head: block_head, tail: block_tail });
86+
vec::push(queues, new_waitqueue());
8587
}
8688
new_sem(count, queues)
8789
}
@@ -136,7 +138,7 @@ impl &sem<()> {
136138
}
137139
}
138140
#[doc(hidden)]
139-
impl &sem<~[waitqueue]> {
141+
impl &sem<~[mut waitqueue]> {
140142
fn access<U>(blk: fn() -> U) -> U {
141143
let mut release = none;
142144
unsafe {
@@ -158,13 +160,13 @@ struct sem_release {
158160
}
159161
#[doc(hidden)]
160162
struct sem_and_signal_release {
161-
sem: &sem<~[waitqueue]>;
162-
new(sem: &sem<~[waitqueue]>) { self.sem = sem; }
163+
sem: &sem<~[mut waitqueue]>;
164+
new(sem: &sem<~[mut waitqueue]>) { self.sem = sem; }
163165
drop { self.sem.release(); }
164166
}
165167

166168
/// A mechanism for atomic-unlock-and-deschedule blocking and signalling.
167-
struct condvar { priv sem: &sem<~[waitqueue]>; drop { } }
169+
struct condvar { priv sem: &sem<~[mut waitqueue]>; drop { } }
168170

169171
impl &condvar {
170172
/**
@@ -232,8 +234,8 @@ impl &condvar {
232234
// mutex during unwinding. As long as the wrapper (mutex, etc) is
233235
// bounded in when it gets released, this shouldn't hang forever.
234236
struct sem_and_signal_reacquire {
235-
sem: &sem<~[waitqueue]>;
236-
new(sem: &sem<~[waitqueue]>) { self.sem = sem; }
237+
sem: &sem<~[mut waitqueue]>;
238+
new(sem: &sem<~[mut waitqueue]>) { self.sem = sem; }
237239
drop unsafe {
238240
// Needs to succeed, instead of itself dying.
239241
do task::unkillable {
@@ -268,19 +270,23 @@ impl &condvar {
268270
/// As broadcast, but with a specified condvar_id. See wait_on.
269271
fn broadcast_on(condvar_id: uint) -> uint {
270272
let mut out_of_bounds = none;
271-
let mut result = 0;
273+
let mut queue = none;
272274
unsafe {
273275
do (**self.sem).with |state| {
274276
if condvar_id < vec::len(state.blocked) {
275-
// FIXME(#3145) fix :broadcast_heavy
276-
result = broadcast_waitqueue(&state.blocked[condvar_id])
277+
// To avoid :broadcast_heavy, we make a new waitqueue,
278+
// swap it out with the old one, and broadcast on the
279+
// old one outside of the little-lock.
280+
queue = some(util::replace(&mut state.blocked[condvar_id],
281+
new_waitqueue()));
277282
} else {
278283
out_of_bounds = some(vec::len(state.blocked));
279284
}
280285
}
281286
}
282287
do check_cvar_bounds(out_of_bounds, condvar_id, "cond.signal_on()") {
283-
result
288+
let queue = option::swap_unwrap(&mut queue);
289+
broadcast_waitqueue(&queue)
284290
}
285291
}
286292
}
@@ -303,7 +309,7 @@ fn check_cvar_bounds<U>(out_of_bounds: option<uint>, id: uint, act: &str,
303309
}
304310

305311
#[doc(hidden)]
306-
impl &sem<~[waitqueue]> {
312+
impl &sem<~[mut waitqueue]> {
307313
// The only other place that condvars get built is rwlock_write_mode.
308314
fn access_cond<U>(blk: fn(c: &condvar) -> U) -> U {
309315
do self.access { blk(&condvar { sem: self }) }
@@ -354,7 +360,7 @@ impl &semaphore {
354360
* A task which fails while holding a mutex will unlock the mutex as it
355361
* unwinds.
356362
*/
357-
struct mutex { priv sem: sem<~[waitqueue]>; }
363+
struct mutex { priv sem: sem<~[mut waitqueue]>; }
358364

359365
/// Create a new mutex, with one associated condvar.
360366
fn mutex() -> mutex { mutex_with_condvars(1) }
@@ -402,7 +408,7 @@ struct rwlock_inner {
402408
*/
403409
struct rwlock {
404410
/* priv */ order_lock: semaphore;
405-
/* priv */ access_lock: sem<~[waitqueue]>;
411+
/* priv */ access_lock: sem<~[mut waitqueue]>;
406412
/* priv */ state: Exclusive<rwlock_inner>;
407413
}
408414

0 commit comments

Comments
 (0)