@@ -162,7 +162,6 @@ impl condvar {
162
162
// Release lock, 'atomically' enqueuing ourselves in so doing.
163
163
do ( * * self . sem ) . with |state| {
164
164
// Drop the lock.
165
- // FIXME(#3145) investigate why factoring doesn't compile.
166
165
state. count += 1 ;
167
166
if state. count <= 0 {
168
167
signal_waitqueue ( & state. waiters ) ;
@@ -343,34 +342,41 @@ impl &rwlock {
343
342
unsafe {
344
343
do task:: unkillable {
345
344
( & self . order_lock ) . acquire ( ) ;
346
- ( & self . access_lock ) . acquire ( ) ;
347
- ( & self . order_lock ) . release ( ) ;
345
+ do ( & self . access_lock ) . access {
346
+ ( & self . order_lock ) . release ( ) ;
347
+ task:: rekillable ( blk)
348
+ }
348
349
}
349
350
}
350
- let _z = rwlock_release_write ( self ) ;
351
- blk( )
352
351
}
353
352
354
353
/**
355
354
* As write(), but also with a handle to a condvar. Waiting on this
356
355
* condvar will allow readers and writers alike to take the rwlock before
357
- * the waiting task is signalled.
356
+ * the waiting task is signalled. (Note: a writer that waited and then
357
+ * was signalled might reacquire the lock before other waiting writers.)
358
358
*/
359
- fn write_cond < U > ( _blk : fn ( condvar ) -> U ) -> U {
360
- fail ~"Need implement lock order lock before access lock";
359
+ fn write_cond < U > ( blk : fn ( condvar ) -> U ) -> U {
360
+ // NB: You might think I should thread the order_lock into the cond
361
+ // wait call, so that it gets waited on before access_lock gets
362
+ // reacquired upon being woken up. However, (a) this would be not
363
+ // pleasant to implement (and would mandate a new 'rw_cond' type) and
364
+ // (b) I think violating no-starvation in that case is appropriate.
365
+ unsafe {
366
+ do task:: unkillable {
367
+ ( & self . order_lock ) . acquire ( ) ;
368
+ do ( & self . access_lock ) . access_cond |cond| {
369
+ ( & self . order_lock ) . release ( ) ;
370
+ do task:: rekillable { blk( cond) }
371
+ }
372
+ }
373
+ }
361
374
}
362
375
363
376
// to-do implement downgrade
364
377
}
365
378
366
- // FIXME(#3136) should go inside of write() and read() respectively
367
- struct rwlock_release_write {
368
- lock : & rwlock ;
369
- new ( lock : & rwlock ) { self . lock = lock; }
370
- drop unsafe {
371
- do task:: unkillable { ( & self . lock . access_lock ) . release ( ) ; }
372
- }
373
- }
379
+ // FIXME(#3136) should go inside of read()
374
380
struct rwlock_release_read {
375
381
lock : & rwlock ;
376
382
new ( lock : & rwlock ) { self . lock = lock; }
@@ -708,6 +714,41 @@ mod tests {
708
714
let _ = p1. recv ( ) ;
709
715
}
710
716
}
717
+ #[ test]
718
+ fn test_rwlock_cond_wait ( ) {
719
+ // As test_mutex_cond_wait above.
720
+ let x = ~rwlock ( ) ;
721
+
722
+ // Child wakes up parent
723
+ do x. write_cond |cond| {
724
+ let x2 = ~x. clone ( ) ;
725
+ do task:: spawn {
726
+ do x2. write_cond |cond| {
727
+ let woken = cond. signal ( ) ;
728
+ assert woken;
729
+ }
730
+ }
731
+ cond. wait ( ) ;
732
+ }
733
+ // Parent wakes up child
734
+ let ( chan, port) = pipes:: stream ( ) ;
735
+ let x3 = ~x. clone ( ) ;
736
+ do task:: spawn {
737
+ do x3. write_cond |cond| {
738
+ chan. send ( ( ) ) ;
739
+ cond. wait ( ) ;
740
+ chan. send ( ( ) ) ;
741
+ }
742
+ }
743
+ let _ = port. recv ( ) ; // Wait until child gets in the rwlock
744
+ do x. read { } // Must be able to get in as a reader in the meantime
745
+ do x. write_cond |cond| { // Or as another writer
746
+ let woken = cond. signal ( ) ;
747
+ assert woken;
748
+ }
749
+ let _ = port. recv ( ) ; // Wait until child wakes up
750
+ do x. read { } // Just for good measure
751
+ }
711
752
#[ cfg( test) ] #[ ignore( cfg( windows) ) ]
712
753
fn rwlock_kill_helper ( reader1 : bool , reader2 : bool ) {
713
754
// Mutex must get automatically unlocked if failed/killed within.
0 commit comments