auto merge of #12705 : alexcrichton/rust/issue-12692, r=brson

Details are in the commit messages, but this closes a few issues seen with `libnative` recently.
This commit is contained in:
bors 2014-03-06 00:41:48 -08:00
commit 2fba2fea12
12 changed files with 136 additions and 45 deletions

View file

@ -19,6 +19,7 @@ use std::libc;
use std::mem;
use std::rt::rtio;
use std::vec;
use std::vec_ng::Vec;
use io::{IoResult, retry, keep_going};
@ -341,7 +342,7 @@ pub fn mkdir(p: &CString, mode: io::FilePermission) -> IoResult<()> {
pub fn readdir(p: &CString) -> IoResult<~[Path]> {
use std::libc::{dirent_t};
use std::libc::{opendir, readdir, closedir};
use std::libc::{opendir, readdir_r, closedir};
fn prune(root: &CString, dirs: ~[Path]) -> ~[Path] {
let root = unsafe { CString::new(root.with_ref(|p| p), false) };
@ -353,9 +354,14 @@ pub fn readdir(p: &CString) -> IoResult<~[Path]> {
}
extern {
fn rust_list_dir_val(ptr: *dirent_t) -> *libc::c_char;
fn rust_dirent_t_size() -> libc::c_int;
fn rust_list_dir_val(ptr: *mut dirent_t) -> *libc::c_char;
}
let size = unsafe { rust_dirent_t_size() };
let mut buf = Vec::<u8>::with_capacity(size as uint);
let ptr = buf.as_mut_slice().as_mut_ptr() as *mut dirent_t;
debug!("os::list_dir -- BEFORE OPENDIR");
let dir_ptr = p.with_ref(|buf| unsafe { opendir(buf) });
@ -363,13 +369,13 @@ pub fn readdir(p: &CString) -> IoResult<~[Path]> {
if dir_ptr as uint != 0 {
let mut paths = ~[];
debug!("os::list_dir -- opendir() SUCCESS");
let mut entry_ptr = unsafe { readdir(dir_ptr) };
while entry_ptr as uint != 0 {
let mut entry_ptr = 0 as *mut dirent_t;
while unsafe { readdir_r(dir_ptr, ptr, &mut entry_ptr) == 0 } {
if entry_ptr.is_null() { break }
let cstr = unsafe {
CString::new(rust_list_dir_val(entry_ptr), false)
};
paths.push(Path::new(cstr));
entry_ptr = unsafe { readdir(dir_ptr) };
}
assert_eq!(unsafe { closedir(dir_ptr) }, 0);
Ok(prune(p, paths))

View file

@ -21,10 +21,10 @@
//! time.
use std::cast;
use std::rt::bookkeeping;
use std::rt;
use std::unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
use bookkeeping;
use io::timer::{Req, Shutdown};
use task;
@ -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

@ -218,8 +218,15 @@ impl Timer {
}
pub fn sleep(ms: u64) {
// FIXME: this can fail because of EINTR, what do do?
let _ = unsafe { libc::usleep((ms * 1000) as libc::c_uint) };
let mut to_sleep = libc::timespec {
tv_sec: (ms / 1000) as libc::time_t,
tv_nsec: ((ms % 1000) * 1000000) as libc::c_long,
};
while unsafe { libc::nanosleep(&to_sleep, &mut to_sleep) } != 0 {
if os::errno() as int != libc::EINTR as int {
fail!("failed to sleep, but not because of EINTR?");
}
}
}
fn inner(&mut self) -> ~Inner {

View file

@ -23,8 +23,8 @@
//! why).
//!
//! As with timer_other, timers just using sleep() do not use the timerfd at
//! all. They remove the timerfd from the worker thread and then invoke usleep()
//! to block the calling thread.
//! all. They remove the timerfd from the worker thread and then invoke
//! nanosleep() to block the calling thread.
//!
//! As with timer_other, all units in this file are in units of millseconds.
@ -183,8 +183,15 @@ impl Timer {
}
pub fn sleep(ms: u64) {
// FIXME: this can fail because of EINTR, what do do?
let _ = unsafe { libc::usleep((ms * 1000) as libc::c_uint) };
let mut to_sleep = libc::timespec {
tv_sec: (ms / 1000) as libc::time_t,
tv_nsec: ((ms % 1000) * 1000000) as libc::c_long,
};
while unsafe { libc::nanosleep(&to_sleep, &mut to_sleep) } != 0 {
if os::errno() as int != libc::EINTR as int {
fail!("failed to sleep, but not because of EINTR?");
}
}
}
fn remove(&mut self) {

View file

@ -58,7 +58,6 @@
use std::os;
use std::rt;
mod bookkeeping;
pub mod io;
pub mod task;
@ -105,6 +104,5 @@ pub fn start(argc: int, argv: **u8, main: proc()) -> int {
/// number of arguments.
pub fn run(main: proc()) -> int {
main();
bookkeeping::wait_for_other_tasks();
os::get_exit_status()
}

View file

@ -16,19 +16,19 @@
use std::any::Any;
use std::cast;
use std::rt::bookkeeping;
use std::rt::env;
use std::rt::local::Local;
use std::rt::rtio;
use std::rt::stack;
use std::rt::task::{Task, BlockedTask, SendMessage};
use std::rt::thread::Thread;
use std::rt;
use std::task::TaskOpts;
use std::unstable::mutex::NativeMutex;
use std::rt::stack;
use io;
use task;
use bookkeeping;
/// Creates a new Task which is ready to execute as a 1:1 task.
pub fn new(stack_bounds: (uint, uint)) -> ~Task {

View file

@ -3658,13 +3658,16 @@ pub mod funcs {
pub unsafe fn opendir(dirname: *c_char) -> *DIR {
rust_opendir(dirname)
}
pub unsafe fn readdir(dirp: *DIR) -> *dirent_t {
rust_readdir(dirp)
pub unsafe fn readdir_r(dirp: *DIR,
entry: *mut dirent_t,
result: *mut *mut dirent_t) -> c_int {
rust_readdir_r(dirp, entry, result)
}
extern {
fn rust_opendir(dirname: *c_char) -> *DIR;
fn rust_readdir(dirp: *DIR) -> *dirent_t;
fn rust_readdir_r(dirp: *DIR, entry: *mut dirent_t,
result: *mut *mut dirent_t) -> c_int;
}
extern {
@ -3680,6 +3683,7 @@ pub mod funcs {
use libc::types::common::c95::c_void;
use libc::types::os::arch::c95::{c_char, c_int, c_long, c_uint};
use libc::types::os::arch::c95::{size_t};
use libc::types::os::common::posix01::timespec;
use libc::types::os::arch::posix01::utimbuf;
use libc::types::os::arch::posix88::{gid_t, off_t, pid_t};
use libc::types::os::arch::posix88::{ssize_t, uid_t};
@ -3729,6 +3733,7 @@ pub mod funcs {
pub fn setuid(uid: uid_t) -> c_int;
pub fn sleep(secs: c_uint) -> c_uint;
pub fn usleep(secs: c_uint) -> c_int;
pub fn nanosleep(rqtp: *timespec, rmtp: *mut timespec) -> c_int;
pub fn sysconf(name: c_int) -> c_long;
pub fn tcgetpgrp(fd: c_int) -> pid_t;
pub fn ttyname(fd: c_int) -> *c_char;

View file

@ -8,16 +8,21 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! 1:1 Task bookkeeping
//! Task bookkeeping
//!
//! This module keeps track of the number of running 1:1 tasks so that entry
//! points with libnative know when it's possible to exit the program (once all
//! tasks have exited).
//! This module keeps track of the number of running tasks so that entry points
//! with libnative know when it's possible to exit the program (once all tasks
//! have exited).
//!
//! The green counterpart for this is bookkeeping on sched pools.
//! The green counterpart for this is bookkeeping on sched pools, and it's up to
//! each respective runtime to make sure that they call increment() and
//! decrement() manually.
use std::sync::atomics;
use std::unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
#[experimental]; // this is a massive code smell
#[doc(hidden)];
use sync::atomics;
use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
static mut TASK_COUNT: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT;
static mut TASK_LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
@ -39,12 +44,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

@ -128,6 +128,9 @@ pub mod args;
// Support for running procedures when a program has exited.
mod at_exit_imp;
// Bookkeeping for task counts
pub mod bookkeeping;
// Stack overflow protection
pub mod stack;
@ -207,6 +210,7 @@ pub fn at_exit(f: proc()) {
/// Invoking cleanup while portions of the runtime are still in use may cause
/// undefined behavior.
pub unsafe fn cleanup() {
bookkeeping::wait_for_other_tasks();
at_exit_imp::run();
args::cleanup();
local_ptr::cleanup();

View file

@ -279,9 +279,14 @@ rust_opendir(char *dirname) {
return opendir(dirname);
}
struct dirent*
rust_readdir(DIR *dirp) {
return readdir(dirp);
int
rust_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) {
return readdir_r(dirp, entry, result);
}
int
rust_dirent_t_size() {
return sizeof(struct dirent);
}
#else
@ -294,6 +299,10 @@ void
rust_readdir() {
}
void
rust_dirent_t_size() {
}
#endif
uintptr_t

View file

@ -0,0 +1,28 @@
// Copyright 2013-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.
// ignore-fast
extern crate native;
extern crate green;
extern crate rustuv;
#[start]
fn start(argc: int, argv: **u8) -> int { green::start(argc, argv, main) }
fn main() {
native::task::spawn(proc() customtask());
}
fn customtask() {
let mut timer = std::io::timer::Timer::new().unwrap();
let periodic = timer.periodic(10);
periodic.recv();
}

View file

@ -0,0 +1,24 @@
// 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.
// ignore-fast
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);
}