Skip to content

Commit c822d10

Browse files
committed
auto merge of #8581 : FlaPer87/rust/issue/8232, r=bblum
As for now, rekillable is an unsafe function, instead, it should behave just like unkillable by encapsulating unsafe code within an unsafe block. This patch does that and removes unsafe blocks that were encapsulating rekillable calls throughout rust's libs. Fixes #8232
2 parents 7841b77 + cc59d96 commit c822d10

File tree

3 files changed

+87
-48
lines changed

3 files changed

+87
-48
lines changed

src/libextra/sync.rs

+19-29
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,7 @@ impl<Q:Send> Sem<Q> {
135135
do task::unkillable {
136136
do (|| {
137137
self.acquire();
138-
unsafe {
139-
do task::rekillable { blk() }
140-
}
138+
do task::rekillable { blk() }
141139
}).finally {
142140
self.release();
143141
}
@@ -234,10 +232,8 @@ impl<'self> Condvar<'self> {
234232
// signaller already sent -- I mean 'unconditionally' in contrast
235233
// with acquire().)
236234
do (|| {
237-
unsafe {
238-
do task::rekillable {
239-
let _ = WaitEnd.take_unwrap().recv();
240-
}
235+
do task::rekillable {
236+
let _ = WaitEnd.take_unwrap().recv();
241237
}
242238
}).finally {
243239
// Reacquire the condvar. Note this is back in the unkillable
@@ -516,14 +512,12 @@ impl RWLock {
516512
* 'write' from other tasks will run concurrently with this one.
517513
*/
518514
pub fn write<U>(&self, blk: &fn() -> U) -> U {
519-
unsafe {
520-
do task::unkillable {
521-
(&self.order_lock).acquire();
522-
do (&self.access_lock).access {
523-
(&self.order_lock).release();
524-
do task::rekillable {
525-
blk()
526-
}
515+
do task::unkillable {
516+
(&self.order_lock).acquire();
517+
do (&self.access_lock).access {
518+
(&self.order_lock).release();
519+
do task::rekillable {
520+
blk()
527521
}
528522
}
529523
}
@@ -562,16 +556,14 @@ impl RWLock {
562556
// which can't happen until T2 finishes the downgrade-read entirely.
563557
// The astute reader will also note that making waking writers use the
564558
// order_lock is better for not starving readers.
565-
unsafe {
566-
do task::unkillable {
567-
(&self.order_lock).acquire();
568-
do (&self.access_lock).access_cond |cond| {
569-
(&self.order_lock).release();
570-
do task::rekillable {
571-
let opt_lock = Just(&self.order_lock);
572-
blk(&Condvar { sem: cond.sem, order: opt_lock,
573-
token: NonCopyable::new() })
574-
}
559+
do task::unkillable {
560+
(&self.order_lock).acquire();
561+
do (&self.access_lock).access_cond |cond| {
562+
(&self.order_lock).release();
563+
do task::rekillable {
564+
let opt_lock = Just(&self.order_lock);
565+
blk(&Condvar { sem: cond.sem, order: opt_lock,
566+
token: NonCopyable::new() })
575567
}
576568
}
577569
}
@@ -606,10 +598,8 @@ impl RWLock {
606598
(&self.access_lock).acquire();
607599
(&self.order_lock).release();
608600
do (|| {
609-
unsafe {
610-
do task::rekillable {
611-
blk(RWLockWriteMode { lock: self, token: NonCopyable::new() })
612-
}
601+
do task::rekillable {
602+
blk(RWLockWriteMode { lock: self, token: NonCopyable::new() })
613603
}
614604
}).finally {
615605
let writer_or_last_reader;

src/libstd/rt/kill.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,11 @@ impl Death {
647647
/// All calls must be paired with a preceding call to inhibit_kill.
648648
#[inline]
649649
pub fn allow_kill(&mut self, already_failing: bool) {
650-
rtassert!(self.unkillable != 0);
650+
if self.unkillable == 0 {
651+
// we need to decrement the counter before failing.
652+
self.unkillable -= 1;
653+
fail!("Cannot enter a rekillable() block without a surrounding unkillable()");
654+
}
651655
self.unkillable -= 1;
652656
if self.unkillable == 0 {
653657
rtassert!(self.kill_handle.is_some());

src/libstd/task/mod.rs

+63-18
Original file line numberDiff line numberDiff line change
@@ -597,21 +597,36 @@ pub fn unkillable<U>(f: &fn() -> U) -> U {
597597
}
598598
}
599599

600-
/// The inverse of unkillable. Only ever to be used nested in unkillable().
601-
pub unsafe fn rekillable<U>(f: &fn() -> U) -> U {
600+
/**
601+
* Makes killable a task marked as unkillable. This
602+
* is meant to be used only nested in unkillable.
603+
*
604+
* # Example
605+
*
606+
* ~~~
607+
* do task::unkillable {
608+
* do task::rekillable {
609+
* // Task is killable
610+
* }
611+
* // Task is unkillable again
612+
* }
613+
*/
614+
pub fn rekillable<U>(f: &fn() -> U) -> U {
602615
use rt::task::Task;
603616

604-
if in_green_task_context() {
605-
let t = Local::unsafe_borrow::<Task>();
606-
do (|| {
607-
(*t).death.allow_kill((*t).unwinder.unwinding);
617+
unsafe {
618+
if in_green_task_context() {
619+
let t = Local::unsafe_borrow::<Task>();
620+
do (|| {
621+
(*t).death.allow_kill((*t).unwinder.unwinding);
622+
f()
623+
}).finally {
624+
(*t).death.inhibit_kill((*t).unwinder.unwinding);
625+
}
626+
} else {
627+
// FIXME(#3095): As in unkillable().
608628
f()
609-
}).finally {
610-
(*t).death.inhibit_kill((*t).unwinder.unwinding);
611629
}
612-
} else {
613-
// FIXME(#3095): As in unkillable().
614-
f()
615630
}
616631
}
617632

@@ -636,8 +651,8 @@ fn test_kill_unkillable_task() {
636651
}
637652
}
638653

639-
#[ignore(reason = "linked failure")]
640654
#[test]
655+
#[ignore(cfg(windows))]
641656
fn test_kill_rekillable_task() {
642657
use rt::test::*;
643658

@@ -646,19 +661,49 @@ fn test_kill_rekillable_task() {
646661
do run_in_newsched_task {
647662
do task::try {
648663
do task::unkillable {
649-
unsafe {
650-
do task::rekillable {
651-
do task::spawn {
652-
fail!();
653-
}
664+
do task::rekillable {
665+
do task::spawn {
666+
fail!();
654667
}
655668
}
656669
}
657670
};
658671
}
659672
}
660673

661-
#[test] #[should_fail]
674+
#[test]
675+
#[should_fail]
676+
#[ignore(cfg(windows))]
677+
fn test_rekillable_not_nested() {
678+
do rekillable {
679+
// This should fail before
680+
// receiving anything since
681+
// this block should be nested
682+
// into a unkillable block.
683+
deschedule();
684+
}
685+
}
686+
687+
688+
#[test]
689+
#[ignore(cfg(windows))]
690+
fn test_rekillable_nested_failure() {
691+
692+
let result = do task::try {
693+
do unkillable {
694+
do rekillable {
695+
let (port,chan) = comm::stream();
696+
do task::spawn { chan.send(()); fail!(); }
697+
port.recv(); // wait for child to exist
698+
port.recv(); // block forever, expect to get killed.
699+
}
700+
}
701+
};
702+
assert!(result.is_err());
703+
}
704+
705+
706+
#[test] #[should_fail] #[ignore(cfg(windows))]
662707
fn test_cant_dup_task_builder() {
663708
let mut builder = task();
664709
builder.unlinked();

0 commit comments

Comments
 (0)