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}