elast0ny / shared_memory

A Rust wrapper around native shared memory for Linux and Windows
389 stars 51 forks source link

Provide a simple example #61

Closed chaoxi24 closed 3 years ago

chaoxi24 commented 3 years ago

Can you provide a simple example that does not involve other packages? For example, save the string-"asdfg" to the shared memory named "T1". Yes, this is also my requirement, but I have read the two examples for a long time and don't know how to achieve my goal.

elast0ny commented 3 years ago

Hello, I added a the most basic example i could come up with here : https://github.com/elast0ny/shared_memory-rs/blob/master/examples/basic.rs

It doesn't use any locking and simply increments a u8 that lives in shared memory.

Your issue with putting a string inside the shared memory is a bit more complicated to do properly & safely.

If you ignore all the safety concerns, you can do something like :

    // Get pointer to the shared memory
    let raw_ptr = shmem.as_ptr();

    unsafe {
        // The string is stored as [len:u32][data]
        let str_len = raw_ptr as *mut u32;
        // Create slice with the rest of the shmem
        let str_data = std::slice::from_raw_parts_mut(
            raw_ptr.add(std::mem::size_of::<u32>()),
            shmem.len() - std::mem::size_of::<u32>()
        );

        if shmem.is_owner() {
            let my_str = "asdfg";
            // Copy our string characters into the shmem
            str_data[..my_str.len()].copy_from_slice(my_str.as_bytes());
            // Set the len
            *str_len = my_str.len() as u32;
            info!("Initialized string '{}' in shmem !", &my_str);

            // Keep shmem alive for another 5 seconds
            std::thread::sleep(std::time::Duration::from_secs(5));
        } else {
            // Wait until len has been set
            while std::ptr::read_volatile(str_len) == 0 {}

            // Assume the length is valid and shmem contains valid utf8
            let shared_str = std::str::from_utf8_unchecked(&str_data[..std::ptr::read_volatile(str_len) as usize]);

            info!("Read string '{}' from shared memory !", shared_str);
        }
    }
chaoxi24 commented 3 years ago

Thank you. I used a simpler solution to write strings.

fn main() {
    let t = "asdfg".to_string();
    unsafe {
        cfm_set("T1", t.as_ptr(), t.len());
    }

    let (tx, rx) = std::sync::mpsc::channel();
    let t: u32 = rx.recv().unwrap();
}

unsafe fn cfm_set(name: &'static str, ptr: *const u8, size: usize) {
    extern "system" {
        fn OpenFileMappingW(hFile: u32, dwFlags: bool, lpLibFileName: *const u16) -> u32;
        fn MapViewOfFile(a: u32, b: u32, c: u32, d: u32, e: usize) -> u64;
        fn UnmapViewOfFile(e: u64) -> u32;
        fn RtlMoveMemory(a: u64, b: *const u8, c: usize);
        fn CreateFileMappingW(a: i64, b: u32, c: u32, d: u32, e: u32, Name: *const u16) -> u32;
    }
    let sz = size as u32;
    let nm: Vec<u16> = name.encode_utf16().chain(Some(0)).collect();
    let cf = CreateFileMappingW(-1, 0, 4, sz >> 16 >> 16, sz & 0xffffffff, nm.as_ptr());
    let mf = MapViewOfFile(cf, 2, 0, 0, 0);
    RtlMoveMemory(mf, ptr, size);
    UnmapViewOfFile(mf);
}