@@ -17,19 +17,23 @@ type signal_end = pipes::chan<()>;
17
17
type waitqueue = { head : pipes:: port < signal_end > ,
18
18
tail : pipes:: chan < signal_end > } ;
19
19
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
+ }
21
24
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 = {
24
28
mut count : int ,
25
29
waiters : waitqueue ,
26
- } >;
30
+ //blocked: waitqueue,
31
+ } ;
27
32
28
33
/// Create a new semaphore with the specified count.
29
34
fn new_semaphore ( count : int ) -> semaphore {
30
- let ( tail, head) = pipes:: stream ( ) ;
31
35
semaphore ( exclusive ( { mut count: count,
32
- waiters : { head : head , tail : tail } } ) )
36
+ waiters: waitqueue ( ) , /* blocked: waitqueue() */ } ) )
33
37
}
34
38
35
39
impl semaphore for & semaphore {
@@ -42,20 +46,21 @@ impl semaphore for &semaphore {
42
46
* Acquires a resource represented by the semaphore. Blocks if necessary
43
47
* until resource(s) become available.
44
48
*/
45
- fn wait ( ) {
49
+ fn acquire ( ) {
46
50
let mut waiter_nobe = none;
47
51
unsafe {
48
52
do ( * * self ) . with |state| {
49
53
state. count -= 1 ;
50
54
if state. count < 0 {
51
- let ( signal_end, wait_end) = new_waiter ( ) ;
55
+ let ( signal_end, wait_end) = pipes :: stream ( ) ;
52
56
waiter_nobe = some ( wait_end) ;
53
57
// Enqueue ourself.
54
58
state. waiters . tail . send ( signal_end) ;
55
59
}
56
60
}
57
61
}
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(); } */
59
64
// Need to wait outside the exclusive.
60
65
if waiter_nobe. is_some ( ) {
61
66
let _ = option:: unwrap ( waiter_nobe) . recv ( ) ;
@@ -66,7 +71,7 @@ impl semaphore for &semaphore {
66
71
* Release a held resource represented by the semaphore. Wakes a blocked
67
72
* contending task, if any exist.
68
73
*/
69
- fn signal ( ) {
74
+ fn release ( ) {
70
75
unsafe {
71
76
do ( * * self ) . with |state| {
72
77
state. count += 1 ;
@@ -85,7 +90,7 @@ impl semaphore for &semaphore {
85
90
86
91
/// Runs a function with ownership of one of the semaphore's resources.
87
92
fn access < U > ( blk : fn ( ) -> U ) -> U {
88
- self . wait ( ) ;
93
+ self . acquire ( ) ;
89
94
let _x = sem_release ( self ) ;
90
95
blk ( )
91
96
}
@@ -95,7 +100,7 @@ impl semaphore for &semaphore {
95
100
struct sem_release {
96
101
sem : & semaphore ;
97
102
new ( sem : & semaphore ) { self . sem = sem; }
98
- drop { self. sem . signal ( ) ; }
103
+ drop { self. sem . release ( ) ; }
99
104
}
100
105
101
106
#[ cfg( test) ]
@@ -120,11 +125,11 @@ mod tests {
120
125
let s = ~new_semaphore ( 0 ) ;
121
126
let s2 = ~s. clone ( ) ;
122
127
do task:: spawn {
123
- s2. wait ( ) ;
128
+ s2. acquire ( ) ;
124
129
c. send ( ( ) ) ;
125
130
}
126
131
for 10 . times { task : : yield( ) ; }
127
- s. signal ( ) ;
132
+ s. release ( ) ;
128
133
let _ = p. recv( ) ;
129
134
130
135
/* Parent waits and child signals */
@@ -133,14 +138,16 @@ mod tests {
133
138
let s2 = ~s. clone ( ) ;
134
139
do task:: spawn {
135
140
for 10 . times { task : : yield ( ) ; }
136
- s2. signal ( ) ;
141
+ s2. release ( ) ;
137
142
let _ = p. recv ( ) ;
138
143
}
139
- s. wait ( ) ;
144
+ s. acquire ( ) ;
140
145
c. send ( ( ) ) ;
141
146
}
142
147
#[ test]
143
148
fn test_sem_mutual_exclusion ( ) {
149
+ // Unsafely achieve shared state, and do the textbook
150
+ // "load tmp <- ptr; inc tmp; store ptr <- tmp" dance.
144
151
let ( c, p) = pipes:: stream ( ) ;
145
152
let s = ~new_semaphore ( 1 ) ;
146
153
let s2 = ~s. clone ( ) ;
@@ -167,7 +174,28 @@ mod tests {
167
174
}
168
175
}
169
176
#[ 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]
170
196
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.
171
199
do task:: spawn_sched ( task:: manual_threads ( 1 ) ) {
172
200
let s = ~new_semaphore ( 1 ) ;
173
201
let s2 = ~s. clone ( ) ;
0 commit comments