Skip to content

Commit 64ba7a3

Browse files
committed
Touch up semaphores; add another test
1 parent a3f9e18 commit 64ba7a3

File tree

1 file changed

+44
-16
lines changed

1 file changed

+44
-16
lines changed

src/libcore/sync.rs

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,23 @@ type signal_end = pipes::chan<()>;
1717
type waitqueue = { head: pipes::port<signal_end>,
1818
tail: pipes::chan<signal_end> };
1919

20-
fn new_waiter() -> (signal_end, wait_end) { pipes::stream() }
20+
fn waitqueue() -> waitqueue {
21+
let (tail, head) = pipes::stream();
22+
{ head: head, tail: tail }
23+
}
2124

22-
/// A counting semaphore.
23-
enum semaphore = exclusive<{
25+
/// A counting, blocking, bounded-waiting semaphore.
26+
enum semaphore = exclusive<semaphore_inner>;
27+
type semaphore_inner = {
2428
mut count: int,
2529
waiters: waitqueue,
26-
}>;
30+
//blocked: waitqueue,
31+
};
2732

2833
/// Create a new semaphore with the specified count.
2934
fn new_semaphore(count: int) -> semaphore {
30-
let (tail, head) = pipes::stream();
3135
semaphore(exclusive({ mut count: count,
32-
waiters: { head: head, tail: tail } }))
36+
waiters: waitqueue(), /* blocked: waitqueue() */ }))
3337
}
3438

3539
impl semaphore for &semaphore {
@@ -42,20 +46,21 @@ impl semaphore for &semaphore {
4246
* Acquires a resource represented by the semaphore. Blocks if necessary
4347
* until resource(s) become available.
4448
*/
45-
fn wait() {
49+
fn acquire() {
4650
let mut waiter_nobe = none;
4751
unsafe {
4852
do (**self).with |state| {
4953
state.count -= 1;
5054
if state.count < 0 {
51-
let (signal_end,wait_end) = new_waiter();
55+
let (signal_end,wait_end) = pipes::stream();
5256
waiter_nobe = some(wait_end);
5357
// Enqueue ourself.
5458
state.waiters.tail.send(signal_end);
5559
}
5660
}
5761
}
58-
for 1000.times { task::yield(); }
62+
// Uncomment if you wish to test for sem races. Not valgrind-friendly.
63+
/* for 1000.times { task::yield(); } */
5964
// Need to wait outside the exclusive.
6065
if waiter_nobe.is_some() {
6166
let _ = option::unwrap(waiter_nobe).recv();
@@ -66,7 +71,7 @@ impl semaphore for &semaphore {
6671
* Release a held resource represented by the semaphore. Wakes a blocked
6772
* contending task, if any exist.
6873
*/
69-
fn signal() {
74+
fn release() {
7075
unsafe {
7176
do (**self).with |state| {
7277
state.count += 1;
@@ -85,7 +90,7 @@ impl semaphore for &semaphore {
8590

8691
/// Runs a function with ownership of one of the semaphore's resources.
8792
fn access<U>(blk: fn() -> U) -> U {
88-
self.wait();
93+
self.acquire();
8994
let _x = sem_release(self);
9095
blk()
9196
}
@@ -95,7 +100,7 @@ impl semaphore for &semaphore {
95100
struct sem_release {
96101
sem: &semaphore;
97102
new(sem: &semaphore) { self.sem = sem; }
98-
drop { self.sem.signal(); }
103+
drop { self.sem.release(); }
99104
}
100105

101106
#[cfg(test)]
@@ -120,11 +125,11 @@ mod tests {
120125
let s = ~new_semaphore(0);
121126
let s2 = ~s.clone();
122127
do task::spawn {
123-
s2.wait();
128+
s2.acquire();
124129
c.send(());
125130
}
126131
for 10.times { task::yield(); }
127-
s.signal();
132+
s.release();
128133
let _ = p.recv();
129134

130135
/* Parent waits and child signals */
@@ -133,14 +138,16 @@ mod tests {
133138
let s2 = ~s.clone();
134139
do task::spawn {
135140
for 10.times { task::yield(); }
136-
s2.signal();
141+
s2.release();
137142
let _ = p.recv();
138143
}
139-
s.wait();
144+
s.acquire();
140145
c.send(());
141146
}
142147
#[test]
143148
fn test_sem_mutual_exclusion() {
149+
// Unsafely achieve shared state, and do the textbook
150+
// "load tmp <- ptr; inc tmp; store ptr <- tmp" dance.
144151
let (c,p) = pipes::stream();
145152
let s = ~new_semaphore(1);
146153
let s2 = ~s.clone();
@@ -167,7 +174,28 @@ mod tests {
167174
}
168175
}
169176
#[test]
177+
fn test_sem_multi_resource() {
178+
// Parent and child both get in the critical section at the same
179+
// time, and shake hands.
180+
let s = ~new_semaphore(2);
181+
let s2 = ~s.clone();
182+
let (c1,p1) = pipes::stream();
183+
let (c2,p2) = pipes::stream();
184+
do task::spawn {
185+
do s2.access {
186+
let _ = p2.recv();
187+
c1.send(());
188+
}
189+
}
190+
do s.access {
191+
c2.send(());
192+
let _ = p1.recv();
193+
}
194+
}
195+
#[test]
170196
fn test_sem_runtime_friendly_blocking() {
197+
// Force the runtime to schedule two threads on the same sched_loop.
198+
// When one blocks, it should schedule the other one.
171199
do task::spawn_sched(task::manual_threads(1)) {
172200
let s = ~new_semaphore(1);
173201
let s2 = ~s.clone();

0 commit comments

Comments
 (0)