about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-03-06 00:41:48 -0800
committerbors <bors@rust-lang.org>2014-03-06 00:41:48 -0800
commit2fba2fea121b616793287f33aa3ee05e8d8893b0 (patch)
tree7b6d2bd1a7449d81b9b6acb7c1099eca91df414d
parent2153293ae434861c72469d41fc7c9dfe9b90b1c4 (diff)
parent9668ab58f338b27d8f53357c7fd4ea3d3f06305e (diff)
downloadrust-2fba2fea121b616793287f33aa3ee05e8d8893b0.tar.gz
rust-2fba2fea121b616793287f33aa3ee05e8d8893b0.zip
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.
-rw-r--r--src/libnative/io/file_unix.rs16
-rw-r--r--src/libnative/io/timer_helper.rs23
-rw-r--r--src/libnative/io/timer_other.rs11
-rw-r--r--src/libnative/io/timer_timerfd.rs15
-rw-r--r--src/libnative/lib.rs2
-rw-r--r--src/libnative/task.rs4
-rw-r--r--src/libstd/libc.rs11
-rw-r--r--src/libstd/rt/bookkeeping.rs (renamed from src/libnative/bookkeeping.rs)28
-rw-r--r--src/libstd/rt/mod.rs4
-rw-r--r--src/rt/rust_builtin.c15
-rw-r--r--src/test/run-pass/issue-12684.rs28
-rw-r--r--src/test/run-pass/issue-12699.rs24
12 files changed, 136 insertions, 45 deletions
diff --git a/src/libnative/io/file_unix.rs b/src/libnative/io/file_unix.rs
index 4b6d1813ffa..cf9ada97a32 100644
--- a/src/libnative/io/file_unix.rs
+++ b/src/libnative/io/file_unix.rs
@@ -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))
diff --git a/src/libnative/io/timer_helper.rs b/src/libnative/io/timer_helper.rs
index 7669d4a658f..62e41771423 100644
--- a/src/libnative/io/timer_helper.rs
+++ b/src/libnative/io/timer_helper.rs
@@ -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 {
diff --git a/src/libnative/io/timer_other.rs b/src/libnative/io/timer_other.rs
index 9d700550863..d7323ddf499 100644
--- a/src/libnative/io/timer_other.rs
+++ b/src/libnative/io/timer_other.rs
@@ -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 {
diff --git a/src/libnative/io/timer_timerfd.rs b/src/libnative/io/timer_timerfd.rs
index 68277efc9b7..55301b6f7c8 100644
--- a/src/libnative/io/timer_timerfd.rs
+++ b/src/libnative/io/timer_timerfd.rs
@@ -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) {
diff --git a/src/libnative/lib.rs b/src/libnative/lib.rs
index 378283973db..4b6942a1083 100644
--- a/src/libnative/lib.rs
+++ b/src/libnative/lib.rs
@@ -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()
 }
diff --git a/src/libnative/task.rs b/src/libnative/task.rs
index aa3afd4c1a5..793e4d48e13 100644
--- a/src/libnative/task.rs
+++ b/src/libnative/task.rs
@@ -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 {
diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs
index 0ef8570ce30..afd524e9d7a 100644
--- a/src/libstd/libc.rs
+++ b/src/libstd/libc.rs
@@ -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;
diff --git a/src/libnative/bookkeeping.rs b/src/libstd/rt/bookkeeping.rs
index b1addc5cda5..5851a6a39c6 100644
--- a/src/libnative/bookkeeping.rs
+++ b/src/libstd/rt/bookkeeping.rs
@@ -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();
     }
 }
diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs
index 2f1a6989092..459bc061c56 100644
--- a/src/libstd/rt/mod.rs
+++ b/src/libstd/rt/mod.rs
@@ -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();
diff --git a/src/rt/rust_builtin.c b/src/rt/rust_builtin.c
index 81eba2984da..6ba121c5d2d 100644
--- a/src/rt/rust_builtin.c
+++ b/src/rt/rust_builtin.c
@@ -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
diff --git a/src/test/run-pass/issue-12684.rs b/src/test/run-pass/issue-12684.rs
new file mode 100644
index 00000000000..a6eef4e2021
--- /dev/null
+++ b/src/test/run-pass/issue-12684.rs
@@ -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();
+}
diff --git a/src/test/run-pass/issue-12699.rs b/src/test/run-pass/issue-12699.rs
new file mode 100644
index 00000000000..6409ba51375
--- /dev/null
+++ b/src/test/run-pass/issue-12699.rs
@@ -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);
+}