share_memory/sys/unix/
mod.rs

1use libc;
2
3use std::io::{self, Result, Error, ErrorKind};
4pub type MemoryId = libc::c_int;
5pub const INVALID_MEMORY_ID: MemoryId = -1;
6
7#[doc(hidden)]
8pub trait IsMinusOne {
9    fn is_minus_one(&self) -> bool;
10}
11
12macro_rules! impl_is_minus_one {
13    ($($t:ident)*) => ($(impl IsMinusOne for $t {
14        fn is_minus_one(&self) -> bool {
15            *self == -1
16        }
17    })*)
18}
19
20impl_is_minus_one! { i8 i16 i32 i64 isize }
21
22pub fn cvt<T: IsMinusOne>(t: T) -> io::Result<T> {
23    if t.is_minus_one() {
24        Err(io::Error::last_os_error())
25    } else {
26        Ok(t)
27    }
28}
29
30#[derive(Debug)]
31pub struct Memory {
32    id: MemoryId,
33    first: Option<*mut libc::c_void>,
34    size: usize,
35}
36
37impl Memory {
38    fn hash_code(name: &String) -> i32 {
39        let bytes = name.as_bytes();
40        let mut h = 0 as i32;
41        for byte in bytes {
42            h = h.wrapping_mul(31).wrapping_add(*byte as i32);
43        }
44        return h;
45    }
46
47    pub fn new(name: String, size: usize, path_name: Option<String>) -> Result<Memory> {
48        let path = path_name.unwrap_or(String::from("/tmp"));
49        let code = Self::hash_code(&name);
50        unsafe {
51            let key = cvt(libc::ftok(path.as_bytes().as_ptr() as *mut i8, code))?;
52            match cvt(libc::shmget(key, size, 0o0666)) {
53                Ok(id) => {
54                    return Ok(Memory {
55                        id: id,
56                        first: None,
57                        size: size,
58                    })
59                }
60                Err(_) => {
61                    let id = cvt(libc::shmget(key, size, 0o0666 | libc::IPC_CREAT | libc::IPC_EXCL))?;
62                    return Ok(Memory {
63                        id: id,
64                        first: None,
65                        size: size,
66                    })
67                }
68            }
69        }
70    }
71
72    pub fn first_memory(&mut self) -> Result<Option<*mut libc::c_void>> {
73        self.check_vaild()?;
74        if self.first.is_some() {
75            return Ok(self.first);
76        }
77        unsafe {
78            match libc::shmat(self.id, ::std::ptr::null_mut(), 0) {
79                addr if addr.is_null() => Ok(None),
80                addr => {
81                    self.first = Some(addr);
82                    Ok(self.first)
83                }
84            }
85        }
86    }
87
88    pub fn offset_memory(&mut self, offset: usize) -> Result<Option<*mut libc::c_void>> {
89        if offset >= self.size {
90            return Err(Error::new(ErrorKind::InvalidData, "offset bigger than size"));
91        }
92        if let Some(first) = self.first_memory()? {
93            unsafe {
94                return Ok(Some(first.offset(offset as isize)));
95            }
96        }
97        return Ok(None)
98    }
99
100    pub fn deattch(&mut self) -> Result<()> {
101        self.check_vaild()?;
102        if self.first.is_none() {
103            return Ok(());
104        }
105        unsafe {
106            if self.first.is_some() {
107                cvt(libc::shmdt(self.first.unwrap()))?;
108                self.first = None;
109            }
110        }
111        return Ok(());
112    }
113
114    pub fn destory(&mut self) -> Result<()> {
115        self.check_vaild()?;
116        self.deattch()?;
117        unsafe {
118            cvt(libc::shmctl(self.id, libc::IPC_RMID, ::std::ptr::null_mut()))?;
119        }
120        self.id = INVALID_MEMORY_ID;
121        Ok(())
122    }
123
124    pub fn is_vaild(&self) -> bool {
125        return self.id != INVALID_MEMORY_ID
126    }
127
128    pub fn check_vaild(&self) -> Result<bool> {
129        if !self.is_vaild() {
130            return Err(Error::new(ErrorKind::InvalidData, "no vaild"));
131        }
132        return Ok(true);
133    }
134}
135
136impl Drop for Memory {
137    fn drop(&mut self) {
138        let _ = self.deattch();
139    }
140}