Raw pointer and send / LazyLock

Hello,

Just as a "warning" I'm not really sure whether I misunderstand the way I should use glib or whether it is a pointer / rust problem. But if I post here I'm rather sure it comes from me and it related to a rust problem otherwise I sincerely apologize in advance for the caused disturbance to an unrelated problem to rust.

I also want to add the fact that when developing this piece of code I had errors indicating that raw pointers weren't Send.

So here is my code:

static MAIN_LOOP: LazyLock<Arc<Mutex<Arc<glib_sys::glib::GMainLoop>>>> = LazyLock::<
    Arc<Mutex<Arc<glib_sys::glib::GMainLoop>>>,
>::new(|| {
    let context_ptr = unsafe { glib_sys::glib::g_main_context_default() };

    let main_loop = unsafe {
        glib_sys::glib::g_main_loop_new(
            context_ptr,
            std::ffi::c_int::try_from(glib_sys::glib::FALSE).unwrap(),
        )
    };

    Arc::<Mutex<Arc<glib_sys::glib::GMainLoop>>>::new(Mutex::<Arc<glib_sys::glib::GMainLoop>>::new(
        unsafe { Arc::<glib_sys::glib::GMainLoop>::from_raw(main_loop) },
    ))
});

/// run the main loop of the default context
///
/// # Panics
/// The main loop is then unable to run.
pub fn run_main_context_loop() {
    let main_loop = &mut MAIN_LOOP.lock().unwrap();
    let arc_main_loop = Arc::get_mut(main_loop).unwrap();
    if unsafe { glib_sys::glib::g_main_loop_is_running(arc_main_loop) }
        == i32::try_from(glib_sys::glib::FALSE).unwrap()
    {
        unsafe { glib_sys::glib::g_main_loop_run(arc_main_loop) }
    }
}

the function run_main_context_loop is run in a thread:

std::thread::spawn(move || {
     run_main_context_loop();
});

Unfortunately the glib thread crashes. I analyzed the stack and seems to come from this line:

pub fn run_main_context_loop() {
    ...
    // here it crashes
    let arc_main_loop = Arc::get_mut(main_loop).unwrap();
    ...
}

Thank you very much in advance for any help

I haven’t personally used glib, but my understanding is that it is the kind of library where you must access all of its objects from the same thread (except as documented otherwise). So, the fact that any Send errors you get are rooted in a raw pointer’s presence is an implementation detail of the Rust bindings, but it does reflect an actual reality you need to obey.

  • You should stop trying to store the GMainLoop in a static variable. If you must, you can put it in a thread_local! variable, but you should try to keep it in an ordinary let variable in the function that’s going to run it, instead.

  • It is not correct to convert a pointer to GMainLoop into an Arc<GMainLoop> with Arc::from_raw, because the pointer does not point to an Arc allocation. You should not be using Arc but, the higher-level wrapper types like glib::MainLoop, which are internally reference-counted using glib's own reference counters.

    (In general, *-sys libraries are low-level FFI libraries which are designed to be the canonical, unopinionated, way to link to the corresponding foreign library, and they do not necessarily offer convenient Rust usage. So you should generally avoid using *-sys libraries and use the higher level wrappers around them (that is, glib instead of glib-sys), unless you have a specific reason to do otherwise.

1 Like

Hello,

Thank you for your quick reply.

Do mean in a variable scoped to the function ?

Thank you for this. Now I understand why Box / Arc won't work. It now seems so obvious.

Thank you for your help

Yes.