Skip to content

Commit

Permalink
Move from lazy_static to a weak static in C lib
Browse files Browse the repository at this point in the history
Sadly, a C library is necessary for this, as `#[linkage="weak"]` is still
unstable in Rust.

Sadly, much like with the lazy-static mutex implementation, it is a
wide-hitting hammer and will also hit platforms which aren’t affected by
this (by virtue of using thread-local dlerrors).

This will require a "major" version bump.

Fixes #32
  • Loading branch information
nagisa committed Jan 8, 2018
1 parent 4b7f66a commit d870a38
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 10 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ license = "ISC"
repository = "https://github.com/nagisa/rust_libloading/"
documentation = "https://docs.rs/libloading/"

[dependencies]
lazy_static = "1"
[build-dependencies.cc]
version = "1.0"

[target.'cfg(windows)'.dependencies.winapi]
version = "0.3"
Expand Down
8 changes: 8 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
extern crate cc;

use std::io::Write;
use std::env;

fn main(){
let target_os = env::var("CARGO_CFG_TARGET_OS");
let is_unix = env::var_os("CARGO_CFG_UNIX").is_some();
match target_os.as_ref().map(|x| &**x) {
Ok("linux") | Ok("android") => println!("cargo:rustc-link-lib=dl"),
Ok("freebsd") | Ok("dragonfly") => println!("cargo:rustc-link-lib=c"),
Expand All @@ -20,4 +23,9 @@ fn main(){
::std::process::exit(0xfc);
}
}
if is_unix {
cc::Build::new()
.file("src/os/unix/global_static.c")
.compile("global_static");
}
}
4 changes: 0 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,6 @@ use std::fmt;
use std::ops;
use std::marker;

#[cfg(unix)]
#[macro_use]
extern crate lazy_static;

#[cfg(unix)]
use self::os::unix as imp;
#[cfg(windows)]
Expand Down
20 changes: 20 additions & 0 deletions src/os/unix/global_static.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include <pthread.h>
#include <stdlib.h>

pthread_mutex_t __attribute__((weak)) rust_libloading_dlerror_mutex = PTHREAD_MUTEX_INITIALIZER;

void __attribute__((weak))
rust_libloading_dlerror_mutex_lock(void)
{
if (pthread_mutex_lock(&rust_libloading_dlerror_mutex) != 0) {
abort();
}
}

void __attribute__((weak))
rust_libloading_dlerror_mutex_unlock(void)
{
if (pthread_mutex_unlock(&rust_libloading_dlerror_mutex) != 0) {
abort();
}
}
27 changes: 23 additions & 4 deletions src/os/unix/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,29 @@ use std::ffi::{CStr, OsStr};
use std::{fmt, io, marker, mem, ptr};
use std::os::raw;
use std::os::unix::ffi::OsStrExt;
use std::sync::Mutex;

lazy_static! {
static ref DLERROR_MUTEX: Mutex<()> = Mutex::new(());
extern "C" {
fn rust_libloading_dlerror_mutex_lock();
fn rust_libloading_dlerror_mutex_unlock();
}

struct DlerrorMutexGuard(());

impl DlerrorMutexGuard {
fn new() -> DlerrorMutexGuard {
unsafe {
rust_libloading_dlerror_mutex_lock();
}
DlerrorMutexGuard(())
}
}

impl Drop for DlerrorMutexGuard {
fn drop(&mut self) {
unsafe {
rust_libloading_dlerror_mutex_unlock();
}
}
}

// libdl is crazy.
Expand All @@ -19,7 +38,7 @@ fn with_dlerror<T, F>(closure: F) -> Result<T, Option<io::Error>>
where F: FnOnce() -> Option<T> {
// We will guard all uses of libdl library with our own mutex. This makes libdl
// safe to use in MT programs provided the only way a program uses libdl is via this library.
let _lock = DLERROR_MUTEX.lock();
let _lock = DlerrorMutexGuard::new();
// While we could could call libdl here to clear the previous error value, only the dlsym
// depends on it being cleared beforehand and only in some cases too. We will instead clear the
// error inside the dlsym binding instead.
Expand Down

0 comments on commit d870a38

Please sign in to comment.