Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it safe to modify an Arc<Mutex<T>> from both a Rust thread and a foreign thread?

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.

like image 680
fghj Avatar asked Dec 09 '25 02:12

fghj


1 Answers

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 libstd relies on. If libstd was 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.

like image 169
leo60228 Avatar answered Dec 12 '25 01:12

leo60228



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!