From 70d2be0cec5b61dec30677654123044b50bb11f7 Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Thu, 1 Aug 2013 18:23:30 -0700 Subject: [PATCH 1/2] Revert "std::rt: Use a constant 4 threads for multithreaded sched tests" This workaround was less than ideal. A better solution is to raise the fd limit. This reverts commit 49b72bdd77916e27aaf95909516702c1450f11ac. --- src/libstd/rt/test.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/libstd/rt/test.rs b/src/libstd/rt/test.rs index 1ed0703de4d37..387ea3c62aad8 100644 --- a/src/libstd/rt/test.rs +++ b/src/libstd/rt/test.rs @@ -70,6 +70,7 @@ pub fn run_in_mt_newsched_task(f: ~fn()) { use os; use from_str::FromStr; use rt::sched::Shutdown; + use rt::util; let f = Cell::new(f); @@ -77,10 +78,10 @@ pub fn run_in_mt_newsched_task(f: ~fn()) { let nthreads = match os::getenv("RUST_RT_TEST_THREADS") { Some(nstr) => FromStr::from_str(nstr).get(), None => { - // A reasonable number of threads for testing - // multithreading. NB: It's easy to exhaust OS X's - // low maximum fd limit by setting this too high (#7772) - 4 + // Using more threads than cores in test code + // to force the OS to preempt them frequently. + // Assuming that this help stress test concurrent types. + util::num_cpus() * 2 } }; From 2001cc043b7c20af1f72b9c39e61070fd1c639f6 Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Wed, 17 Jul 2013 18:50:53 -0700 Subject: [PATCH 2/2] Bump fd limit on macos when running rt tests OS X defaults the ulimit for open files to 256 for programs launched from the Terminal (GUI apps get a higher default). Unfortunately this is too low for the rt tests, which deliberately overcommit and create a lot of threads (which means a lot of schedulers, and each scheduler needs at least 2 fds). By calling sysctl() and setrlimit() we can bump the fd limit up to the maximum allowed (on stock OS X it's 10240). Fixes #7772. --- src/libstd/rt/test.rs | 78 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/src/libstd/rt/test.rs b/src/libstd/rt/test.rs index 387ea3c62aad8..66ae085b1a081 100644 --- a/src/libstd/rt/test.rs +++ b/src/libstd/rt/test.rs @@ -63,6 +63,81 @@ pub fn run_in_newsched_task_core(f: ~fn()) { sched.bootstrap(task); } +#[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 sys::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: %s", 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: %s", 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: %s", err); + return; + } + } +} + +#[cfg(not(target_os="macos"))] +mod darwin_fd_limit { + pub unsafe fn raise_fd_limit() {} +} + /// Create more than one scheduler and run a function in a task /// in one of the schedulers. The schedulers will stay alive /// until the function `f` returns. @@ -72,6 +147,9 @@ pub fn run_in_mt_newsched_task(f: ~fn()) { use rt::sched::Shutdown; use rt::util; + // Bump the fd limit on OS X. See darwin_fd_limit for an explanation. + unsafe { darwin_fd_limit::raise_fd_limit() } + let f = Cell::new(f); do run_in_bare_thread {