Are there any general rules, design documentation or something similar that explains how the Rust standard library deals with threads that were not spawned by std::thread?
I have a cdylib crate and want to use it from another language in a threaded manner:
use std::mem;
use std::sync::{Arc, Mutex};
use std::thread;
type jlong = usize;
type SharedData = Arc<Mutex<u32>>;
struct Foo {
data: SharedData,
}
#[no_mangle]
pub fn Java_com_example_Foo_init(shared_data: &SharedData) -> jlong {
let this = Box::into_raw(Box::new(Foo { data: shared_data.clone() }));
this as jlong
}
#[cfg(target_pointer_width = "32")]
unsafe fn jlong_to_pointer<T>(val: jlong) -> *mut T {
mem::transmute::<u32, *mut T>(val as u32)
}
#[cfg(target_pointer_width = "64")]
unsafe fn jlong_to_pointer<T>(val: jlong) -> *mut T {
mem::transmute::<jlong, *mut T>(val)
}
#[no_mangle]
pub fn Java_com_example_Foo_f(this: jlong) {
let mut this = unsafe { jlong_to_pointer::<Foo>(this).as_mut().unwrap() };
let data = this.data.clone();
let mut data = data.lock().unwrap();
*data = *data + 5;
}
specifically in
let shared_data = Arc::new(Mutex::new(5));
let foo = Java_com_example_Foo_init(&shared_data);
is it safe to modify shared_data from a thread spawned by thread::spawn if Java_com_example_Foo_f will be called from an unknown JVM thread?
Possible reason why it can be bad.
Yes. The issue you linked relates to librustrt, which was removed before Rust 1.0. RFC 230, which removed librustrt, specifically notes:
When embedding Rust code into other contexts -- whether calling from C code or embedding in high-level languages -- there is a fair amount of setup needed to provide the "runtime" infrastructure that
libstdrelies on. Iflibstdwas instead bound to the native threading and I/O system, the embedding setup would be much simpler.
Additionally, see PR #19654 which implemented that RFC:
When using Rust in an embedded context, it should now be possible to call a Rust function directly as a C function with absolutely no setup, though in that case panics will cause the process to abort. In this regard, the C/Rust interface will look much like the C/C++ interface.
For current documentation, the Rustonomicon chapter on FFI's examples of Rust code to be called from C make use of libstd (including Mutex, I believe, though that's an implementation detail of println!) without any caveats relating to runtime setup.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With