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.
This commit is contained in:
Ben Noordhuis 2014-01-29 18:19:23 +01:00
parent b02b5cdcf4
commit 431edacbef

View File

@ -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,