ubolonton / emacs-module-rs

Rust binding and tools for Emacs's dynamic modules
336 stars 22 forks source link

Concurrency #50

Open fosskers opened 2 years ago

fosskers commented 2 years ago

I am playing around with exposing some of Rust's rayon crate to Emacs. I've started with attempting to implement join:

#[emacs::defun]
fn join<'a>(env: &Env, fa: Value<'a>, fb: Value<'a>) -> emacs::Result<()> {
    env.message("racing: Entered join.")?;

    let la = Lambda::new(fa);
    let lb = Lambda::new(fb);
    let a = || la.call();
    let b = || lb.call();

    env.message("racing: Invoking rayon...")?;

    let (ra, rb) = rayon::join(a, b);

    env.message(format!("ra: {}", ra.is_ok()))?;
    env.message(format!("rb: {}", rb.is_ok()))?;

    Ok(())
}

Ignoring the return type for the moment. After building and loading, I invoke it like this:

(racing-join (lambda () (message "Call from first lambda within Elisp!"))
             (lambda () (message "Call from second lambda within Elisp!")))

Here, Lambda is a wrapper type I've introduced to allow these evil trait instances:

unsafe impl<'a> Send for Lambda<'a> {}
unsafe impl<'a> Sync for Lambda<'a> {}

Otherwise the compiler complains of raw pointers (within Env) being unSendable.

My join function "works" only if I replace b with something that doesn't call lb, the second lambda. Otherwise Emacs complete freezes as soon as I invoke the Lisp shown above. Poking around in the source code of your library, I suspect it has something to do with Env. Having these unsafe trait instances as I do might just be impossible.

Do you have any ideas as to why Emacs would entirely freeze (as opposed to just erroring) when I invoke racing-join? Is Env entirely thread-unsafe?

Thank you kindly.