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/weak.rs | |
| 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/weak.rs')
| -rw-r--r-- | src/libstd/sys/unix/weak.rs | 81 | 
1 files changed, 81 insertions, 0 deletions
| 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 +} | 
