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:
commit
2fba2fea12
12 changed files with 136 additions and 45 deletions
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
28
src/test/run-pass/issue-12684.rs
Normal file
28
src/test/run-pass/issue-12684.rs
Normal 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();
|
||||
}
|
||||
24
src/test/run-pass/issue-12699.rs
Normal file
24
src/test/run-pass/issue-12699.rs
Normal 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);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue