@@ -221,7 +221,7 @@ mod imp {
221221 PTHREAD_CREATE_JOINABLE ) , 0 ) ;
222222
223223 // Reserve room for the red zone, the runtime's stack of last resort.
224- let stack_size = cmp:: max ( stack, RED_ZONE + PTHREAD_STACK_MIN as uint ) ;
224+ let stack_size = cmp:: max ( stack, RED_ZONE + __pthread_get_minstack ( & attr ) as uint ) ;
225225 match pthread_attr_setstacksize ( & mut attr, stack_size as libc:: size_t ) {
226226 0 => {
227227 } ,
@@ -261,6 +261,51 @@ mod imp {
261261 #[ cfg( not( target_os = "macos" ) , not( target_os = "android" ) ) ]
262262 pub unsafe fn yield_now ( ) { assert_eq ! ( pthread_yield( ) , 0 ) ; }
263263
264+ #[ cfg( not( target_os = "linux" ) ) ]
265+ unsafe fn __pthread_get_minstack ( _: * libc:: pthread_attr_t ) -> libc:: size_t {
266+ libc:: PTHREAD_STACK_MIN
267+ }
268+
269+ // glibc >= 2.15 has a __pthread_get_minstack() function that returns
270+ // PTHREAD_STACK_MIN plus however many bytes are needed for thread-local
271+ // storage. We need that information to avoid blowing up when a small stack
272+ // is created in an application with big thread-local storage requirements.
273+ // See #6233 for rationale and details.
274+ //
275+ // Dynamically resolve the symbol for compatibility with older versions
276+ // of glibc. Assumes that we've been dynamically linked to libpthread
277+ // but that is currently always the case. Note that this means we take
278+ // a dlopen/dlsym/dlclose hit for every new thread. Mitigating that by
279+ // caching the symbol or the function's return value has its drawbacks:
280+ //
281+ // * Caching the symbol breaks when libpthread.so is reloaded because
282+ // its address changes.
283+ //
284+ // * Caching the return value assumes that it's a fixed quantity.
285+ // Not very future-proof and untrue in the presence of guard pages
286+ // The reason __pthread_get_minstack() takes a *libc::pthread_attr_t
287+ // as its argument is because it takes pthread_attr_setguardsize() into
288+ // account.
289+ //
290+ // A better solution is to define __pthread_get_minstack() as a weak symbol
291+ // but there is currently no way to express that in Rust code.
292+ #[ cfg( target_os = "linux" ) ]
293+ unsafe fn __pthread_get_minstack ( attr : * libc:: pthread_attr_t ) -> libc:: size_t {
294+ use option:: None ;
295+ use result:: { Err , Ok } ;
296+ use unstable:: dynamic_lib;
297+ match dynamic_lib:: DynamicLibrary :: open ( None ) {
298+ Err ( err) => fail ! ( "DynamicLibrary::open(): {}" , err) ,
299+ Ok ( handle) => {
300+ match handle. symbol :: < extern "C" fn ( * libc:: pthread_attr_t ) ->
301+ libc:: size_t > ( "__pthread_get_minstack" ) {
302+ Err ( _) => libc:: PTHREAD_STACK_MIN ,
303+ Ok ( __pthread_get_minstack) => __pthread_get_minstack ( attr) ,
304+ }
305+ }
306+ }
307+ }
308+
264309 extern {
265310 fn pthread_create ( native : * mut libc:: pthread_t ,
266311 attr : * libc:: pthread_attr_t ,
0 commit comments