Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate out caml_startup-dependent code into runtime library #36

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ocaml-interop"
version = "0.8.4" # remember to update html_root_url
version = "0.9.0" # remember to update html_root_url
authors = ["Bruno Deferrari <utizoc@gmail.com>"]
license = "MIT"
description = "Utilities for Rust and OCaml interoperability"
Expand Down
16 changes: 16 additions & 0 deletions runtime/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "ocaml-interop-runtime"
version = "0.9.0" # remember to update html_root_url
authors = ["Bruno Deferrari <utizoc@gmail.com>"]
license = "MIT"
description = "Runtime utilities for Rust and OCaml interoperability"
homepage = "http://github.com/tezedge/ocaml-interop"
repository = "http://github.com/tezedge/ocaml-interop"
keywords = ["ocaml", "rust", "ffi", "interop"]
edition = "2018"

[dependencies]
ocaml-interop = "0.9.0"
ocaml-sys = "^0.20.1"
ocaml-boxroot-sys = "0.2"
static_assertions = "1.1.0"
28 changes: 28 additions & 0 deletions runtime/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) Viable Systems and TezEdge Contributors
// SPDX-License-Identifier: MIT
use std::sync::Once;
use ocaml_sys::{caml_startup};
use ocaml_interop::OCamlRuntime;

/// Initializes the OCaml runtime and returns an OCaml runtime handle.
///
/// Once the handle is dropped, the OCaml runtime will be shutdown.
pub fn init() -> OCamlRuntime {
init_persistent();
unsafe { ocaml_interop::OCamlRuntime::create() }
}

/// Initializes the OCaml runtime.
///
/// After the first invocation, this method does nothing.
pub fn init_persistent() {
static INIT: Once = Once::new();

INIT.call_once(|| {
let arg0 = "ocaml\0".as_ptr() as *const ocaml_sys::Char;
let c_args = vec![arg0, core::ptr::null()];
unsafe {
caml_startup(c_args.as_ptr());
}
})
}
7 changes: 4 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,10 @@
//! result.to_rust::<i64>(cr) as usize
//! }
//!
//! fn entry_point() {
//! /* NB: Requires ocaml_interop_runtime as a dependency */
//! /*fn entry_point() {
//! // IMPORTANT: the OCaml runtime has to be initialized first.
//! let mut cr = OCamlRuntime::init();
//! let mut cr = ocaml_interop_runtime::init();
//! // `cr` is the OCaml runtime handle, must be passed to any function
//! // that interacts with the OCaml runtime.
//! let first_n = twice(&mut cr, 5);
Expand All @@ -220,7 +221,7 @@
//! println!("Bytes2 after: {}", result2);
//! // `OCamlRuntime`'s `Drop` implementation will pefrorm the necessary cleanup
//! // to shutdown the OCaml runtime.
//! }
//! }*/
//! ```
//!
//! ### Calling into Rust from OCaml
Expand Down
44 changes: 18 additions & 26 deletions src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// SPDX-License-Identifier: MIT

use ocaml_boxroot_sys::{boxroot_setup, boxroot_teardown};
use ocaml_sys::{caml_shutdown, caml_startup};
use std::{marker::PhantomData, sync::Once};
use ocaml_sys::{caml_shutdown};
use std::{marker::PhantomData};

use crate::{memory::OCamlRef, value::OCaml};

Expand All @@ -18,42 +18,34 @@ pub struct OCamlRuntime {
}

impl OCamlRuntime {
/// Initializes the OCaml runtime and returns an OCaml runtime handle.
/// Recover the runtime handle.
///
/// Once the handle is dropped, the OCaml runtime will be shutdown.
pub fn init() -> Self {
Self::init_persistent();
Self { _private: () }
}

/// Initializes the OCaml runtime.
/// # Safety
///
/// After the first invocation, this method does nothing.
pub fn init_persistent() {
static INIT: Once = Once::new();

INIT.call_once(|| {
let arg0 = "ocaml\0".as_ptr() as *const ocaml_sys::Char;
let c_args = vec![arg0, core::ptr::null()];
unsafe {
caml_startup(c_args.as_ptr());
}
})
/// This function is unsafe because the OCaml runtime handle should be obtained once
/// upon initialization of the OCaml runtime and then passed around. This method exists
/// to allow the capture of the runtime when it is already known to have been
/// initialized.
#[inline(always)]
pub unsafe fn recover_handle() -> &'static mut Self {
static mut RUNTIME: OCamlRuntime = OCamlRuntime { _private: () };
&mut RUNTIME
}

/// Recover the runtime handle.
/// Create a new runtime handle.
///
/// This method is used internally, do not use directly in code, only when writing tests.
///
/// # Safety
///
/// This function is unsafe because the OCaml runtime handle should be obtained once
/// upon initialization of the OCaml runtime and then passed around. This method exists
/// only to ease the authoring of tests.
/// to allow the creation of a runtime after `caml_startup` has been called and the
/// runtime is initialized. The OCaml runtime will be shutdown when this value is
/// dropped.
#[inline(always)]
pub unsafe fn recover_handle() -> &'static mut Self {
static mut RUNTIME: OCamlRuntime = OCamlRuntime { _private: () };
&mut RUNTIME
pub unsafe fn create() -> Self {
OCamlRuntime { _private: () }
}

/// Release the OCaml runtime lock, call `f`, and re-acquire the OCaml runtime lock.
Expand Down
3 changes: 3 additions & 0 deletions testing/rust-caller/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,8 @@ edition = "2018"
[dependencies.ocaml-interop]
path = "../.."

[dependencies.ocaml-interop-runtime]
path = "../../runtime"

[dev-dependencies]
serial_test = "*"
28 changes: 14 additions & 14 deletions testing/rust-caller/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,15 +161,15 @@ use serial_test::serial;
#[test]
#[serial]
fn test_twice() {
OCamlRuntime::init_persistent();
ocaml_interop_runtime::init_persistent();
let mut cr = unsafe { OCamlRuntime::recover_handle() };
assert_eq!(twice(&mut cr, 10), 20);
}

#[test]
#[serial]
fn test_increment_bytes() {
OCamlRuntime::init_persistent();
ocaml_interop_runtime::init_persistent();
let mut cr = unsafe { OCamlRuntime::recover_handle() };
assert_eq!(
increment_bytes(&mut cr, "0000000000000000", 10),
Expand All @@ -180,7 +180,7 @@ fn test_increment_bytes() {
#[test]
#[serial]
fn test_increment_ints_list() {
OCamlRuntime::init_persistent();
ocaml_interop_runtime::init_persistent();
let mut cr = unsafe { OCamlRuntime::recover_handle() };
let ints = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let expected = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
Expand All @@ -190,7 +190,7 @@ fn test_increment_ints_list() {
#[test]
#[serial]
fn test_make_tuple() {
OCamlRuntime::init_persistent();
ocaml_interop_runtime::init_persistent();
let mut cr = unsafe { OCamlRuntime::recover_handle() };
assert_eq!(
make_tuple(&mut cr, "fst".to_owned(), 9),
Expand All @@ -201,7 +201,7 @@ fn test_make_tuple() {
#[test]
#[serial]
fn test_make_some() {
OCamlRuntime::init_persistent();
ocaml_interop_runtime::init_persistent();
let mut cr = unsafe { OCamlRuntime::recover_handle() };
assert_eq!(
make_some(&mut cr, "some".to_owned()),
Expand All @@ -212,7 +212,7 @@ fn test_make_some() {
#[test]
#[serial]
fn test_make_result() {
OCamlRuntime::init_persistent();
ocaml_interop_runtime::init_persistent();
let mut cr = unsafe { OCamlRuntime::recover_handle() };
assert_eq!(make_ok(&mut cr, 10), Ok(10));
assert_eq!(
Expand All @@ -224,15 +224,15 @@ fn test_make_result() {
#[test]
#[serial]
fn test_frame_management() {
OCamlRuntime::init_persistent();
ocaml_interop_runtime::init_persistent();
let mut cr = unsafe { OCamlRuntime::recover_handle() };
assert_eq!(allocate_alot(&mut cr), true);
}

#[test]
#[serial]
fn test_record_conversion() {
OCamlRuntime::init_persistent();
ocaml_interop_runtime::init_persistent();
let mut cr = unsafe { OCamlRuntime::recover_handle() };
let record = ocaml::TestRecord {
i: 10,
Expand All @@ -249,7 +249,7 @@ fn test_record_conversion() {
#[test]
#[serial]
fn test_variant_conversion() {
OCamlRuntime::init_persistent();
ocaml_interop_runtime::init_persistent();
let mut cr = unsafe { OCamlRuntime::recover_handle() };
assert_eq!(
verify_variant_test(&mut cr, ocaml::Movement::RotateLeft),
Expand All @@ -268,7 +268,7 @@ fn test_variant_conversion() {
#[test]
#[serial]
fn test_polymorphic_variant_conversion() {
OCamlRuntime::init_persistent();
ocaml_interop_runtime::init_persistent();
let mut cr = unsafe { OCamlRuntime::recover_handle() };
assert_eq!(
verify_polymorphic_variant_test(&mut cr, ocaml::PolymorphicEnum::Unit),
Expand All @@ -287,7 +287,7 @@ fn test_polymorphic_variant_conversion() {
#[test]
#[serial]
fn test_exception_handling_with_message() {
OCamlRuntime::init_persistent();
ocaml_interop_runtime::init_persistent();
let result = std::panic::catch_unwind(move || {
let mut cr = unsafe { OCamlRuntime::recover_handle() };
let mcr = &mut cr;
Expand All @@ -306,7 +306,7 @@ fn test_exception_handling_with_message() {
#[test]
#[serial]
fn test_exception_handling_without_message() {
OCamlRuntime::init_persistent();
ocaml_interop_runtime::init_persistent();
let result = std::panic::catch_unwind(|| {
let cr = unsafe { OCamlRuntime::recover_handle() };
ocaml::raises_nonmessage_exception(cr, &OCaml::unit());
Expand All @@ -323,7 +323,7 @@ fn test_exception_handling_without_message() {
#[test]
#[serial]
fn test_exception_handling_nonblock_exception() {
OCamlRuntime::init_persistent();
ocaml_interop_runtime::init_persistent();
let result = std::panic::catch_unwind(|| {
let cr = unsafe { OCamlRuntime::recover_handle() };
ocaml::raises_nonblock_exception(cr, &OCaml::unit());
Expand All @@ -340,7 +340,7 @@ fn test_exception_handling_nonblock_exception() {
#[test]
#[serial]
fn test_dynbox() {
OCamlRuntime::init_persistent();
ocaml_interop_runtime::init_persistent();
let mut cr = unsafe { OCamlRuntime::recover_handle() };

let mut list = OCaml::nil().root();
Expand Down