about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-03-11 09:56:57 -0700
committerbors <bors@rust-lang.org>2014-03-11 09:56:57 -0700
commit9f3ebd8fc50682d6e4ef549cb31e70171acdcd71 (patch)
tree568d189da6e6d954f880746411f923f4db5906a1 /src/libstd
parenta0f20f09fde77fb7330b1a67918744149dca3318 (diff)
parent699b33d060c5c9cc580d50cf3fe39536ae7a059a (diff)
downloadrust-9f3ebd8fc50682d6e4ef549cb31e70171acdcd71.tar.gz
rust-9f3ebd8fc50682d6e4ef549cb31e70171acdcd71.zip
auto merge of #12556 : alexcrichton/rust/weak-linkage, r=brson
It is often convenient to have forms of weak linkage or other various types of
linkage. Sadly, just using these flavors of linkage are not compatible with
Rust's typesystem and how it considers some pointers to be non-null.

As a compromise, this commit adds support for weak linkage to external symbols,
but it requires that this is only placed on extern statics of type `*T`.
Codegen-wise, we get translations like:

```rust
    // rust code
    extern {
        #[linkage = "extern_weak"]
        static foo: *i32;
    }

    // generated IR
    @foo = extern_weak global i32
    @_some_internal_symbol = internal global *i32 @foo
```

All references to the rust value of `foo` then reference `_some_internal_symbol`
instead of the symbol `_foo` itself. This allows us to guarantee that the
address of `foo` will never be null while the value may sometimes be null.

An example was implemented in `std::rt::thread` to determine if
`__pthread_get_minstack()` is available at runtime, and a test is checked in to
use it for a static value as well. Function pointers a little odd because you
still need to transmute the pointer value to a function pointer, but it's
thankfully better than not having this capability at all.

Thanks to @bnoordhuis for the original patch, most of this work is still his!
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/lib.rs5
-rw-r--r--src/libstd/rt/thread.rs63
2 files changed, 28 insertions, 40 deletions
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index bdc4fc387ca..4d3d1641bd0 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -52,10 +52,9 @@
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://static.rust-lang.org/doc/master")];
 
-#[feature(macro_rules, globs, asm, managed_boxes, thread_local, link_args, simd)];
+#[feature(macro_rules, globs, asm, managed_boxes, thread_local, link_args,
+          simd, linkage, default_type_params)];
 
-// Turn on default type parameters.
-#[feature(default_type_params)];
 // NOTE remove the following two attributes after the next snapshot.
 #[allow(unrecognized_lint)];
 #[allow(default_type_param_usage)];
diff --git a/src/libstd/rt/thread.rs b/src/libstd/rt/thread.rs
index 7b24c94b518..e27698d7dd0 100644
--- a/src/libstd/rt/thread.rs
+++ b/src/libstd/rt/thread.rs
@@ -221,7 +221,7 @@ mod imp {
                                                PTHREAD_CREATE_JOINABLE), 0);
 
         // Reserve room for the red zone, the runtime's stack of last resort.
-        let stack_size = cmp::max(stack, RED_ZONE + __pthread_get_minstack(&attr) as uint);
+        let stack_size = cmp::max(stack, RED_ZONE + min_stack_size(&attr) as uint);
         match pthread_attr_setstacksize(&mut attr, stack_size as libc::size_t) {
             0 => {
             },
@@ -261,51 +261,39 @@ mod imp {
     #[cfg(not(target_os = "macos"), not(target_os = "android"))]
     pub unsafe fn yield_now() { assert_eq!(pthread_yield(), 0); }
 
-    #[cfg(not(target_os = "linux"))]
-    unsafe fn __pthread_get_minstack(_: *libc::pthread_attr_t) -> libc::size_t {
-        libc::PTHREAD_STACK_MIN
-    }
-
     // glibc >= 2.15 has a __pthread_get_minstack() function that returns
     // PTHREAD_STACK_MIN plus however many bytes are needed for thread-local
     // 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.
     //
-    // Dynamically resolve the symbol for compatibility with older versions
-    // of glibc.  Assumes that we've been dynamically linked to libpthread
-    // but that is currently always the case.  Note that this means we take
-    // a dlopen/dlsym/dlclose hit for every new thread.  Mitigating that by
-    // caching the symbol or the function's return value has its drawbacks:
-    //
-    //  * Caching the symbol breaks when libpthread.so is reloaded because
-    //    its address changes.
-    //
-    //  * Caching the return value assumes that it's a fixed quantity.
-    //    Not very future-proof and untrue in the presence of guard pages
-    //    The reason __pthread_get_minstack() takes a *libc::pthread_attr_t
-    //    as its argument is because it takes pthread_attr_setguardsize() into
-    //    account.
-    //
-    // A better solution is to define __pthread_get_minstack() as a weak symbol
-    // but there is currently no way to express that in Rust code.
-    #[cfg(target_os = "linux")]
-    unsafe fn __pthread_get_minstack(attr: *libc::pthread_attr_t) -> libc::size_t {
-        use option::None;
-        use result::{Err, Ok};
-        use unstable::dynamic_lib;
-        match dynamic_lib::DynamicLibrary::open(None) {
-            Err(err) => fail!("DynamicLibrary::open(): {}", err),
-            Ok(handle) => {
-                match handle.symbol::<extern "C" fn(*libc::pthread_attr_t) ->
-                                     libc::size_t>("__pthread_get_minstack") {
-                    Err(_) => libc::PTHREAD_STACK_MIN,
-                    Ok(__pthread_get_minstack) => __pthread_get_minstack(attr),
-                }
-            }
+    // Link weakly to the symbol for compatibility with older versions of glibc.
+    // Assumes that we've been dynamically linked to libpthread but that is
+    // currently always the case.  Note that you need to check that the symbol
+    // is non-null before calling it!
+    #[cfg(target_os = "linux", not(stage0))]
+    fn min_stack_size(attr: *libc::pthread_attr_t) -> libc::size_t {
+        use ptr::RawPtr;
+        type F = extern "C" unsafe fn(*libc::pthread_attr_t) -> libc::size_t;
+        extern {
+            #[linkage = "extern_weak"]
+            static __pthread_get_minstack: *();
+        }
+        if __pthread_get_minstack.is_null() {
+            PTHREAD_STACK_MIN
+        } else {
+            unsafe { cast::transmute::<*(), F>(__pthread_get_minstack)(attr) }
         }
     }
 
+    // __pthread_get_minstack() is marked as weak but extern_weak linkage is
+    // not supported on OS X, hence this kludge...
+    #[cfg(not(target_os = "linux"))]
+    #[cfg(stage0)]
+    fn min_stack_size(_: *libc::pthread_attr_t) -> libc::size_t {
+        PTHREAD_STACK_MIN
+    }
+
     extern {
         fn pthread_create(native: *mut libc::pthread_t,
                           attr: *libc::pthread_attr_t,
@@ -347,3 +335,4 @@ mod tests {
         assert_eq!(42, Thread::start_stack(1, proc () 42).join());
     }
 }
+