Mutex for extern `static mut`

I have a mutable stativ variable that comes from a C library.

#[link(name = "imaevm")]
extern "C" {
    static mut imaevm_params: libimaevm_params;
}

libimaevm fills this struct with values taken from options and arguments of the CLI application. This is safe since the CLI is single-threaded. But how do I ensure that calling something like this from multiple threads is safe?

fn do_stuff(some_field: *const i8) {
    unsafe {
        imaevm_params = libimaevm_params {
            some_field,
            ..imaevm_params
        };
    }
    use_imaevm_params();
}

I personally would do something like

fn mutate_foo(f: impl Fn(Foo) -> Foo) -> LockResult<...> {
    static LOCK: Mutex<()> = Mutex::new();

    let _g = LOCK.lock()?;
    unsafe {
        libmaevm_params = f(libmaevm_params);
    }
}
1 Like

This is what I ended up with:

fn mutate_imaevm_params(f: impl Fn(&mut libimaevm_params) -> libimaevm_params) {
    let _guard = IMAEVM_PARAMS_MUTEX.lock().unwrap();
    // SAFETY: Use of mutable static is unsafe, because mutable statics can be
    //     mutated by multiple threads. But we only access it after locking a
    //     Mutex, so it's fine.
    unsafe {
        imaevm_params = f(&mut imaevm_params);
    }
}

Usage example:

mutate_imaevm_params(|params| {
    libimaevm_params {
        hash_algo,
        // The rest of the fields are not set there, so defaults are used.
        ..*params
    }
});

Suggestions are much appreciated! I think using a proper struct with ImaevmParams::get and ImaevmParams::set would be even better.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.