5
5
* in std.
6
6
*/
7
7
8
- export condvar;
9
- export semaphore, new_semaphore;
10
- export mutex, new_mutex;
11
- export rwlock;
8
+ export condvar, semaphore, mutex, rwlock;
12
9
13
10
// FIXME (#3119) This shouldn't be a thing exported from core.
14
11
import arc:: exclusive;
@@ -21,8 +18,8 @@ import arc::exclusive;
21
18
type wait_end = pipes:: port < ( ) > ;
22
19
type signal_end = pipes:: chan < ( ) > ;
23
20
// A doubly-ended queue of waiting tasks.
24
- type waitqueue = { head : pipes:: port < signal_end > ,
25
- tail : pipes:: chan < signal_end > } ;
21
+ struct waitqueue { head : pipes:: port < signal_end > ;
22
+ tail: pipes:: chan<signal_end>; }
26
23
27
24
// Signals one live task from the queue.
28
25
fn signal_waitqueue ( q : & waitqueue ) -> bool {
@@ -51,23 +48,25 @@ fn broadcast_waitqueue(q: &waitqueue) -> uint {
51
48
}
52
49
53
50
// The building-block used to make semaphores, mutexes, and rwlocks.
54
- enum sem < Q : send > = exclusive< {
55
- mut count: int,
56
- waiters: waitqueue,
51
+ struct sem_inner < Q > {
52
+ mut count : int ;
53
+ waiters: waitqueue;
57
54
// Can be either unit or another waitqueue. Some sems shouldn't come with
58
55
// a condition variable attached, others should.
59
- blocked: Q ,
60
- } >;
56
+ blocked: Q ;
57
+ }
58
+ enum sem< Q : send > = exclusive< sem_inner<Q >>;
61
59
62
60
fn new_sem<Q : send > ( count: int, +q: Q ) -> sem < Q > {
63
61
let ( wait_tail , wait_head ) = pipes:: stream ( ) ;
64
- sem ( exclusive ( { mut count: count,
65
- waiters : { head : wait_head, tail : wait_tail } ,
66
- blocked: q } ) )
62
+ sem ( exclusive ( sem_inner {
63
+ mut count : count,
64
+ waiters : waitqueue { head : wait_head, tail : wait_tail } ,
65
+ blocked : q } ) )
67
66
}
68
67
fn new_sem_and_signal ( count : int ) -> sem < waitqueue > {
69
68
let ( block_tail, block_head) = pipes:: stream ( ) ;
70
- new_sem ( count, { head: block_head, tail: block_tail } )
69
+ new_sem ( count, waitqueue { head : block_head, tail : block_tail } )
71
70
}
72
71
73
72
impl < Q : send > & sem < Q > {
@@ -143,7 +142,7 @@ struct sem_and_signal_release {
143
142
}
144
143
145
144
/// A mechanism for atomic-unlock-and-deschedule blocking and signalling.
146
- enum condvar = & sem< waitqueue > ;
145
+ struct condvar { priv sem : & sem < waitqueue > ; }
147
146
148
147
impl condvar {
149
148
/// Atomically drop the associated lock, and block until a signal is sent.
@@ -158,10 +157,10 @@ impl condvar {
158
157
// killed before or after enqueueing. Deciding whether to
159
158
// unkillably reacquire the lock needs to happen atomically
160
159
// wrt enqueuing.
161
- reacquire = some ( sem_and_signal_reacquire ( * self ) ) ;
160
+ reacquire = some ( sem_and_signal_reacquire ( self . sem ) ) ;
162
161
163
162
// Release lock, 'atomically' enqueuing ourselves in so doing.
164
- do ( * * * self ) . with |state| {
163
+ do ( * * self . sem ) . with |state| {
165
164
// Drop the lock.
166
165
// FIXME(#3145) investigate why factoring doesn't compile.
167
166
state. count += 1 ;
@@ -196,7 +195,7 @@ impl condvar {
196
195
/// Wake up a blocked task. Returns false if there was no blocked task.
197
196
fn signal ( ) -> bool {
198
197
unsafe {
199
- do ( * * * self ) . with |state| {
198
+ do ( * * self . sem ) . with |state| {
200
199
signal_waitqueue ( & state. blocked )
201
200
}
202
201
}
@@ -205,7 +204,7 @@ impl condvar {
205
204
/// Wake up all blocked tasks. Returns the number of tasks woken.
206
205
fn broadcast ( ) -> uint {
207
206
unsafe {
208
- do ( * * * self ) . with |state| {
207
+ do ( * * self . sem ) . with |state| {
209
208
// FIXME(#3145) fix :broadcast_heavy
210
209
broadcast_waitqueue ( & state. blocked )
211
210
}
@@ -215,7 +214,7 @@ impl condvar {
215
214
216
215
impl & sem < waitqueue > {
217
216
fn access_cond < U > ( blk : fn ( condvar ) -> U ) -> U {
218
- do self . access { blk ( condvar ( self ) ) }
217
+ do self . access { blk ( condvar { sem : self } ) }
219
218
}
220
219
}
221
220
@@ -224,30 +223,32 @@ impl &sem<waitqueue> {
224
223
****************************************************************************/
225
224
226
225
/// A counting, blocking, bounded-waiting semaphore.
227
- enum semaphore = sem<( ) >;
226
+ struct semaphore { priv sem: sem < ( ) > ; }
228
227
229
228
/// Create a new semaphore with the specified count.
230
- fn new_semaphore ( count : int ) -> semaphore { semaphore ( new_sem ( count, ( ) ) ) }
229
+ fn semaphore ( count : int ) -> semaphore {
230
+ semaphore { sem : new_sem ( count, ( ) ) }
231
+ }
231
232
232
233
impl & semaphore {
233
234
/// Create a new handle to the semaphore.
234
- fn clone ( ) -> semaphore { semaphore ( sem ( ( * * * self ) . clone ( ) ) ) }
235
+ fn clone ( ) -> semaphore { semaphore { sem : sem ( ( * self . sem ) . clone ( ) ) } }
235
236
236
237
/**
237
238
* Acquire a resource represented by the semaphore. Blocks if necessary
238
239
* until resource(s) become available.
239
240
*/
240
- fn acquire ( ) { ( & * * self ) . acquire ( ) }
241
+ fn acquire ( ) { ( & self . sem ) . acquire ( ) }
241
242
242
243
/**
243
244
* Release a held resource represented by the semaphore. Wakes a blocked
244
245
* contending task, if any exist. Won't block the caller.
245
246
*/
246
- fn release ( ) { ( & * * self ) . release ( ) }
247
+ fn release ( ) { ( & self . sem ) . release ( ) }
247
248
248
249
/// Run a function with ownership of one of the semaphore's resources.
249
250
// FIXME(#3145): figure out whether or not this should get exported.
250
- fn access < U > ( blk : fn ( ) -> U ) -> U { ( & * * self ) . access ( blk) }
251
+ fn access < U > ( blk : fn ( ) -> U ) -> U { ( & self . sem ) . access ( blk) }
251
252
}
252
253
253
254
/****************************************************************************
@@ -259,21 +260,21 @@ impl &semaphore {
259
260
* FIFO condition variable.
260
261
* FIXME(#3145): document killability
261
262
*/
262
- enum mutex = sem< waitqueue > ;
263
+ struct mutex { priv sem: sem < waitqueue > ; }
263
264
264
265
/// Create a new mutex.
265
- fn new_mutex ( ) -> mutex { mutex ( new_sem_and_signal ( 1 ) ) }
266
+ fn mutex ( ) -> mutex { mutex { sem : new_sem_and_signal ( 1 ) } }
266
267
267
268
impl & mutex {
268
269
/// Create a new handle to the mutex.
269
- fn clone ( ) -> mutex { mutex ( sem ( ( * * * self ) . clone ( ) ) ) }
270
+ fn clone ( ) -> mutex { mutex { sem : sem ( ( * self . sem ) . clone ( ) ) } }
270
271
271
272
/// Run a function with ownership of the mutex.
272
- fn lock < U > ( blk : fn ( ) -> U ) -> U { ( & * * self ) . access ( blk) }
273
+ fn lock < U > ( blk : fn ( ) -> U ) -> U { ( & self . sem ) . access ( blk) }
273
274
274
275
/// Run a function with ownership of the mutex and a handle to a condvar.
275
276
fn lock_cond < U > ( blk : fn ( condvar ) -> U ) -> U {
276
- ( & * * self ) . access_cond ( blk)
277
+ ( & self . sem ) . access_cond ( blk)
277
278
}
278
279
}
279
280
@@ -290,14 +291,14 @@ struct rwlock_inner {
290
291
291
292
/// A blocking, no-starvation, reader-writer lock with an associated condvar.
292
293
struct rwlock {
293
- order_lock : semaphore ;
294
- access_lock: sem<waitqueue>;
295
- state: arc:: exclusive<rwlock_inner>;
294
+ /* priv */ order_lock : semaphore ;
295
+ /* priv */ access_lock: sem<waitqueue>;
296
+ /* priv */ state: arc:: exclusive<rwlock_inner>;
296
297
}
297
298
298
299
/// Create a new rwlock.
299
300
fn rwlock ( ) -> rwlock {
300
- rwlock { order_lock : new_semaphore ( 1 ) , access_lock : new_sem_and_signal ( 1 ) ,
301
+ rwlock { order_lock : semaphore ( 1 ) , access_lock : new_sem_and_signal ( 1 ) ,
301
302
state : arc:: exclusive ( rwlock_inner { read_mode : false ,
302
303
read_count : 0 } ) }
303
304
}
@@ -399,19 +400,19 @@ mod tests {
399
400
************************************************************************/
400
401
#[ test]
401
402
fn test_sem_acquire_release ( ) {
402
- let s = ~new_semaphore ( 1 ) ;
403
+ let s = ~semaphore ( 1 ) ;
403
404
s. acquire ( ) ;
404
405
s. release ( ) ;
405
406
s. acquire ( ) ;
406
407
}
407
408
#[ test]
408
409
fn test_sem_basic ( ) {
409
- let s = ~new_semaphore ( 1 ) ;
410
+ let s = ~semaphore ( 1 ) ;
410
411
do s. access { }
411
412
}
412
413
#[ test]
413
414
fn test_sem_as_mutex ( ) {
414
- let s = ~new_semaphore ( 1 ) ;
415
+ let s = ~semaphore ( 1 ) ;
415
416
let s2 = ~s. clone ( ) ;
416
417
do task:: spawn {
417
418
do s2. access {
@@ -426,7 +427,7 @@ mod tests {
426
427
fn test_sem_as_cvar ( ) {
427
428
/* Child waits and parent signals */
428
429
let ( c, p) = pipes:: stream ( ) ;
429
- let s = ~new_semaphore ( 0 ) ;
430
+ let s = ~semaphore ( 0 ) ;
430
431
let s2 = ~s. clone ( ) ;
431
432
do task:: spawn {
432
433
s2. acquire ( ) ;
@@ -438,7 +439,7 @@ mod tests {
438
439
439
440
/* Parent waits and child signals */
440
441
let ( c, p) = pipes:: stream ( ) ;
441
- let s = ~new_semaphore ( 0 ) ;
442
+ let s = ~semaphore ( 0 ) ;
442
443
let s2 = ~s. clone ( ) ;
443
444
do task:: spawn {
444
445
for 5 . times { task : : yield ( ) ; }
@@ -452,7 +453,7 @@ mod tests {
452
453
fn test_sem_multi_resource ( ) {
453
454
// Parent and child both get in the critical section at the same
454
455
// time, and shake hands.
455
- let s = ~new_semaphore ( 2 ) ;
456
+ let s = ~semaphore ( 2 ) ;
456
457
let s2 = ~s. clone ( ) ;
457
458
let ( c1, p1) = pipes:: stream ( ) ;
458
459
let ( c2, p2) = pipes:: stream ( ) ;
@@ -472,7 +473,7 @@ mod tests {
472
473
// Force the runtime to schedule two threads on the same sched_loop.
473
474
// When one blocks, it should schedule the other one.
474
475
do task:: spawn_sched ( task:: manual_threads ( 1 ) ) {
475
- let s = ~new_semaphore ( 1 ) ;
476
+ let s = ~semaphore ( 1 ) ;
476
477
let s2 = ~s. clone ( ) ;
477
478
let ( c, p) = pipes:: stream ( ) ;
478
479
let child_data = ~mut some ( ( s2, c) ) ;
@@ -497,7 +498,7 @@ mod tests {
497
498
// Unsafely achieve shared state, and do the textbook
498
499
// "load tmp <- ptr; inc tmp; store ptr <- tmp" dance.
499
500
let ( c, p) = pipes:: stream ( ) ;
500
- let m = ~new_mutex ( ) ;
501
+ let m = ~mutex ( ) ;
501
502
let m2 = ~m. clone ( ) ;
502
503
let sharedstate = ~0 ;
503
504
let ptr = ptr:: addr_of ( * sharedstate) ;
@@ -523,7 +524,7 @@ mod tests {
523
524
}
524
525
#[ test]
525
526
fn test_mutex_cond_wait ( ) {
526
- let m = ~new_mutex ( ) ;
527
+ let m = ~mutex ( ) ;
527
528
528
529
// Child wakes up parent
529
530
do m. lock_cond |cond| {
@@ -555,7 +556,7 @@ mod tests {
555
556
}
556
557
#[ cfg( test) ]
557
558
fn test_mutex_cond_broadcast_helper ( num_waiters : uint ) {
558
- let m = ~new_mutex ( ) ;
559
+ let m = ~mutex ( ) ;
559
560
let mut ports = ~[ ] ;
560
561
561
562
for num_waiters. times {
@@ -590,7 +591,7 @@ mod tests {
590
591
}
591
592
#[ test]
592
593
fn test_mutex_cond_no_waiter ( ) {
593
- let m = ~new_mutex ( ) ;
594
+ let m = ~mutex ( ) ;
594
595
let m2 = ~m. clone ( ) ;
595
596
do task:: try {
596
597
do m. lock_cond |_x| { }
@@ -602,7 +603,7 @@ mod tests {
602
603
#[ test] #[ ignore( cfg( windows) ) ]
603
604
fn test_mutex_killed_simple ( ) {
604
605
// Mutex must get automatically unlocked if failed/killed within.
605
- let m = ~new_mutex ( ) ;
606
+ let m = ~mutex ( ) ;
606
607
let m2 = ~m. clone ( ) ;
607
608
608
609
let result: result:: result < ( ) , ( ) > = do task:: try {
@@ -618,7 +619,7 @@ mod tests {
618
619
fn test_mutex_killed_cond ( ) {
619
620
// Getting killed during cond wait must not corrupt the mutex while
620
621
// unwinding (e.g. double unlock).
621
- let m = ~new_mutex ( ) ;
622
+ let m = ~mutex ( ) ;
622
623
let m2 = ~m. clone ( ) ;
623
624
624
625
let result: result:: result < ( ) , ( ) > = do task:: try {
0 commit comments