about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorBen Noordhuis <info@bnoordhuis.nl>2014-01-29 18:19:23 +0100
committerBen Noordhuis <info@bnoordhuis.nl>2014-01-31 13:47:25 +0100
commit431edacbef23e691d1b192da78b4112c35addfbf (patch)
tree2bd5f9664b3b572ac447b18deef2a931950fed54 /src/libstd
parentb02b5cdcf42b4fe6b1e3ebe56ad0cd43fd907489 (diff)
downloadrust-431edacbef23e691d1b192da78b4112c35addfbf.tar.gz
rust-431edacbef23e691d1b192da78b4112c35addfbf.zip
Use __pthread_get_minstack() when available.
glibc >= 2.15 has a __pthread_get_minstack() function that returns
PTHREAD_STACK_MIN plus however many bytes are needed for thread-local
storage.  Use it when it's available because just PTHREAD_STACK_MIN is
not enough in applications that have big thread-local storage
requirements.

Fixes #6233.
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/rt/thread.rs47
1 files changed, 46 insertions, 1 deletions
diff --git a/src/libstd/rt/thread.rs b/src/libstd/rt/thread.rs
index 605923ac99c..b762c1173f5 100644
--- a/src/libstd/rt/thread.rs
+++ b/src/libstd/rt/thread.rs
@@ -221,7 +221,7 @@ mod imp {
                                                PTHREAD_CREATE_JOINABLE), 0);
 
         // Reserve room for the red zone, the runtime's stack of last resort.
-        let stack_size = cmp::max(stack, RED_ZONE + PTHREAD_STACK_MIN as uint);
+        let stack_size = cmp::max(stack, RED_ZONE + __pthread_get_minstack(&attr) as uint);
         match pthread_attr_setstacksize(&mut attr, stack_size as libc::size_t) {
             0 => {
             },
@@ -261,6 +261,51 @@ mod imp {
     #[cfg(not(target_os = "macos"), not(target_os = "android"))]
     pub unsafe fn yield_now() { assert_eq!(pthread_yield(), 0); }
 
+    #[cfg(not(target_os = "linux"))]
+    unsafe fn __pthread_get_minstack(_: *libc::pthread_attr_t) -> libc::size_t {
+        libc::PTHREAD_STACK_MIN
+    }
+
+    // glibc >= 2.15 has a __pthread_get_minstack() function that returns
+    // PTHREAD_STACK_MIN plus however many bytes are needed for thread-local
+    // storage.  We need that information to avoid blowing up when a small stack
+    // is created in an application with big thread-local storage requirements.
+    // See #6233 for rationale and details.
+    //
+    // Dynamically resolve the symbol for compatibility with older versions
+    // of glibc.  Assumes that we've been dynamically linked to libpthread
+    // but that is currently always the case.  Note that this means we take
+    // a dlopen/dlsym/dlclose hit for every new thread.  Mitigating that by
+    // caching the symbol or the function's return value has its drawbacks:
+    //
+    //  * Caching the symbol breaks when libpthread.so is reloaded because
+    //    its address changes.
+    //
+    //  * Caching the return value assumes that it's a fixed quantity.
+    //    Not very future-proof and untrue in the presence of guard pages
+    //    The reason __pthread_get_minstack() takes a *libc::pthread_attr_t
+    //    as its argument is because it takes pthread_attr_setguardsize() into
+    //    account.
+    //
+    // A better solution is to define __pthread_get_minstack() as a weak symbol
+    // but there is currently no way to express that in Rust code.
+    #[cfg(target_os = "linux")]
+    unsafe fn __pthread_get_minstack(attr: *libc::pthread_attr_t) -> libc::size_t {
+        use option::None;
+        use result::{Err, Ok};
+        use unstable::dynamic_lib;
+        match dynamic_lib::DynamicLibrary::open(None) {
+            Err(err) => fail!("DynamicLibrary::open(): {}", err),
+            Ok(handle) => {
+                match handle.symbol::<extern "C" fn(*libc::pthread_attr_t) ->
+                                     libc::size_t>("__pthread_get_minstack") {
+                    Err(_) => libc::PTHREAD_STACK_MIN,
+                    Ok(__pthread_get_minstack) => __pthread_get_minstack(attr),
+                }
+            }
+        }
+    }
+
     extern {
         fn pthread_create(native: *mut libc::pthread_t,
                           attr: *libc::pthread_attr_t,