native: Fix usage of a deallocated mutex
When the timer_helper thread exited, it would attempt to re-acquire the global task count mutex, but the mutex had previously been deallocated, leading to undefined behavior of the mutex, and in some cases deadlock. Another mutex is used to coordinate shutting down the timer helper thread. Closes #12699
This commit is contained in:
parent
d8bd8de82e
commit
e6acff8287
3 changed files with 36 additions and 16 deletions
|
@ -39,12 +39,9 @@ pub fn decrement() {
|
|||
/// the entry points of native programs
|
||||
pub fn wait_for_other_tasks() {
|
||||
unsafe {
|
||||
{
|
||||
let mut guard = TASK_LOCK.lock();
|
||||
while TASK_COUNT.load(atomics::SeqCst) > 0 {
|
||||
guard.wait();
|
||||
}
|
||||
let mut guard = TASK_LOCK.lock();
|
||||
while TASK_COUNT.load(atomics::SeqCst) > 0 {
|
||||
guard.wait();
|
||||
}
|
||||
TASK_LOCK.destroy();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,8 @@ use task;
|
|||
static mut HELPER_CHAN: *mut Chan<Req> = 0 as *mut Chan<Req>;
|
||||
static mut HELPER_SIGNAL: imp::signal = 0 as imp::signal;
|
||||
|
||||
static mut TIMER_HELPER_EXIT: StaticNativeMutex = NATIVE_MUTEX_INIT;
|
||||
|
||||
pub fn boot(helper: fn(imp::signal, Port<Req>)) {
|
||||
static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
|
||||
static mut INITIALIZED: bool = false;
|
||||
|
@ -53,6 +55,7 @@ pub fn boot(helper: fn(imp::signal, Port<Req>)) {
|
|||
task::spawn(proc() {
|
||||
bookkeeping::decrement();
|
||||
helper(receive, msgp);
|
||||
TIMER_HELPER_EXIT.lock().signal()
|
||||
});
|
||||
|
||||
rt::at_exit(proc() { shutdown() });
|
||||
|
@ -70,17 +73,15 @@ pub fn send(req: Req) {
|
|||
}
|
||||
|
||||
fn shutdown() {
|
||||
// We want to wait for the entire helper task to exit, and in doing so it
|
||||
// will attempt to decrement the global task count. When the helper was
|
||||
// created, it decremented the count so it wouldn't count towards preventing
|
||||
// the program to exit, so here we pair that manual decrement with a manual
|
||||
// increment. We will then wait for the helper thread to exit by calling
|
||||
// wait_for_other_tasks.
|
||||
bookkeeping::increment();
|
||||
|
||||
// Request a shutdown, and then wait for the task to exit
|
||||
send(Shutdown);
|
||||
bookkeeping::wait_for_other_tasks();
|
||||
unsafe {
|
||||
let mut guard = TIMER_HELPER_EXIT.lock();
|
||||
send(Shutdown);
|
||||
guard.wait();
|
||||
drop(guard);
|
||||
TIMER_HELPER_EXIT.destroy();
|
||||
}
|
||||
|
||||
|
||||
// Clean up after ther helper thread
|
||||
unsafe {
|
||||
|
|
22
src/test/run-pass/issue-12699.rs
Normal file
22
src/test/run-pass/issue-12699.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
extern crate native;
|
||||
|
||||
use std::io::timer;
|
||||
|
||||
#[start]
|
||||
fn start(argc: int, argv: **u8) -> int {
|
||||
native::start(argc, argv, main)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
timer::sleep(250);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue