diff --git a/Cargo.lock b/Cargo.lock index 797f4b22..ab1016ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1076,6 +1076,7 @@ dependencies = [ "rodbus-schema", "rust-oo-bindgen", "tokio", + "tokio-ffi-schema", "tracing", "tracing-core", "tracing-ffi-schema", @@ -1097,6 +1098,7 @@ name = "rodbus-schema" version = "1.0.0" dependencies = [ "oo-bindgen", + "tokio-ffi-schema", "tracing-ffi-schema", ] @@ -1402,6 +1404,14 @@ dependencies = [ "winapi", ] +[[package]] +name = "tokio-ffi-schema" +version = "0.1.0" +source = "git+https://github.com/stepfunc/tokio-ffi.git?tag=0.1.0#d25867ac956adf265d2f5f8830834ac5f78edbe5" +dependencies = [ + "oo-bindgen", +] + [[package]] name = "tokio-macros" version = "1.8.0" diff --git a/dep_config.json b/dep_config.json index acc8a30a..a094407d 100644 --- a/dep_config.json +++ b/dep_config.json @@ -21,7 +21,6 @@ "same-file", "semver", "semver-parser", - "tracing-ffi-schema", "ucd-trie", "unicode-segmentation", "version_check", @@ -43,6 +42,12 @@ }, "scursor": { "url": "https://github.com/stepfunc/scursor" + }, + "tokio-ffi-schema": { + "url": "https://github.com/stepfunc/tokio-ffi" + }, + "tracing-ffi-schema": { + "url": "https://github.com/stepfunc/tracing-ffi" } }, "third_party": { diff --git a/ffi/rodbus-ffi/Cargo.toml b/ffi/rodbus-ffi/Cargo.toml index 1f81d880..f13d3c8a 100644 --- a/ffi/rodbus-ffi/Cargo.toml +++ b/ffi/rodbus-ffi/Cargo.toml @@ -25,6 +25,7 @@ num_cpus = "1" rodbus-schema = { path = "../rodbus-schema" } rust-oo-bindgen = { git = "https://github.com/stepfunc/oo_bindgen.git", tag = "0.3.0" } tracing-ffi-schema = { git = "https://github.com/stepfunc/tracing-ffi.git", tag = "0.1.0" } +tokio-ffi-schema = { git = "https://github.com/stepfunc/tokio-ffi.git", tag = "0.1.0" } [features] default = ["serial", "tls"] diff --git a/ffi/rodbus-ffi/build.rs b/ffi/rodbus-ffi/build.rs index 6246a6ff..f945e14f 100644 --- a/ffi/rodbus-ffi/build.rs +++ b/ffi/rodbus-ffi/build.rs @@ -2,14 +2,27 @@ use std::env; use std::io::Write; use std::path::Path; -fn main() { - println!("cargo:rerun-if-changed=build.rs"); - +fn write_tracing_ffi() { let mut file = std::fs::File::create(Path::new(&env::var_os("OUT_DIR").unwrap()).join("tracing.rs")) .unwrap(); file.write_all(tracing_ffi_schema::get_impl_file().as_bytes()) .unwrap(); +} + +fn write_tokio_ffi() { + let mut file = + std::fs::File::create(Path::new(&env::var_os("OUT_DIR").unwrap()).join("runtime.rs")) + .unwrap(); + file.write_all(tokio_ffi_schema::get_impl_file().as_bytes()) + .unwrap(); +} + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + + write_tracing_ffi(); + write_tokio_ffi(); match rodbus_schema::build_lib() { Ok(lib) => { diff --git a/ffi/rodbus-ffi/src/lib.rs b/ffi/rodbus-ffi/src/lib.rs index ebe0938e..d7466a1c 100644 --- a/ffi/rodbus-ffi/src/lib.rs +++ b/ffi/rodbus-ffi/src/lib.rs @@ -27,16 +27,41 @@ pub use server::*; pub mod ffi; +lazy_static::lazy_static! { + static ref VERSION: std::ffi::CString = std::ffi::CString::new(rodbus::VERSION).unwrap(); +} + +fn version() -> &'static std::ffi::CStr { + &VERSION +} + +// the From<> impls below are needed to map tracing and tokio ffi stuff to the actual errors used in this crate + impl From for std::os::raw::c_int { fn from(_: crate::TracingInitError) -> Self { crate::ffi::ParamError::LoggingAlreadyConfigured.into() } } -lazy_static::lazy_static! { - static ref VERSION: std::ffi::CString = std::ffi::CString::new(rodbus::VERSION).unwrap(); +impl From for crate::ffi::ParamError { + fn from(err: crate::runtime::RuntimeError) -> Self { + match err { + crate::runtime::RuntimeError::RuntimeDestroyed => { + crate::ffi::ParamError::RuntimeDestroyed + } + crate::runtime::RuntimeError::CannotBlockWithinAsync => { + crate::ffi::ParamError::RuntimeCannotBlockWithinAsync + } + crate::runtime::RuntimeError::FailedToCreateRuntime => { + crate::ffi::ParamError::RuntimeCreationFailure + } + } + } } -fn version() -> &'static std::ffi::CStr { - &VERSION +impl From for std::os::raw::c_int { + fn from(err: crate::runtime::RuntimeError) -> Self { + let err: crate::ffi::ParamError = err.into(); + err.into() + } } diff --git a/ffi/rodbus-ffi/src/runtime.rs b/ffi/rodbus-ffi/src/runtime.rs index 2b3510f1..c15ee8df 100644 --- a/ffi/rodbus-ffi/src/runtime.rs +++ b/ffi/rodbus-ffi/src/runtime.rs @@ -1,81 +1 @@ -use std::future::Future; - -use crate::ffi; - -pub struct Runtime { - pub(crate) inner: std::sync::Arc, -} - -impl Runtime { - fn new(inner: tokio::runtime::Runtime) -> Self { - Self { - inner: std::sync::Arc::new(inner), - } - } - - pub(crate) fn handle(&self) -> RuntimeHandle { - RuntimeHandle { - inner: std::sync::Arc::downgrade(&self.inner), - } - } -} - -#[derive(Clone)] -pub(crate) struct RuntimeHandle { - inner: std::sync::Weak, -} - -impl RuntimeHandle { - pub(crate) fn block_on(&self, future: F) -> Result { - let inner = self - .inner - .upgrade() - .ok_or(ffi::ParamError::RuntimeDestroyed)?; - if tokio::runtime::Handle::try_current().is_ok() { - return Err(ffi::ParamError::RuntimeCannotBlockWithinAsync); - } - Ok(inner.block_on(future)) - } - - pub(crate) fn spawn(&self, future: F) -> Result<(), ffi::ParamError> - where - F: Future + Send + 'static, - F::Output: Send + 'static, - { - let inner = self - .inner - .upgrade() - .ok_or(ffi::ParamError::RuntimeDestroyed)?; - inner.spawn(future); - Ok(()) - } -} - -fn build_runtime(f: F) -> std::result::Result -where - F: Fn(&mut tokio::runtime::Builder) -> &mut tokio::runtime::Builder, -{ - let mut builder = tokio::runtime::Builder::new_multi_thread(); - f(&mut builder).enable_all().build() -} - -pub(crate) unsafe fn runtime_create( - config: ffi::RuntimeConfig, -) -> Result<*mut crate::runtime::Runtime, ffi::ParamError> { - let num_threads = if config.num_core_threads == 0 { - num_cpus::get() - } else { - config.num_core_threads as usize - }; - - tracing::info!("creating runtime with {} threads", num_threads); - let runtime = build_runtime(|r| r.worker_threads(num_threads as usize)) - .map_err(|_| ffi::ParamError::RuntimeCreationFailure)?; - Ok(Box::into_raw(Box::new(Runtime::new(runtime)))) -} - -pub(crate) unsafe fn runtime_destroy(runtime: *mut crate::runtime::Runtime) { - if !runtime.is_null() { - drop(Box::from_raw(runtime)); - }; -} +include!(concat!(env!("OUT_DIR"), "/runtime.rs")); diff --git a/ffi/rodbus-schema/Cargo.toml b/ffi/rodbus-schema/Cargo.toml index 721b829d..614d680b 100644 --- a/ffi/rodbus-schema/Cargo.toml +++ b/ffi/rodbus-schema/Cargo.toml @@ -14,3 +14,4 @@ readme = "../README.md" [dependencies] oo-bindgen = { git = "https://github.com/stepfunc/oo_bindgen.git", tag = "0.3.0" } tracing-ffi-schema = { git = "https://github.com/stepfunc/tracing-ffi.git", tag = "0.1.0" } +tokio-ffi-schema = { git = "https://github.com/stepfunc/tokio-ffi.git", tag = "0.1.0" } diff --git a/ffi/rodbus-schema/src/common.rs b/ffi/rodbus-schema/src/common.rs index 83fb2daa..abda6a78 100644 --- a/ffi/rodbus-schema/src/common.rs +++ b/ffi/rodbus-schema/src/common.rs @@ -31,7 +31,7 @@ impl CommonDefinitions { error_type: error_type.clone(), nothing, decode_level, - runtime_handle: crate::runtime::define(lib, error_type)?, + runtime_handle: tokio_ffi_schema::define(lib, error_type)?, error_info: build_request_error(lib)?, address_range: build_address_range(lib)?, request_param: build_request_param(lib)?, diff --git a/ffi/rodbus-schema/src/lib.rs b/ffi/rodbus-schema/src/lib.rs index 7c9d57d5..0d971f80 100644 --- a/ffi/rodbus-schema/src/lib.rs +++ b/ffi/rodbus-schema/src/lib.rs @@ -6,7 +6,6 @@ use oo_bindgen::model::*; mod client; mod common; mod decoding; -mod runtime; mod server; // derived from Cargo.toml diff --git a/ffi/rodbus-schema/src/runtime.rs b/ffi/rodbus-schema/src/runtime.rs deleted file mode 100644 index 3e4be517..00000000 --- a/ffi/rodbus-schema/src/runtime.rs +++ /dev/null @@ -1,64 +0,0 @@ -use oo_bindgen::model::*; - -fn define_runtime_config(lib: &mut LibraryBuilder) -> BackTraced { - let num_core_threads = Name::create("num_core_threads")?; - - let config_struct = lib.declare_function_argument_struct("runtime_config")?; - let config_struct= lib - .define_function_argument_struct(config_struct)? - .add( - &num_core_threads, - Primitive::U16, - doc("Number of runtime threads to spawn. For a guess of the number of CPU cores, use 0.") - .details("Even if tons of connections are expected, it is preferred to use a value around the number of CPU cores for better performances. The library uses an efficient thread pool polling mechanism."), - )? - .doc("Configuration options for the Runtime")? - .end_fields()? - .begin_initializer("init", InitializerType::Normal, "Initialize the configuration to default values")? - .default(&num_core_threads, NumberValue::U16(0))? - .end_initializer()? - .build()?; - - Ok(config_struct) -} - -pub fn define( - lib: &mut LibraryBuilder, - error_type: ErrorTypeHandle, -) -> BackTraced { - // Forward declare the class - let runtime = lib.declare_class("runtime")?; - - let config_struct = define_runtime_config(lib)?; - - let constructor = lib - .define_constructor(runtime.clone())? - .param( - "config", - config_struct, - "Runtime configuration", - )? - .fails_with(error_type)? - .doc( - doc("Creates a new runtime for running the protocol stack.") - .warning("The runtime should be kept alive for as long as it's needed and it should be released with {class:runtime.[destructor]}") - )? - .build()?; - - let destructor = lib - .define_destructor( - runtime.clone(), - doc("Destroy a runtime.") - .details("This method will gracefully wait for all asynchronous operation to end before returning") - )?; - - let runtime = lib - .define_class(&runtime)? - .constructor(constructor)? - .destructor(destructor)? - .custom_destroy("shutdown")? - .doc("Handle to the underlying runtime")? - .build()?; - - Ok(runtime.declaration.clone()) -}