Skip to content

Commit

Permalink
Merge pull request #12 from bearcove/no-ctor
Browse files Browse the repository at this point in the history
Don't rely on ctor, run check once per SO lazily
  • Loading branch information
fasterthanlime committed Jul 23, 2024
2 parents cbcf73b + ee52ab0 commit ea85477
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 64 deletions.
46 changes: 0 additions & 46 deletions rubicon/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions rubicon/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ keywords = ["ffi", "thread-local"]
crate-type = ["dylib"]

[dependencies]
ctor = { version = "0.2.8", optional = true }
libc = { version = "0.2.155", optional = true }
paste = { version = "1.0.15", optional = true }

Expand All @@ -24,5 +23,4 @@ rustc_version = { version = "0.4.0", optional = true }
[features]
default = []
export-globals = ["dep:paste", "dep:rustc_version"]
import-globals = ["dep:paste", "dep:rustc_version", "dep:ctor", "dep:libc"]
ctor = ["dep:ctor"]
import-globals = ["dep:paste", "dep:rustc_version", "dep:libc"]
44 changes: 29 additions & 15 deletions rubicon/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,6 @@ compile_error!("The features `export-globals` and `import-globals` are mutually
#[cfg(any(feature = "export-globals", feature = "import-globals"))]
pub use paste::paste;

#[cfg(feature = "import-globals")]
pub use ctor;

#[cfg(feature = "import-globals")]
pub use libc;

Expand All @@ -54,13 +51,18 @@ pub const RUBICON_TARGET_TRIPLE: &str = env!("RUBICON_TARGET_TRIPLE");

/// Wrapper around an `extern` `static` ref to avoid requiring `unsafe` for imported globals.
#[doc(hidden)]
pub struct TrustedExtern<T: 'static>(pub &'static T);
pub struct TrustedExtern<T: 'static>(pub &'static T, pub fn());

use std::ops::Deref;

impl<T> Deref for TrustedExtern<T> {
type Target = T;

#[inline(always)]
fn deref(&self) -> &Self::Target {
// this is a good time to run compatibility checks
(self.1)();

self.0
}
}
Expand All @@ -73,12 +75,16 @@ impl<T> Deref for TrustedExtern<T> {
///
/// As a result, imported thread-locals have an additional layer of indirection.
#[doc(hidden)]
pub struct TrustedExternDouble<T: 'static>(pub &'static &'static T);
pub struct TrustedExternDouble<T: 'static>(pub &'static &'static T, pub fn());

impl<T> Deref for TrustedExternDouble<T> {
type Target = T;

#[inline(always)]
fn deref(&self) -> &Self::Target {
// autoderef goes brrr
// this is a good time to run compatibility checks
(self.1)();

self.0
}
}
Expand Down Expand Up @@ -173,7 +179,7 @@ macro_rules! thread_local_inner {
// even though this ends up being not a LocalKey, but a type that Derefs to LocalKey,
// in practice, most codebases work just fine with this, since they call methods
// that takes `self: &LocalKey`: they don't see the difference.
$vis static $name: $crate::TrustedExternDouble<::std::thread::LocalKey<$ty>> = $crate::TrustedExternDouble(unsafe { &[<$name __rubicon_import>] });
$vis static $name: $crate::TrustedExternDouble<::std::thread::LocalKey<$ty>> = $crate::TrustedExternDouble(unsafe { &[<$name __rubicon_import>] }, crate::compatibility_check_once);
}
};
}
Expand Down Expand Up @@ -280,7 +286,7 @@ macro_rules! process_local_inner {
static [<$name __rubicon_import>]: $ty;
}

$vis static $name: $crate::TrustedExtern<$ty> = $crate::TrustedExtern(unsafe { &[<$name __rubicon_import>] });
$vis static $name: $crate::TrustedExtern<$ty> = $crate::TrustedExtern(unsafe { &[<$name __rubicon_import>] }, crate::compatibility_check_once);
}
};
}
Expand Down Expand Up @@ -328,7 +334,6 @@ macro_rules! compatibility_check {
macro_rules! compatibility_check {
($($feature:tt)*) => {
use std::env;
use $crate::ctor::ctor;

extern "Rust" {
#[link_name = concat!(env!("CARGO_PKG_NAME"), "_compatibility_info")]
Expand Down Expand Up @@ -408,8 +413,16 @@ macro_rules! compatibility_check {
len
}

#[ctor]
fn check_compatibility() {
// this one is _actually_ meant to exist once per shared object
static COMPATIBILITY_CHECK_ONCE: std::sync::Once = std::sync::Once::new();

pub fn compatibility_check_once() {
COMPATIBILITY_CHECK_ONCE.call_once(|| {
check_compatibility();
});
}

pub fn check_compatibility() {
eprintln!("Entering check_compatibility function");
let imported: &[(&str, &str)] = &[
("rustc-version", $crate::RUBICON_RUSTC_VERSION),
Expand All @@ -424,6 +437,7 @@ macro_rules! compatibility_check {

if missing.is_empty() && extra.is_empty() {
eprintln!("No compatibility issues found");

// all good
return;
}
Expand All @@ -439,7 +453,7 @@ macro_rules! compatibility_check {
error_message.push_str("\n\x1b[31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m\n");
error_message.push_str(&format!(" 💀 Feature mismatch for crate \x1b[31m{}\x1b[0m\n\n", env!("CARGO_PKG_NAME")));

error_message.push_str(&format!("Loading {} would mix different configurations of the {} crate.\n\n", blue(so_name), red(env!("CARGO_PKG_NAME"))));
error_message.push_str(&format!("{} has an incompatible configuration for {}.\n\n", blue(so_name), red(env!("CARGO_PKG_NAME"))));

eprintln!("Calculating column widths for grid display");
// Compute max lengths for alignment
Expand Down Expand Up @@ -520,8 +534,8 @@ macro_rules! compatibility_check {
let imported_value = imported.iter().find(|&(k, _)| k == key).map(|(_, v)| v);

let key_column = colored(AnsiColor::GREY, key).to_string();
let binary_column = format_column(imported_value.as_deref().copied(), exported_value.as_deref().copied(), AnsiColor::RED);
let module_column = format_column(exported_value.as_deref().copied(), imported_value.as_deref().copied(), AnsiColor::GREEN);
let binary_column = format_column(exported_value.as_deref().copied(), imported_value.as_deref().copied(), AnsiColor::GREEN);
let module_column = format_column(imported_value.as_deref().copied(), exported_value.as_deref().copied(), AnsiColor::RED);

fn format_column(primary: Option<&str>, secondary: Option<&str>, highlight_color: AnsiColor) -> String {
match primary {
Expand All @@ -532,7 +546,7 @@ macro_rules! compatibility_check {
colored(highlight_color, value).to_string()
}
},
None => colored(AnsiColor::GREY, "∅").to_string(),
None => colored(AnsiColor::RED, "∅").to_string(),
}
}

Expand Down

0 comments on commit ea85477

Please sign in to comment.