about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/io/test.rs79
-rw-r--r--src/libstd/rt/task.rs18
-rw-r--r--src/libstd/sync/arc.rs2
3 files changed, 96 insertions, 3 deletions
diff --git a/src/libstd/io/test.rs b/src/libstd/io/test.rs
index dd24150e03e..e273aedf7cc 100644
--- a/src/libstd/io/test.rs
+++ b/src/libstd/io/test.rs
@@ -113,3 +113,82 @@ fn base_port() -> u16 {
 
     return final_base;
 }
+
+pub fn raise_fd_limit() {
+    unsafe { darwin_fd_limit::raise_fd_limit() }
+}
+
+#[cfg(target_os="macos")]
+#[allow(non_camel_case_types)]
+mod darwin_fd_limit {
+    /*!
+     * darwin_fd_limit exists to work around an issue where launchctl on Mac OS X defaults the
+     * rlimit maxfiles to 256/unlimited. The default soft limit of 256 ends up being far too low
+     * for our multithreaded scheduler testing, depending on the number of cores available.
+     *
+     * This fixes issue #7772.
+     */
+
+    use libc;
+    type rlim_t = libc::uint64_t;
+    struct rlimit {
+        rlim_cur: rlim_t,
+        rlim_max: rlim_t
+    }
+    #[nolink]
+    extern {
+        // name probably doesn't need to be mut, but the C function doesn't specify const
+        fn sysctl(name: *mut libc::c_int, namelen: libc::c_uint,
+                  oldp: *mut libc::c_void, oldlenp: *mut libc::size_t,
+                  newp: *mut libc::c_void, newlen: libc::size_t) -> libc::c_int;
+        fn getrlimit(resource: libc::c_int, rlp: *mut rlimit) -> libc::c_int;
+        fn setrlimit(resource: libc::c_int, rlp: *rlimit) -> libc::c_int;
+    }
+    static CTL_KERN: libc::c_int = 1;
+    static KERN_MAXFILESPERPROC: libc::c_int = 29;
+    static RLIMIT_NOFILE: libc::c_int = 8;
+
+    pub unsafe fn raise_fd_limit() {
+        // The strategy here is to fetch the current resource limits, read the kern.maxfilesperproc
+        // sysctl value, and bump the soft resource limit for maxfiles up to the sysctl value.
+        use ptr::{to_unsafe_ptr, to_mut_unsafe_ptr, mut_null};
+        use mem::size_of_val;
+        use os::last_os_error;
+
+        // Fetch the kern.maxfilesperproc value
+        let mut mib: [libc::c_int, ..2] = [CTL_KERN, KERN_MAXFILESPERPROC];
+        let mut maxfiles: libc::c_int = 0;
+        let mut size: libc::size_t = size_of_val(&maxfiles) as libc::size_t;
+        if sysctl(to_mut_unsafe_ptr(&mut mib[0]), 2,
+                  to_mut_unsafe_ptr(&mut maxfiles) as *mut libc::c_void,
+                  to_mut_unsafe_ptr(&mut size),
+                  mut_null(), 0) != 0 {
+            let err = last_os_error();
+            error!("raise_fd_limit: error calling sysctl: {}", err);
+            return;
+        }
+
+        // Fetch the current resource limits
+        let mut rlim = rlimit{rlim_cur: 0, rlim_max: 0};
+        if getrlimit(RLIMIT_NOFILE, to_mut_unsafe_ptr(&mut rlim)) != 0 {
+            let err = last_os_error();
+            error!("raise_fd_limit: error calling getrlimit: {}", err);
+            return;
+        }
+
+        // Bump the soft limit to the smaller of kern.maxfilesperproc and the hard limit
+        rlim.rlim_cur = ::cmp::min(maxfiles as rlim_t, rlim.rlim_max);
+
+        // Set our newly-increased resource limit
+        if setrlimit(RLIMIT_NOFILE, to_unsafe_ptr(&rlim)) != 0 {
+            let err = last_os_error();
+            error!("raise_fd_limit: error calling setrlimit: {}", err);
+            return;
+        }
+    }
+}
+
+#[cfg(not(target_os="macos"))]
+mod darwin_fd_limit {
+    pub unsafe fn raise_fd_limit() {}
+}
diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs
index 91e285b1061..c0e1086483d 100644
--- a/src/libstd/rt/task.rs
+++ b/src/libstd/rt/task.rs
@@ -38,8 +38,13 @@ use task::{TaskResult, TaskOpts};
 use unstable::finally::Finally;
 use unstable::mutex::{Mutex, MUTEX_INIT};
 
-#[cfg(stage0)] pub use rt::unwind::begin_unwind;
+#[cfg(stage0)]
+pub use rt::unwind::begin_unwind;
 
+// These two statics are used as bookeeping to keep track of the rust runtime's
+// count of threads. In 1:1 contexts, this is used to know when to return from
+// the main function, and in M:N contexts this is used to know when to shut down
+// the pool of schedulers.
 static mut TASK_COUNT: AtomicUint = INIT_ATOMIC_UINT;
 static mut TASK_LOCK: Mutex = MUTEX_INIT;
 
@@ -181,10 +186,15 @@ impl Task {
         // Cleanup the dynamic borrowck debugging info
         borrowck::clear_task_borrow_list();
 
-        // TODO: dox
+        // Here we must unsafely borrow the task in order to not remove it from
+        // TLS. When collecting failure, we may attempt to send on a channel (or
+        // just run aribitrary code), so we must be sure to still have a local
+        // task in TLS.
         unsafe {
             let me: *mut Task = Local::unsafe_borrow();
             (*me).death.collect_failure((*me).unwinder.result());
+
+            // see comments on these statics for why they're used
             if TASK_COUNT.fetch_sub(1, SeqCst) == 1 {
                 TASK_LOCK.lock();
                 TASK_LOCK.signal();
@@ -386,6 +396,10 @@ impl Drop for Death {
     }
 }
 
+/// The main function of all rust executables will by default use this function.
+/// This function will *block* the OS thread (hence the `unsafe`) waiting for
+/// all known tasks to complete. Once this function has returned, it is
+/// guaranteed that no more user-defined code is still running.
 pub unsafe fn wait_for_completion() {
     TASK_LOCK.lock();
     while TASK_COUNT.load(SeqCst) > 0 {
diff --git a/src/libstd/sync/arc.rs b/src/libstd/sync/arc.rs
index 7b94a3acc2b..b405104c09a 100644
--- a/src/libstd/sync/arc.rs
+++ b/src/libstd/sync/arc.rs
@@ -32,7 +32,7 @@ use vec;
 /// An atomically reference counted pointer.
 ///
 /// Enforces no shared-memory safety.
-#[unsafe_no_drop_flag]
+//#[unsafe_no_drop_flag] FIXME: #9758
 pub struct UnsafeArc<T> {
     priv data: *mut ArcData<T>,
 }