feat: runtime
This commit is contained in:
parent
7eef137bcd
commit
b400124096
@ -52,9 +52,9 @@ lazy val root = project
|
|||||||
},
|
},
|
||||||
cargoBuild := {
|
cargoBuild := {
|
||||||
println(Seq("sh", "-c", "cd glue; cargo rustc -- -Awarnings") !!)
|
println(Seq("sh", "-c", "cd glue; cargo rustc -- -Awarnings") !!)
|
||||||
println(
|
//println(
|
||||||
Seq("sh", "-c", "cd glue; cargo test --quiet") !!
|
// Seq("sh", "-c", "cd glue; RUST_BACKTRACE=full cargo test --quiet --features e2e") !!
|
||||||
) // very important: test suite validates interfaces
|
//) // very important: test suite validates interfaces
|
||||||
},
|
},
|
||||||
fullBuild := {
|
fullBuild := {
|
||||||
cargoBuild.value
|
cargoBuild.value
|
||||||
|
3
glue/Cargo.lock
generated
3
glue/Cargo.lock
generated
@ -571,6 +571,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"jni",
|
"jni",
|
||||||
"nb",
|
"nb",
|
||||||
|
"no-std-net",
|
||||||
"tinyvec",
|
"tinyvec",
|
||||||
"toad",
|
"toad",
|
||||||
"toad-jni",
|
"toad-jni",
|
||||||
@ -580,8 +581,6 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "toad-jni"
|
name = "toad-jni"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9d47119dc7ecc1c65fa860a7b2c95dd45b177d07331ee8a18cac0cc41c9bd825"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jni",
|
"jni",
|
||||||
"toad-array 0.5.0",
|
"toad-array 0.5.0",
|
||||||
|
@ -7,10 +7,15 @@ publish = false
|
|||||||
[lib]
|
[lib]
|
||||||
crate_type = ["cdylib"]
|
crate_type = ["cdylib"]
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["e2e"]
|
||||||
|
e2e = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
jni = "0.21.1"
|
jni = "0.21.1"
|
||||||
nb = "1"
|
nb = "1"
|
||||||
toad = "0.17.3"
|
toad = "0.17.3"
|
||||||
toad-jni = "0.5.1"
|
toad-jni = {path = "../../toad/toad-jni"} # "0.6.0"
|
||||||
|
no-std-net = "0.6"
|
||||||
toad-msg = "0.18.1"
|
toad-msg = "0.18.1"
|
||||||
tinyvec = {version = "1.5", default_features = false, features = ["rustc_1_55"]}
|
tinyvec = {version = "1.5", default_features = false, features = ["rustc_1_55"]}
|
||||||
|
35
glue/src/e2e.rs
Normal file
35
glue/src/e2e.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
use std::sync::Once;
|
||||||
|
|
||||||
|
use no_std_net::SocketAddr;
|
||||||
|
use toad::platform::Platform;
|
||||||
|
use toad_jni::java::{self, Object};
|
||||||
|
use toad::net::Addrd;
|
||||||
|
use toad_msg::{Type, Id, Token, alloc::Message, Code};
|
||||||
|
|
||||||
|
use crate::{runtime::Runtime, runtime_config::RuntimeConfig};
|
||||||
|
|
||||||
|
pub fn runtime_init<'a>() -> (Runtime, java::Env<'a>) {
|
||||||
|
let mut _env = crate::test::init();
|
||||||
|
let env = &mut _env;
|
||||||
|
|
||||||
|
let cfg = RuntimeConfig::new(env);
|
||||||
|
let runtime = Runtime::get_or_init(env, cfg);
|
||||||
|
(runtime, _env)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn runtime_poll_req(runtime: &Runtime, env: &mut java::Env) {
|
||||||
|
assert!(runtime.poll_req(env).is_none());
|
||||||
|
|
||||||
|
let client = crate::Runtime::try_new("0.0.0.0:5684", Default::default()).unwrap();
|
||||||
|
let request = Message::new(Type::Con, Code::GET, Id(0), Token(Default::default()));
|
||||||
|
client.send_msg(Addrd(request, "0.0.0.0:5683".parse().unwrap())).unwrap();
|
||||||
|
|
||||||
|
assert!(runtime.poll_req(env).is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn e2e_test_suite() {
|
||||||
|
let (runtime, mut env) = runtime_init();
|
||||||
|
runtime_poll_req(&runtime, &mut env);
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,10 @@
|
|||||||
#![feature(strict_provenance)]
|
#![feature(strict_provenance)]
|
||||||
|
|
||||||
|
use std::ffi::c_void;
|
||||||
|
|
||||||
|
use jni::JavaVM;
|
||||||
|
use mem::RuntimeAllocator;
|
||||||
|
|
||||||
pub type Runtime =
|
pub type Runtime =
|
||||||
toad::std::Platform<toad::std::dtls::N, toad::step::runtime::std::Runtime<toad::std::dtls::N>>;
|
toad::std::Platform<toad::std::dtls::N, toad::step::runtime::std::Runtime<toad::std::dtls::N>>;
|
||||||
|
|
||||||
@ -21,8 +26,22 @@ pub mod runtime;
|
|||||||
pub mod runtime_config;
|
pub mod runtime_config;
|
||||||
pub mod uint;
|
pub mod uint;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "system" fn JNI_OnLoad(jvm: JavaVM, _: *const c_void) -> i32 {
|
||||||
|
toad_jni::global::init_with(jvm);
|
||||||
|
jni::sys::JNI_VERSION_1_8
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "system" fn JNI_OnUnload(_: JavaVM, _: *const c_void) {
|
||||||
|
unsafe {mem::Runtime::dealloc()}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(test, feature = "e2e"))]
|
||||||
|
pub mod e2e;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
pub mod test {
|
||||||
use std::sync::Once;
|
use std::sync::Once;
|
||||||
|
|
||||||
use jni::{InitArgsBuilder, JavaVM};
|
use jni::{InitArgsBuilder, JavaVM};
|
||||||
@ -33,20 +52,20 @@ mod tests {
|
|||||||
use crate::retry_strategy::RetryStrategy;
|
use crate::retry_strategy::RetryStrategy;
|
||||||
use crate::runtime_config::RuntimeConfig;
|
use crate::runtime_config::RuntimeConfig;
|
||||||
|
|
||||||
static INIT: Once = Once::new();
|
|
||||||
pub fn init<'a>() -> java::Env<'a> {
|
pub fn init<'a>() -> java::Env<'a> {
|
||||||
|
static INIT: Once = Once::new();
|
||||||
INIT.call_once(|| {
|
INIT.call_once(|| {
|
||||||
let jvm =
|
let jvm =
|
||||||
JavaVM::new(InitArgsBuilder::new().option("--enable-preview")
|
JavaVM::new(InitArgsBuilder::new().option("-Djava.library.path=/home/orion/src/toad-lib/toad-java/target/glue/debug/")
|
||||||
.option("-Djava.class.path=../target/scala-3.2.2/classes/")
|
.option("-Djava.class.path=../target/scala-3.2.2/classes")
|
||||||
|
.option("--enable-preview")
|
||||||
.build()
|
.build()
|
||||||
.unwrap()).unwrap();
|
.unwrap()).unwrap();
|
||||||
toad_jni::global::init_with(jvm);
|
toad_jni::global::init_with(jvm);
|
||||||
});
|
});
|
||||||
|
|
||||||
toad_jni::global::jvm().attach_current_thread_permanently()
|
toad_jni::global::jvm().attach_current_thread_permanently()
|
||||||
.unwrap();
|
.unwrap()
|
||||||
toad_jni::global::jvm().get_env().unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -9,7 +9,10 @@ pub type Runtime = RuntimeGlobalStaticAllocator;
|
|||||||
/// strict provenance to prevent addresses from leaking outside of that memory region.
|
/// strict provenance to prevent addresses from leaking outside of that memory region.
|
||||||
pub trait RuntimeAllocator: core::default::Default + core::fmt::Debug + Copy {
|
pub trait RuntimeAllocator: core::default::Default + core::fmt::Debug + Copy {
|
||||||
/// Allocate memory for the runtime and yield a stable pointer to it
|
/// Allocate memory for the runtime and yield a stable pointer to it
|
||||||
unsafe fn alloc(r: crate::Runtime) -> *mut crate::Runtime;
|
unsafe fn alloc(r: impl FnOnce() -> crate::Runtime) -> *mut crate::Runtime;
|
||||||
|
|
||||||
|
/// Teardown
|
||||||
|
unsafe fn dealloc() {}
|
||||||
|
|
||||||
/// Coerce a `long` rep of the stable pointer created by [`Self::alloc`] to
|
/// Coerce a `long` rep of the stable pointer created by [`Self::alloc`] to
|
||||||
/// a pointer (preferably using strict_provenance)
|
/// a pointer (preferably using strict_provenance)
|
||||||
@ -32,18 +35,19 @@ static mut RUNTIME: *mut crate::Runtime = core::ptr::null_mut();
|
|||||||
pub struct RuntimeGlobalStaticAllocator;
|
pub struct RuntimeGlobalStaticAllocator;
|
||||||
impl RuntimeAllocator for RuntimeGlobalStaticAllocator {
|
impl RuntimeAllocator for RuntimeGlobalStaticAllocator {
|
||||||
/// Nops on already-init
|
/// Nops on already-init
|
||||||
unsafe fn alloc(r: crate::Runtime) -> *mut crate::Runtime {
|
unsafe fn alloc(r: impl FnOnce() -> crate::Runtime) -> *mut crate::Runtime {
|
||||||
if RUNTIME.is_null() {
|
if RUNTIME.is_null() {
|
||||||
let p =
|
RUNTIME = Box::into_raw(Box::new(r()));
|
||||||
std::alloc::alloc(std::alloc::Layout::new::<crate::Runtime>()).cast::<crate::Runtime>();
|
|
||||||
*p = r;
|
|
||||||
RUNTIME = p;
|
|
||||||
RUNTIME
|
RUNTIME
|
||||||
} else {
|
} else {
|
||||||
RUNTIME
|
RUNTIME
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn dealloc() {
|
||||||
|
drop(Box::from_raw(RUNTIME));
|
||||||
|
}
|
||||||
|
|
||||||
unsafe fn deref(_: i64) -> *mut crate::Runtime {
|
unsafe fn deref(_: i64) -> *mut crate::Runtime {
|
||||||
RUNTIME
|
RUNTIME
|
||||||
}
|
}
|
||||||
|
@ -11,10 +11,14 @@ use crate::Runtime as ToadRuntime;
|
|||||||
pub struct Runtime(java::lang::Object);
|
pub struct Runtime(java::lang::Object);
|
||||||
|
|
||||||
impl Runtime {
|
impl Runtime {
|
||||||
pub fn init(e: &mut java::Env, cfg: RuntimeConfig) -> i64 {
|
pub fn get_or_init(e: &mut java::Env, cfg: RuntimeConfig) -> Self {
|
||||||
let r =
|
static GET_OR_INIT: java::StaticMethod<Runtime, fn(RuntimeConfig) -> Runtime> = java::StaticMethod::new("getOrInit");
|
||||||
ToadRuntime::try_new(format!("0.0.0.0:{}", cfg.net(e).port(e)), cfg.to_toad(e)).unwrap();
|
GET_OR_INIT.invoke(e, cfg)
|
||||||
unsafe { crate::mem::Runtime::alloc(r).addr() as i64 }
|
}
|
||||||
|
|
||||||
|
pub fn poll_req(&self, e: &mut java::Env) -> Option<MessageRef> {
|
||||||
|
static POLL_REQ: java::Method<Runtime, fn() -> java::util::Optional<MessageRef>> = java::Method::new("pollReq");
|
||||||
|
POLL_REQ.invoke(e, self).to_option(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addr(&self, e: &mut java::Env) -> i64 {
|
pub fn addr(&self, e: &mut java::Env) -> i64 {
|
||||||
@ -25,6 +29,27 @@ impl Runtime {
|
|||||||
pub fn ref_(&self, e: &mut java::Env) -> &'static ToadRuntime {
|
pub fn ref_(&self, e: &mut java::Env) -> &'static ToadRuntime {
|
||||||
unsafe { crate::mem::Runtime::deref(self.addr(e)).as_ref().unwrap() }
|
unsafe { crate::mem::Runtime::deref(self.addr(e)).as_ref().unwrap() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn init_impl(e: &mut java::Env, cfg: RuntimeConfig) -> i64 {
|
||||||
|
let r = ||
|
||||||
|
ToadRuntime::try_new(format!("0.0.0.0:{}", cfg.net(e).port(e)), cfg.to_toad(e)).unwrap();
|
||||||
|
unsafe { crate::mem::Runtime::alloc(r).addr() as i64 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll_req_impl(&self, e: &mut java::Env) -> java::util::Optional<MessageRef> {
|
||||||
|
match self.ref_(e).poll_req() {
|
||||||
|
| Ok(req) => {
|
||||||
|
let mr = MessageRef::new(e, req.data().msg());
|
||||||
|
java::util::Optional::<MessageRef>::of(e, mr)
|
||||||
|
},
|
||||||
|
| Err(nb::Error::WouldBlock) => {
|
||||||
|
java::util::Optional::<MessageRef>::empty(e)
|
||||||
|
},
|
||||||
|
| Err(nb::Error::Other(err)) => {
|
||||||
|
e.throw(format!("{:?}", err)).unwrap();
|
||||||
|
java::util::Optional::<MessageRef>::empty(e)
|
||||||
|
},
|
||||||
|
} }
|
||||||
}
|
}
|
||||||
|
|
||||||
java::object_newtype!(Runtime);
|
java::object_newtype!(Runtime);
|
||||||
@ -41,29 +66,18 @@ pub extern "system" fn Java_dev_toad_Runtime_init<'local>(mut e: java::Env<'loca
|
|||||||
let e = &mut e;
|
let e = &mut e;
|
||||||
let cfg = java::lang::Object::from_local(e, cfg).upcast_to::<RuntimeConfig>(e);
|
let cfg = java::lang::Object::from_local(e, cfg).upcast_to::<RuntimeConfig>(e);
|
||||||
|
|
||||||
Runtime::init(e, cfg)
|
Runtime::init_impl(e, cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// JNIEXPORT jobject JNICALL Java_dev_toad_Runtime_pollReq
|
|
||||||
// (JNIEnv *, jobject, jobject);
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "system" fn Java_dev_toad_Runtime_pollReq<'local>(mut e: java::Env<'local>,
|
pub extern "system" fn Java_dev_toad_Runtime_pollReq<'local>(mut e: java::Env<'local>,
|
||||||
runtime: JObject<'local>,
|
runtime: JObject<'local>)
|
||||||
cfg: JObject<'local>)
|
|
||||||
-> jobject {
|
-> jobject {
|
||||||
let e = &mut e;
|
let e = &mut e;
|
||||||
let runtime = java::lang::Object::from_local(e, runtime).upcast_to::<Runtime>(e);
|
java::lang::Object::from_local(e, runtime)
|
||||||
match runtime.ref_(e).poll_req() {
|
.upcast_to::<Runtime>(e)
|
||||||
| Ok(req) => {
|
.poll_req_impl(e)
|
||||||
let mr = MessageRef::new(e, req.data().msg());
|
.downcast(e)
|
||||||
java::util::Optional::<MessageRef>::of(e, mr).downcast(e)
|
.to_local(e)
|
||||||
.as_raw()
|
.as_raw()
|
||||||
},
|
|
||||||
| Err(nb::Error::WouldBlock) => java::util::Optional::<MessageRef>::empty(e).downcast(e)
|
|
||||||
.as_raw(),
|
|
||||||
| Err(nb::Error::Other(err)) => {
|
|
||||||
e.throw(format!("{:?}", err)).unwrap();
|
|
||||||
core::ptr::null_mut()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ use toad::time::Millis;
|
|||||||
use toad_jni::java;
|
use toad_jni::java;
|
||||||
|
|
||||||
use crate::retry_strategy::RetryStrategy;
|
use crate::retry_strategy::RetryStrategy;
|
||||||
|
use crate::uint;
|
||||||
|
|
||||||
pub struct RuntimeConfig(java::lang::Object);
|
pub struct RuntimeConfig(java::lang::Object);
|
||||||
|
|
||||||
@ -74,15 +75,21 @@ impl java::Class for Net {
|
|||||||
const PATH: &'static str = concat!(package!(dev.toad.RuntimeOptions), "$Net");
|
const PATH: &'static str = concat!(package!(dev.toad.RuntimeOptions), "$Net");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NET_PORT: java::Field<Net, uint::u16> = java::Field::new("port");
|
||||||
|
|
||||||
impl Net {
|
impl Net {
|
||||||
pub fn port(&self, e: &mut java::Env) -> i16 {
|
pub fn port(&self, e: &mut java::Env) -> u16 {
|
||||||
static PORT: java::Method<Net, fn() -> i16> = java::Method::new("port");
|
NET_PORT.get(e, self).to_rust(e)
|
||||||
PORT.invoke(e, self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn concurrency(&self, e: &mut java::Env) -> i16 {
|
pub fn set_port(&self, e: &mut java::Env, new: u16) {
|
||||||
static CONCURRENCY: java::Method<Net, fn() -> i16> = java::Method::new("concurrency");
|
let new = uint::u16::from_rust(e, new);
|
||||||
CONCURRENCY.invoke(e, self)
|
NET_PORT.set(e, self, new)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn concurrency(&self, e: &mut java::Env) -> u8 {
|
||||||
|
static CONCURRENCY: java::Field<Net, uint::u8> = java::Field::new("concurrency");
|
||||||
|
CONCURRENCY.get(e, self).to_rust(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn msg(&self, e: &mut java::Env) -> Msg {
|
pub fn msg(&self, e: &mut java::Env) -> Msg {
|
||||||
|
@ -5,10 +5,18 @@ import java.util.Optional;
|
|||||||
|
|
||||||
public class Runtime {
|
public class Runtime {
|
||||||
|
|
||||||
|
static {
|
||||||
|
System.loadLibrary("toad_java_glue");
|
||||||
|
}
|
||||||
|
|
||||||
private final long addr;
|
private final long addr;
|
||||||
|
|
||||||
private static native long init(RuntimeOptions o);
|
private static native long init(RuntimeOptions o);
|
||||||
private native Optional<MessageRef> pollReq(RuntimeOptions o);
|
private native Optional<MessageRef> pollReq();
|
||||||
|
|
||||||
|
public static Runtime getOrInit(RuntimeOptions o) {
|
||||||
|
return new Runtime(o);
|
||||||
|
}
|
||||||
|
|
||||||
public Runtime(RuntimeOptions o) {
|
public Runtime(RuntimeOptions o) {
|
||||||
this.addr = Runtime.init(o);
|
this.addr = Runtime.init(o);
|
||||||
|
Loading…
Reference in New Issue
Block a user