Skip to content

Commit 76589cc

Browse files
committed
---
yaml --- r: 63281 b: refs/heads/snap-stage3 c: bd019c4 h: refs/heads/master i: 63279: de6f080 v: v3
1 parent f46ff1e commit 76589cc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

108 files changed

+1429
-1569
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
refs/heads/master: 2d28d645422c1617be58c8ca7ad9a457264ca850
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
4-
refs/heads/snap-stage3: d9d50a5bd4130d55e6f4f7172d17b6314729a697
4+
refs/heads/snap-stage3: bd019c4c26d49c9481ebc4b57134bfdc5c5e5a97
55
refs/heads/try: 7b78b52e602bb3ea8174f9b2006bff3315f03ef9
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b

branches/snap-stage3/src/libextra/arc.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,6 @@ struct RWARCInner<T> { lock: RWlock, failed: bool, data: T }
281281
#[mutable]
282282
struct RWARC<T> {
283283
x: UnsafeAtomicRcBox<RWARCInner<T>>,
284-
cant_nest: ()
285284
}
286285

287286
/// Create a reader/writer ARC with the supplied data.
@@ -299,15 +298,14 @@ pub fn rw_arc_with_condvars<T:Const + Owned>(
299298
let data =
300299
RWARCInner { lock: rwlock_with_condvars(num_condvars),
301300
failed: false, data: user_data };
302-
RWARC { x: UnsafeAtomicRcBox::new(data), cant_nest: () }
301+
RWARC { x: UnsafeAtomicRcBox::new(data), }
303302
}
304303

305304
impl<T:Const + Owned> RWARC<T> {
306305
/// Duplicate a rwlock-protected ARC, as arc::clone.
307306
pub fn clone(&self) -> RWARC<T> {
308307
RWARC {
309308
x: self.x.clone(),
310-
cant_nest: (),
311309
}
312310
}
313311

branches/snap-stage3/src/libextra/sync.rs

Lines changed: 72 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,27 @@ fn SemAndSignalRelease<'r>(sem: &'r Sem<~[Waitqueue]>)
189189
}
190190
}
191191

192+
// FIXME(#3598): Want to use an Option down below, but we need a custom enum
193+
// that's not polymorphic to get around the fact that lifetimes are invariant
194+
// inside of type parameters.
195+
enum ReacquireOrderLock<'self> {
196+
Nothing, // c.c
197+
Just(&'self Semaphore),
198+
}
199+
192200
/// A mechanism for atomic-unlock-and-deschedule blocking and signalling.
193-
pub struct Condvar<'self> { priv sem: &'self Sem<~[Waitqueue]> }
201+
pub struct Condvar<'self> {
202+
// The 'Sem' object associated with this condvar. This is the one that's
203+
// atomically-unlocked-and-descheduled upon and reacquired during wakeup.
204+
priv sem: &'self Sem<~[Waitqueue]>,
205+
// This is (can be) an extra semaphore which is held around the reacquire
206+
// operation on the first one. This is only used in cvars associated with
207+
// rwlocks, and is needed to ensure that, when a downgrader is trying to
208+
// hand off the access lock (which would be the first field, here), a 2nd
209+
// writer waking up from a cvar wait can't race with a reader to steal it,
210+
// See the comment in write_cond for more detail.
211+
priv order: ReacquireOrderLock<'self>,
212+
}
194213

195214
#[unsafe_destructor]
196215
impl<'self> Drop for Condvar<'self> { fn finalize(&self) {} }
@@ -247,7 +266,8 @@ impl<'self> Condvar<'self> {
247266
// unkillably reacquire the lock needs to happen atomically
248267
// wrt enqueuing.
249268
if out_of_bounds.is_none() {
250-
reacquire = Some(SemAndSignalReacquire(self.sem));
269+
reacquire = Some(CondvarReacquire { sem: self.sem,
270+
order: self.order });
251271
}
252272
}
253273
}
@@ -261,28 +281,29 @@ impl<'self> Condvar<'self> {
261281
// This is needed for a failing condition variable to reacquire the
262282
// mutex during unwinding. As long as the wrapper (mutex, etc) is
263283
// bounded in when it gets released, this shouldn't hang forever.
264-
struct SemAndSignalReacquire<'self> {
284+
struct CondvarReacquire<'self> {
265285
sem: &'self Sem<~[Waitqueue]>,
286+
order: ReacquireOrderLock<'self>,
266287
}
267288

268289
#[unsafe_destructor]
269-
impl<'self> Drop for SemAndSignalReacquire<'self> {
290+
impl<'self> Drop for CondvarReacquire<'self> {
270291
fn finalize(&self) {
271292
unsafe {
272293
// Needs to succeed, instead of itself dying.
273294
do task::unkillable {
274-
self.sem.acquire();
295+
match self.order {
296+
Just(lock) => do lock.access {
297+
self.sem.acquire();
298+
},
299+
Nothing => {
300+
self.sem.acquire();
301+
},
302+
}
275303
}
276304
}
277305
}
278306
}
279-
280-
fn SemAndSignalReacquire<'r>(sem: &'r Sem<~[Waitqueue]>)
281-
-> SemAndSignalReacquire<'r> {
282-
SemAndSignalReacquire {
283-
sem: sem
284-
}
285-
}
286307
}
287308

288309
/// Wake up a blocked task. Returns false if there was no blocked task.
@@ -350,9 +371,12 @@ fn check_cvar_bounds<U>(out_of_bounds: Option<uint>, id: uint, act: &str,
350371

351372
#[doc(hidden)]
352373
impl Sem<~[Waitqueue]> {
353-
// The only other place that condvars get built is rwlock_write_mode.
374+
// The only other places that condvars get built are rwlock.write_cond()
375+
// and rwlock_write_mode.
354376
pub fn access_cond<U>(&self, blk: &fn(c: &Condvar) -> U) -> U {
355-
do self.access { blk(&Condvar { sem: self }) }
377+
do self.access {
378+
blk(&Condvar { sem: self, order: Nothing })
379+
}
356380
}
357381
}
358382

@@ -534,17 +558,39 @@ impl RWlock {
534558
* was signalled might reacquire the lock before other waiting writers.)
535559
*/
536560
pub fn write_cond<U>(&self, blk: &fn(c: &Condvar) -> U) -> U {
537-
// NB: You might think I should thread the order_lock into the cond
538-
// wait call, so that it gets waited on before access_lock gets
539-
// reacquired upon being woken up. However, (a) this would be not
540-
// pleasant to implement (and would mandate a new 'rw_cond' type) and
541-
// (b) I think violating no-starvation in that case is appropriate.
561+
// It's important to thread our order lock into the condvar, so that
562+
// when a cond.wait() wakes up, it uses it while reacquiring the
563+
// access lock. If we permitted a waking-up writer to "cut in line",
564+
// there could arise a subtle race when a downgrader attempts to hand
565+
// off the reader cloud lock to a waiting reader. This race is tested
566+
// in arc.rs (test_rw_write_cond_downgrade_read_race) and looks like:
567+
// T1 (writer) T2 (downgrader) T3 (reader)
568+
// [in cond.wait()]
569+
// [locks for writing]
570+
// [holds access_lock]
571+
// [is signalled, perhaps by
572+
// downgrader or a 4th thread]
573+
// tries to lock access(!)
574+
// lock order_lock
575+
// xadd read_count[0->1]
576+
// tries to lock access
577+
// [downgrade]
578+
// xadd read_count[1->2]
579+
// unlock access
580+
// Since T1 contended on the access lock before T3 did, it will steal
581+
// the lock handoff. Adding order_lock in the condvar reacquire path
582+
// solves this because T1 will hold order_lock while waiting on access,
583+
// which will cause T3 to have to wait until T1 finishes its write,
584+
// which can't happen until T2 finishes the downgrade-read entirely.
542585
unsafe {
543586
do task::unkillable {
544587
(&self.order_lock).acquire();
545588
do (&self.access_lock).access_cond |cond| {
546589
(&self.order_lock).release();
547-
do task::rekillable { blk(cond) }
590+
do task::rekillable {
591+
let opt_lock = Just(&self.order_lock);
592+
blk(&Condvar { order: opt_lock, ..*cond })
593+
}
548594
}
549595
}
550596
}
@@ -605,7 +651,8 @@ impl RWlock {
605651
// Guaranteed not to let another writer in, because
606652
// another reader was holding the order_lock. Hence they
607653
// must be the one to get the access_lock (because all
608-
// access_locks are acquired with order_lock held).
654+
// access_locks are acquired with order_lock held). See
655+
// the comment in write_cond for more justification.
609656
(&self.access_lock).release();
610657
}
611658
}
@@ -709,7 +756,10 @@ impl<'self> RWlockWriteMode<'self> {
709756
pub fn write<U>(&self, blk: &fn() -> U) -> U { blk() }
710757
/// Access the pre-downgrade rwlock in write mode with a condvar.
711758
pub fn write_cond<U>(&self, blk: &fn(c: &Condvar) -> U) -> U {
712-
blk(&Condvar { sem: &self.lock.access_lock })
759+
// Need to make the condvar use the order lock when reacquiring the
760+
// access lock. See comment in RWlock::write_cond for why.
761+
blk(&Condvar { sem: &self.lock.access_lock,
762+
order: Just(&self.lock.order_lock), })
713763
}
714764
}
715765

branches/snap-stage3/src/libfuzzer/fuzzer.rc

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -345,13 +345,13 @@ pub fn check_variants_T<T:Copy>(crate: @ast::crate,
345345
intr,
346346
span_handler,
347347
crate2,
348-
fname.to_managed(),
348+
fname.to_str(),
349349
rdr,
350350
a,
351351
pprust::no_ann(),
352352
false)
353353
};
354-
string.to_managed()
354+
@string
355355
};
356356
match cx.mode {
357357
tm_converge => check_roundtrip_convergence(str3, 1),
@@ -361,9 +361,9 @@ pub fn check_variants_T<T:Copy>(crate: @ast::crate,
361361
thing_label,
362362
i,
363363
j);
364-
let safe_to_run = !(content_is_dangerous_to_run(str3)
364+
let safe_to_run = !(content_is_dangerous_to_run(*str3)
365365
|| has_raw_pointers(crate2));
366-
check_whole_compiler(str3,
366+
check_whole_compiler(*str3,
367367
&Path(file_label),
368368
safe_to_run);
369369
}
@@ -502,28 +502,28 @@ pub fn check_compiling(filename: &Path) -> happiness {
502502
}
503503

504504

505-
pub fn parse_and_print(code: @str) -> @str {
505+
pub fn parse_and_print(code: @~str) -> ~str {
506506
let filename = Path("tmp.rs");
507507
let sess = parse::new_parse_sess(option::None);
508-
write_file(&filename, code);
509-
let crate = parse::parse_crate_from_source_str(filename.to_str().to_managed(),
508+
write_file(&filename, *code);
509+
let crate = parse::parse_crate_from_source_str(filename.to_str(),
510510
code,
511511
~[],
512512
sess);
513-
do io::with_str_reader(code) |rdr| {
513+
do io::with_str_reader(*code) |rdr| {
514514
let filename = filename.to_str();
515515
do as_str |a| {
516516
pprust::print_crate(sess.cm,
517517
// Assuming there are no token_trees
518518
token::mk_fake_ident_interner(),
519519
copy sess.span_diagnostic,
520520
crate,
521-
filename.to_managed(),
521+
filename.to_str(),
522522
rdr,
523523
a,
524524
pprust::no_ann(),
525525
false)
526-
}.to_managed()
526+
}
527527
}
528528
}
529529

@@ -598,15 +598,15 @@ pub fn file_might_not_converge(filename: &Path) -> bool {
598598
return false;
599599
}
600600

601-
pub fn check_roundtrip_convergence(code: @str, maxIters: uint) {
601+
pub fn check_roundtrip_convergence(code: @~str, maxIters: uint) {
602602
let mut i = 0u;
603603
let mut newv = code;
604604
let mut oldv = code;
605605

606606
while i < maxIters {
607607
oldv = newv;
608-
if content_might_not_converge(oldv) { return; }
609-
newv = parse_and_print(oldv);
608+
if content_might_not_converge(*oldv) { return; }
609+
newv = @parse_and_print(oldv);
610610
if oldv == newv { break; }
611611
i += 1u;
612612
}
@@ -615,8 +615,8 @@ pub fn check_roundtrip_convergence(code: @str, maxIters: uint) {
615615
error!("Converged after %u iterations", i);
616616
} else {
617617
error!("Did not converge after %u iterations!", i);
618-
write_file(&Path("round-trip-a.rs"), oldv);
619-
write_file(&Path("round-trip-b.rs"), newv);
618+
write_file(&Path("round-trip-a.rs"), *oldv);
619+
write_file(&Path("round-trip-b.rs"), *newv);
620620
run::process_status("diff", [~"-w", ~"-u", ~"round-trip-a.rs", ~"round-trip-b.rs"]);
621621
fail!("Mismatch");
622622
}
@@ -626,8 +626,8 @@ pub fn check_convergence(files: &[Path]) {
626626
error!("pp convergence tests: %u files", files.len());
627627
for files.each |file| {
628628
if !file_might_not_converge(file) {
629-
let s = result::get(&io::read_whole_file_str(file)).to_managed();
630-
if !content_might_not_converge(s) {
629+
let s = @result::get(&io::read_whole_file_str(file));
630+
if !content_might_not_converge(*s) {
631631
error!("pp converge: %s", file.to_str());
632632
// Change from 7u to 2u once
633633
// https://github.com/mozilla/rust/issues/850 is fixed
@@ -646,26 +646,26 @@ pub fn check_variants(files: &[Path], cx: Context) {
646646
loop;
647647
}
648648

649-
let s = result::get(&io::read_whole_file_str(file)).to_managed();
650-
if s.contains_char('#') {
649+
let s = @result::get(&io::read_whole_file_str(file));
650+
if contains(*s, "#") {
651651
loop; // Macros are confusing
652652
}
653-
if cx.mode == tm_converge && content_might_not_converge(s) {
653+
if cx.mode == tm_converge && content_might_not_converge(*s) {
654654
loop;
655655
}
656-
if cx.mode == tm_run && content_is_dangerous_to_compile(s) {
656+
if cx.mode == tm_run && content_is_dangerous_to_compile(*s) {
657657
loop;
658658
}
659659

660660
let file_str = file.to_str();
661661

662662
error!("check_variants: %?", file_str);
663663
let sess = parse::new_parse_sess(None);
664-
let crate = parse::parse_crate_from_source_str(file_str.to_managed(),
664+
let crate = parse::parse_crate_from_source_str(file_str.to_str(),
665665
s,
666666
~[],
667667
sess);
668-
io::with_str_reader(s, |rdr| {
668+
io::with_str_reader(*s, |rdr| {
669669
let file_str = file_str.to_str();
670670
error!("%s",
671671
as_str(|a| {
@@ -675,7 +675,7 @@ pub fn check_variants(files: &[Path], cx: Context) {
675675
token::mk_fake_ident_interner(),
676676
copy sess.span_diagnostic,
677677
crate,
678-
file_str.to_managed(),
678+
file_str.to_str(),
679679
rdr,
680680
a,
681681
pprust::no_ann(),

0 commit comments

Comments
 (0)