diff --git a/src/liblibc b/src/liblibc index 30f70baa6cc..a64ee24718c 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 30f70baa6cc1ba3ddebb55b988fafbad0c0cc810 +Subproject commit a64ee24718c0289b82a77d692cf56f8a1226de51 diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index f8a4bcdecd7..01769a75afd 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -27,6 +27,9 @@ use ops::Neg; #[cfg(target_os = "openbsd")] pub use os::openbsd as platform; #[cfg(target_os = "solaris")] pub use os::solaris as platform; +#[macro_use] +pub mod weak; + pub mod backtrace; pub mod condvar; pub mod ext; diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 277aa5f19f0..a7195bab741 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -317,37 +317,12 @@ pub mod guard { // 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. -// -// Use dlsym to get the symbol value at runtime, both for -// compatibility with older versions of glibc, and to avoid creating -// dependencies on GLIBC_PRIVATE symbols. Assumes that we've been -// dynamically linked to libpthread but that is currently always the -// case. We previously used weak linkage (under the same assumption), -// but that caused Debian to detect an unnecessarily strict versioned -// dependency on libc6 (#23628). #[cfg(target_os = "linux")] #[allow(deprecated)] fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize { - use dynamic_lib::DynamicLibrary; - use sync::Once; + weak!(fn __pthread_get_minstack(*const libc::pthread_attr_t) -> libc::size_t); - type F = unsafe extern "C" fn(*const libc::pthread_attr_t) -> libc::size_t; - static INIT: Once = Once::new(); - static mut __pthread_get_minstack: Option = None; - - INIT.call_once(|| { - let lib = match DynamicLibrary::open(None) { - Ok(l) => l, - Err(..) => return, - }; - unsafe { - if let Ok(f) = lib.symbol("__pthread_get_minstack") { - __pthread_get_minstack = Some(mem::transmute::<*const (), F>(f)); - } - } - }); - - match unsafe { __pthread_get_minstack } { + match __pthread_get_minstack.get() { None => libc::PTHREAD_STACK_MIN as usize, Some(f) => unsafe { f(attr) as usize }, } diff --git a/src/libstd/sys/unix/weak.rs b/src/libstd/sys/unix/weak.rs new file mode 100644 index 00000000000..2cbcd62f533 --- /dev/null +++ b/src/libstd/sys/unix/weak.rs @@ -0,0 +1,81 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Support for "weak linkage" to symbols on Unix +//! +//! Some I/O operations we do in libstd require newer versions of OSes but we +//! need to maintain binary compatibility with older releases for now. In order +//! to use the new functionality when available we use this module for +//! detection. +//! +//! One option to use here is weak linkage, but that is unfortunately only +//! really workable on Linux. Hence, use dlsym to get the symbol value at +//! runtime. This is also done for compatibility with older versions of glibc, +//! and to avoid creating dependencies on GLIBC_PRIVATE symbols. It assumes that +//! we've been dynamically linked to the library the symbol comes from, but that +//! is currently always the case for things like libpthread/libc. +//! +//! A long time ago this used weak linkage for the __pthread_get_minstack +//! symbol, but that caused Debian to detect an unnecessarily strict versioned +//! dependency on libc6 (#23628). + +use libc; + +use ffi::CString; +use marker; +use mem; +use sync::atomic::{AtomicUsize, Ordering}; + +macro_rules! weak { + (fn $name:ident($($t:ty),*) -> $ret:ty) => ( + static $name: ::sys::weak::Weak $ret> = + ::sys::weak::Weak::new(stringify!($name)); + ) +} + +pub struct Weak { + name: &'static str, + addr: AtomicUsize, + _marker: marker::PhantomData, +} + +impl Weak { + pub const fn new(name: &'static str) -> Weak { + Weak { + name: name, + addr: AtomicUsize::new(1), + _marker: marker::PhantomData, + } + } + + pub fn get(&self) -> Option<&F> { + assert_eq!(mem::size_of::(), mem::size_of::()); + unsafe { + if self.addr.load(Ordering::SeqCst) == 1 { + self.addr.store(fetch(self.name), Ordering::SeqCst); + } + mem::transmute::<&AtomicUsize, Option<&F>>(&self.addr) + } + } +} + +unsafe fn fetch(name: &str) -> usize { + let name = match CString::new(name) { + Ok(cstr) => cstr, + Err(..) => return 0, + }; + let lib = libc::dlopen(0 as *const _, libc::RTLD_LAZY); + if lib.is_null() { + return 0 + } + let ret = libc::dlsym(lib, name.as_ptr()) as usize; + libc::dlclose(lib); + return ret +}