Skip to content

Commit 1a31e1c

Browse files
committed
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.
1 parent 1bd2d20 commit 1a31e1c

File tree

4 files changed

+87
-28
lines changed

4 files changed

+87
-28
lines changed

src/liblibc

src/libstd/sys/unix/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ use ops::Neg;
2727
#[cfg(target_os = "openbsd")] pub use os::openbsd as platform;
2828
#[cfg(target_os = "solaris")] pub use os::solaris as platform;
2929

30+
#[macro_use]
31+
pub mod weak;
32+
3033
pub mod backtrace;
3134
pub mod condvar;
3235
pub mod ext;

src/libstd/sys/unix/thread.rs

+2-27
Original file line numberDiff line numberDiff line change
@@ -317,37 +317,12 @@ pub mod guard {
317317
// storage. We need that information to avoid blowing up when a small stack
318318
// is created in an application with big thread-local storage requirements.
319319
// See #6233 for rationale and details.
320-
//
321-
// Use dlsym to get the symbol value at runtime, both for
322-
// compatibility with older versions of glibc, and to avoid creating
323-
// dependencies on GLIBC_PRIVATE symbols. Assumes that we've been
324-
// dynamically linked to libpthread but that is currently always the
325-
// case. We previously used weak linkage (under the same assumption),
326-
// but that caused Debian to detect an unnecessarily strict versioned
327-
// dependency on libc6 (#23628).
328320
#[cfg(target_os = "linux")]
329321
#[allow(deprecated)]
330322
fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize {
331-
use dynamic_lib::DynamicLibrary;
332-
use sync::Once;
333-
334-
type F = unsafe extern "C" fn(*const libc::pthread_attr_t) -> libc::size_t;
335-
static INIT: Once = Once::new();
336-
static mut __pthread_get_minstack: Option<F> = None;
337-
338-
INIT.call_once(|| {
339-
let lib = match DynamicLibrary::open(None) {
340-
Ok(l) => l,
341-
Err(..) => return,
342-
};
343-
unsafe {
344-
if let Ok(f) = lib.symbol("__pthread_get_minstack") {
345-
__pthread_get_minstack = Some(mem::transmute::<*const (), F>(f));
346-
}
347-
}
348-
});
323+
weak!(fn __pthread_get_minstack(*const libc::pthread_attr_t) -> libc::size_t);
349324

350-
match unsafe { __pthread_get_minstack } {
325+
match __pthread_get_minstack.get() {
351326
None => libc::PTHREAD_STACK_MIN as usize,
352327
Some(f) => unsafe { f(attr) as usize },
353328
}

src/libstd/sys/unix/weak.rs

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! Support for "weak linkage" to symbols on Unix
12+
//!
13+
//! Some I/O operations we do in libstd require newer versions of OSes but we
14+
//! need to maintain binary compatibility with older releases for now. In order
15+
//! to use the new functionality when available we use this module for
16+
//! detection.
17+
//!
18+
//! One option to use here is weak linkage, but that is unfortunately only
19+
//! really workable on Linux. Hence, use dlsym to get the symbol value at
20+
//! runtime. This is also done for compatibility with older versions of glibc,
21+
//! and to avoid creating dependencies on GLIBC_PRIVATE symbols. It assumes that
22+
//! we've been dynamically linked to the library the symbol comes from, but that
23+
//! is currently always the case for things like libpthread/libc.
24+
//!
25+
//! A long time ago this used weak linkage for the __pthread_get_minstack
26+
//! symbol, but that caused Debian to detect an unnecessarily strict versioned
27+
//! dependency on libc6 (#23628).
28+
29+
use libc;
30+
31+
use ffi::CString;
32+
use marker;
33+
use mem;
34+
use sync::atomic::{AtomicUsize, Ordering};
35+
36+
macro_rules! weak {
37+
(fn $name:ident($($t:ty),*) -> $ret:ty) => (
38+
static $name: ::sys::weak::Weak<unsafe extern fn($($t),*) -> $ret> =
39+
::sys::weak::Weak::new(stringify!($name));
40+
)
41+
}
42+
43+
pub struct Weak<F> {
44+
name: &'static str,
45+
addr: AtomicUsize,
46+
_marker: marker::PhantomData<F>,
47+
}
48+
49+
impl<F> Weak<F> {
50+
pub const fn new(name: &'static str) -> Weak<F> {
51+
Weak {
52+
name: name,
53+
addr: AtomicUsize::new(1),
54+
_marker: marker::PhantomData,
55+
}
56+
}
57+
58+
pub fn get(&self) -> Option<&F> {
59+
assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
60+
unsafe {
61+
if self.addr.load(Ordering::SeqCst) == 1 {
62+
self.addr.store(fetch(self.name), Ordering::SeqCst);
63+
}
64+
mem::transmute::<&AtomicUsize, Option<&F>>(&self.addr)
65+
}
66+
}
67+
}
68+
69+
unsafe fn fetch(name: &str) -> usize {
70+
let name = match CString::new(name) {
71+
Ok(cstr) => cstr,
72+
Err(..) => return 0,
73+
};
74+
let lib = libc::dlopen(0 as *const _, libc::RTLD_LAZY);
75+
if lib.is_null() {
76+
return 0
77+
}
78+
let ret = libc::dlsym(lib, name.as_ptr()) as usize;
79+
libc::dlclose(lib);
80+
return ret
81+
}

0 commit comments

Comments
 (0)