1
Fork 0

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:
Alex Crichton 2014-03-04 18:20:46 -08:00
parent d8bd8de82e
commit e6acff8287
3 changed files with 36 additions and 16 deletions

View file

@ -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();
}
}

View file

@ -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 {

View 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);
}