From abb3e132004996c2fc8de1b1e05e54a8f068fea9 Mon Sep 17 00:00:00 2001 From: zach Date: Thu, 6 Feb 2025 15:55:09 -0800 Subject: [PATCH] Update boxroot (#160) * chore: update boxroot bindings * cleanup: additional improvements for boxroot changes * cleanup: remove explicit call to caml_thread_initialize * cleanup: remove empty declaration * cleanup: remove caml_thread_initialize from ocaml-sys * chore: use boxroot 0.4.0 * cleanup: improve panic handler implementation * fix: no-std --- Cargo.toml | 2 +- src/lib.rs | 2 -- src/macros.rs | 39 +-------------------------- src/runtime.rs | 65 ++++++++++++++++++++++++++++++++++++++++----- sys/src/ocaml-sys.c | 4 +-- sys/src/runtime.rs | 1 + 6 files changed, 62 insertions(+), 51 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5be566a..fbda45e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ features = [ "derive", "without-ocamlopt", "ocaml5" ] [dependencies] ocaml-sys = {path = "./sys", version = ">=0.25"} -ocaml-boxroot-sys = {version = "0.3.1", default-features = false} +ocaml-boxroot-sys = {version = "0.4.0", default-features = false} ocaml-derive = {path = "./derive", optional = true, version = "^1.0.0"} cstr_core = {version = "0.2", optional = true} ndarray = {version = "^0.16.1", optional = true} diff --git a/src/lib.rs b/src/lib.rs index d4432d3..d5b1b0d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -162,8 +162,6 @@ pub use crate::tag::Tag; pub use crate::types::{bigarray, Array, List, Seq}; pub use crate::value::{FromValue, Raw, ToValue, Value}; -pub use crate::macros::initial_setup; - /// OCaml `float` pub type Float = f64; diff --git a/src/macros.rs b/src/macros.rs index 3fecc04..e245102 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1,37 +1,3 @@ -static PANIC_HANDLER_INIT: core::sync::atomic::AtomicBool = - core::sync::atomic::AtomicBool::new(false); - -#[doc(hidden)] -pub fn initial_setup() { - if PANIC_HANDLER_INIT - .compare_exchange( - false, - true, - core::sync::atomic::Ordering::Relaxed, - core::sync::atomic::Ordering::Relaxed, - ) - .is_err() - { - return; - } - - #[cfg(not(feature = "no-panic-hook"))] - { - ::std::panic::set_hook(Box::new(|info| { - let err = info.payload(); - let msg = if err.is::<&str>() { - err.downcast_ref::<&str>().unwrap().to_string() - } else if err.is::() { - err.downcast_ref::().unwrap().clone() - } else { - format!("{:?}", err) - }; - - crate::Error::raise_failure(&msg) - })) - } -} - /// `body!` is needed to help the OCaml runtime to manage garbage collection, it should /// be used to wrap the body of each function exported to OCaml. Panics from Rust code /// will automatically be unwound/caught here (unless the `no-std` feature is enabled) @@ -49,10 +15,7 @@ pub fn initial_setup() { #[macro_export] macro_rules! body { ($gc:ident: $code:block) => {{ - let $gc = unsafe { $crate::Runtime::recover_handle() }; - - // Ensure panic handler is initialized - $crate::initial_setup(); + let $gc = unsafe { &$crate::Runtime::init() }; { $code diff --git a/src/runtime.rs b/src/runtime.rs index b553e1b..e2cac06 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -1,6 +1,6 @@ /// OCaml runtime handle pub struct Runtime { - _private: (), + _panic_guard: PanicGuard, } static RUNTIME_INIT: core::sync::atomic::AtomicBool = core::sync::atomic::AtomicBool::new(false); @@ -9,7 +9,9 @@ impl Runtime { /// Initialize the OCaml runtime. pub fn init() -> Self { Self::init_persistent(); - Self { _private: () } + Self { + _panic_guard: PanicGuard::new(), + } } /// Initializes the OCaml runtime. @@ -44,7 +46,9 @@ impl Runtime { #[doc(hidden)] #[inline(always)] pub unsafe fn recover_handle() -> &'static Self { - static RUNTIME: Runtime = Runtime { _private: () }; + static RUNTIME: Runtime = Runtime { + _panic_guard: PanicGuard, + }; &RUNTIME } @@ -62,15 +66,12 @@ impl Runtime { /// Initialize the OCaml runtime, the runtime will be /// freed when the value goes out of scope pub fn init() -> Runtime { - let rt = Runtime::init(); - crate::initial_setup(); - rt + Runtime::init() } /// Initialize the OCaml runtime pub fn init_persistent() { Runtime::init_persistent(); - crate::initial_setup(); } /// Wrapper for `caml_leave_blocking_section` @@ -104,3 +105,53 @@ pub unsafe fn gc_full_major() { pub unsafe fn gc_compact() { ocaml_sys::caml_gc_compaction(ocaml_sys::UNIT); } + +#[cfg(not(feature = "no-std"))] +thread_local! { + #[allow(clippy::missing_const_for_thread_local)] + static GUARD_COUNT: core::cell::Cell = const { core::cell::Cell::new(0) }; +} + +#[cfg(not(feature = "no-std"))] +static INIT: std::sync::Once = std::sync::Once::new(); + +struct PanicGuard; + +impl PanicGuard { + #[cfg(not(any(feature = "no-panic-hook", feature = "no-std")))] + pub(crate) fn new() -> Self { + INIT.call_once(|| { + let original_hook = std::panic::take_hook(); + std::panic::set_hook(Box::new(move |panic_info| { + if GUARD_COUNT.with(|count| count.get()) > 0 { + let err = panic_info.payload(); + let msg = if let Some(s) = err.downcast_ref::<&str>() { + s.to_string() + } else if let Some(s) = err.downcast_ref::() { + s.clone() + } else { + format!("{:?}", err) + }; + crate::Error::raise_failure(&msg); + } else { + original_hook(panic_info); + } + })); + }); + + GUARD_COUNT.with(|count| count.set(count.get() + 1)); + PanicGuard + } + + #[cfg(any(feature = "no-panic-hook", feature = "no-std"))] + pub(crate) fn new() -> Self { + PanicGuard + } +} + +#[cfg(not(any(feature = "no-panic-hook", feature = "no-std")))] +impl Drop for PanicGuard { + fn drop(&mut self) { + GUARD_COUNT.with(|count| count.set(count.get() - 1)); + } +} diff --git a/sys/src/ocaml-sys.c b/sys/src/ocaml-sys.c index 920e5e0..f7ec0e5 100644 --- a/sys/src/ocaml-sys.c +++ b/sys/src/ocaml-sys.c @@ -9,6 +9,4 @@ void caml_sys_store_double_field(value x, mlsize_t index, double d) { Store_double_field(x, index, d); } -caml_domain_state* caml_sys_get_domain_state() { - return Caml_state; -} +caml_domain_state *caml_sys_get_domain_state() { return Caml_state; } diff --git a/sys/src/runtime.rs b/sys/src/runtime.rs index 0bef523..8310d66 100644 --- a/sys/src/runtime.rs +++ b/sys/src/runtime.rs @@ -7,6 +7,7 @@ extern "C" { pub fn caml_named_value(name: *const Char) -> *const Value; pub fn caml_enter_blocking_section(); pub fn caml_leave_blocking_section(); + pub fn caml_thread_initialize(unit: Value) -> Value; } // GC control