Skip to content

Commit 90ff64c

Browse files
committed
---
yaml --- r: 23125 b: refs/heads/master c: e1086b0 h: refs/heads/master i: 23123: ac531e6 v: v3
1 parent 6574f0e commit 90ff64c

File tree

3 files changed

+75
-20
lines changed

3 files changed

+75
-20
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: 4c9f16837249a7eeec129fa5f18c61a270262f1d
2+
refs/heads/master: e1086b017596c7d21905adaf756010baecc0fb60
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
44
refs/heads/snap-stage3: cd6f24f9d14ac90d167386a56e7a6ac1f0318195
55
refs/heads/try: ffbe0e0e00374358b789b0037bcb3a577cd218be

trunk/src/libcore/sync.rs

Lines changed: 57 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,6 @@ impl condvar {
162162
// Release lock, 'atomically' enqueuing ourselves in so doing.
163163
do (**self.sem).with |state| {
164164
// Drop the lock.
165-
// FIXME(#3145) investigate why factoring doesn't compile.
166165
state.count += 1;
167166
if state.count <= 0 {
168167
signal_waitqueue(&state.waiters);
@@ -343,34 +342,41 @@ impl &rwlock {
343342
unsafe {
344343
do task::unkillable {
345344
(&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+
}
348349
}
349350
}
350-
let _z = rwlock_release_write(self);
351-
blk()
352351
}
353352

354353
/**
355354
* As write(), but also with a handle to a condvar. Waiting on this
356355
* 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.)
358358
*/
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+
}
361374
}
362375

363376
// to-do implement downgrade
364377
}
365378

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()
374380
struct rwlock_release_read {
375381
lock: &rwlock;
376382
new(lock: &rwlock) { self.lock = lock; }
@@ -708,6 +714,41 @@ mod tests {
708714
let _ = p1.recv();
709715
}
710716
}
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+
}
711752
#[cfg(test)] #[ignore(cfg(windows))]
712753
fn rwlock_kill_helper(reader1: bool, reader2: bool) {
713754
// Mutex must get automatically unlocked if failed/killed within.

trunk/src/libcore/task.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export try;
5656
export yield;
5757
export failing;
5858
export get_task;
59-
export unkillable;
59+
export unkillable, rekillable;
6060
export atomically;
6161

6262
export local_data_key;
@@ -572,7 +572,7 @@ fn get_task() -> task {
572572
* }
573573
* ~~~
574574
*/
575-
unsafe fn unkillable(f: fn()) {
575+
unsafe fn unkillable<U>(f: fn() -> U) -> U {
576576
class allow_failure {
577577
let t: *rust_task;
578578
new(t: *rust_task) { self.t = t; }
@@ -582,7 +582,21 @@ unsafe fn unkillable(f: fn()) {
582582
let t = rustrt::rust_get_task();
583583
let _allow_failure = allow_failure(t);
584584
rustrt::rust_task_inhibit_kill(t);
585-
f();
585+
f()
586+
}
587+
588+
/// The inverse of unkillable. Only ever to be used nested in unkillable().
589+
unsafe fn rekillable<U>(f: fn() -> U) -> U {
590+
class disallow_failure {
591+
let t: *rust_task;
592+
new(t: *rust_task) { self.t = t; }
593+
drop { rustrt::rust_task_inhibit_kill(self.t); }
594+
}
595+
596+
let t = rustrt::rust_get_task();
597+
let _allow_failure = disallow_failure(t);
598+
rustrt::rust_task_allow_kill(t);
599+
f()
586600
}
587601

588602
/**

0 commit comments

Comments
 (0)