diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2016-02-04 13:56:59 -0800 | 
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2016-02-05 17:11:02 -0800 | 
| commit | 1a31e1c09f89daeefa06ca9336912e9bcadb0c1d (patch) | |
| tree | 21555a570bd032e4aab39c7f9a6ee6aa9c16eada /src/libstd/sys/unix | |
| parent | 1bd2d2016178fe85e42d4d34868e9bc58dfd5d07 (diff) | |
| download | rust-1a31e1c09f89daeefa06ca9336912e9bcadb0c1d.tar.gz rust-1a31e1c09f89daeefa06ca9336912e9bcadb0c1d.zip | |
std: Add a helper for symbols that may not exist
Right now we only attempt to call one symbol which my not exist everywhere, __pthread_get_minstack, but this pattern will come up more often as we start to bind newer functionality of systems like Linux. Take a similar strategy as the Windows implementation where we use `dlopen` to lookup whether a symbol exists or not.
Diffstat (limited to 'src/libstd/sys/unix')
| -rw-r--r-- | src/libstd/sys/unix/mod.rs | 3 | ||||
| -rw-r--r-- | src/libstd/sys/unix/thread.rs | 29 | ||||
| -rw-r--r-- | src/libstd/sys/unix/weak.rs | 81 | 
3 files changed, 86 insertions, 27 deletions
| 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; - - 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<F> = 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)); - } - } - }); + weak!(fn __pthread_get_minstack(*const libc::pthread_attr_t) -> libc::size_t); - 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<unsafe extern fn($($t),*) -> $ret> = + ::sys::weak::Weak::new(stringify!($name)); + ) +} + +pub struct Weak<F> { + name: &'static str, + addr: AtomicUsize, + _marker: marker::PhantomData<F>, +} + +impl<F> Weak<F> { + pub const fn new(name: &'static str) -> Weak<F> { + Weak { + name: name, + addr: AtomicUsize::new(1), + _marker: marker::PhantomData, + } + } + + pub fn get(&self) -> Option<&F> { + assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>()); + 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 +} | 
