mozilla / cbindgen

A project for generating C bindings from Rust code
Mozilla Public License 2.0
2.37k stars 305 forks source link

How do I mark a struct variable volatile? #960

Open flaviojs opened 4 months ago

flaviojs commented 4 months ago

I am converting code from C to rust. There is too much code so the transition must be done in steps. Some struct variables have the volatile modifier, so I have to find a way to generate struct variables with volatile to ensure the C code behaves the same during the transition and everything can be tested.

On the rust side volatile behavior is achieved by using read_volatile/write_volatile manually or with a wrapper. On the C side the variables must have the volatile modifier or I must cast every singe use of the variable to a volatile type (untested).

I am looking for a solution that avoids having to modify the original C code. The ideal solution would be cbindgen generating the volatile modifier in specific struct variables, which allows me to change the structure at a later stage while ensuring the remaining C code behaves the same.

So, how do I mark a struct variable volatile?

flaviojs commented 4 months ago

Temporary workaround for C:

lib.rs

/// cbindgen:no-export
#[repr(transparent)]
#[derive(Debug, Copy, Clone)]
pub struct Volatile<T>(pub T);
impl<T> Volatile<T> {
    pub fn get(&self) -> T {
        unsafe { std::ptr::read_volatile(std::ptr::addr_of!(self.0)) }
    }
    pub fn set(&mut self, x: T) {
        unsafe { std::ptr::write_volatile(std::ptr::addr_of_mut!(self.0), x) }
    }
}

#[repr(C)]
pub struct S {
    pub vi: Volatile<std::ffi::c_int>,
    pub vpi: Volatile<*mut std::ffi::c_int>,
}

#[no_mangle]
pub extern "C" fn _export(_: S) {}

cbindgen.toml

after_includes = """
// volatile types (cbindgen does not emit the C volatile type qualifier)
typedef volatile int Volatile_c_int;
typedef int *volatile Volatile_____c_int;
"""