| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 use std::mem; | |
| 6 use std::slice; | |
| 7 use std::ptr; | |
| 8 | |
| 9 use system::ffi; | |
| 10 // This full import is intentional; nearly every type in mojo_types needs to be
used. | |
| 11 use system::mojo_types::*; | |
| 12 use system::handle; | |
| 13 use system::handle::{CastHandle, Handle}; | |
| 14 | |
| 15 #[repr(u32)] | |
| 16 /// Create flags for shared buffers | |
| 17 pub enum Create { | |
| 18 None = 0, | |
| 19 } | |
| 20 | |
| 21 #[repr(u32)] | |
| 22 /// Duplicate flags for shared buffers | |
| 23 pub enum Duplicate { | |
| 24 None = 0, | |
| 25 } | |
| 26 | |
| 27 #[repr(u32)] | |
| 28 /// Map flags for shared buffers | |
| 29 pub enum Map { | |
| 30 None = 0, | |
| 31 } | |
| 32 | |
| 33 #[repr(u32)] | |
| 34 /// Map flags for shared buffers | |
| 35 pub enum Info { | |
| 36 None = 0, | |
| 37 } | |
| 38 | |
| 39 /// A MappedBuffer represents the result of | |
| 40 /// calling map_buffer on a shared buffer handle. | |
| 41 /// | |
| 42 /// The C API allocates a buffer which can then be | |
| 43 /// read or written to through this data structure. | |
| 44 /// | |
| 45 /// The importance of this data structure is that | |
| 46 /// we bind the lifetime of the slice given to us | |
| 47 /// from the C API to this structure. Additionally, | |
| 48 /// reads and writes to this data structure are guaranteed | |
| 49 /// to be able to propagate through Mojo as they are | |
| 50 /// volatile. Language optimization backends are generally | |
| 51 /// unaware of other address spaces, and since this structure | |
| 52 /// represents some buffer from another address space, we | |
| 53 /// need to make sure loads and stores are volatile. | |
| 54 /// | |
| 55 /// Changes to this data structure are propagated through Mojo | |
| 56 /// on the next Mojo operation (that is, Mojo operations are | |
| 57 /// considered barriers). So, unmapping the buffer, sending a | |
| 58 /// message across a pipe, duplicating a shared buffer handle, | |
| 59 /// etc. are all valid ways of propagating changes. The read | |
| 60 /// and write methods do NOT guarantee changes to propagate. | |
| 61 /// | |
| 62 /// This structure also prevents resource leaks by | |
| 63 /// unmapping the buffer it contains on destruction. | |
| 64 pub struct MappedBuffer<'a> { | |
| 65 buffer: &'a mut [u8], | |
| 66 } | |
| 67 | |
| 68 impl<'a> MappedBuffer<'a> { | |
| 69 /// Returns the length of the wrapped buffer. | |
| 70 /// | |
| 71 /// Part of reimplementing the array interface to be | |
| 72 /// able to use the structure naturally. | |
| 73 pub fn len(&self) -> usize { | |
| 74 self.buffer.len() | |
| 75 } | |
| 76 | |
| 77 /// Read safely from the shared buffer. Makes sure a real load | |
| 78 /// is performed by marking the read as volatile. | |
| 79 pub fn read(&self, index: usize) -> u8 { | |
| 80 unsafe { ptr::read_volatile((&self.buffer[index]) as *const u8) } | |
| 81 } | |
| 82 | |
| 83 /// Write safely to the shared buffer. Makes sure a real store | |
| 84 /// is performed by marking the store as volatile. | |
| 85 pub fn write(&mut self, index: usize, value: u8) { | |
| 86 unsafe { | |
| 87 ptr::write_volatile((&mut self.buffer[index]) as *mut u8, value); | |
| 88 } | |
| 89 } | |
| 90 | |
| 91 /// Returns the slice this buffer wraps. | |
| 92 /// | |
| 93 /// The reason this method is unsafe is because the way Rust maps | |
| 94 /// reads and writes down to loads and stores may not be to real | |
| 95 /// loads and stores which are required to allow changes to propagate | |
| 96 /// through Mojo. If you are not careful, some writes and reads may be | |
| 97 /// to incorrect data! Use at your own risk. | |
| 98 pub unsafe fn as_slice(&'a mut self) -> &'a mut [u8] { | |
| 99 self.buffer | |
| 100 } | |
| 101 } | |
| 102 | |
| 103 impl<'a> Drop for MappedBuffer<'a> { | |
| 104 /// The destructor for MappedBuffer. Unmaps the buffer it | |
| 105 /// encloses by using the original, raw pointer to the mapped | |
| 106 /// memory region. | |
| 107 fn drop(&mut self) { | |
| 108 let r = MojoResult::from_code(unsafe { | |
| 109 ffi::MojoUnmapBuffer(self.buffer.as_ptr() as *const ffi::c_void) | |
| 110 }); | |
| 111 if r != MojoResult::Okay { | |
| 112 panic!("Failed to unmap buffer. Mojo Error: {}", r); | |
| 113 } | |
| 114 } | |
| 115 } | |
| 116 | |
| 117 /// Creates a shared buffer in Mojo and returns a SharedBuffer | |
| 118 /// structure which represents a handle to the shared buffer. | |
| 119 pub fn create(flags: CreateFlags, num_bytes: u64) -> Result<SharedBuffer, MojoRe
sult> { | |
| 120 let opts = ffi::MojoCreateSharedBufferOptions { | |
| 121 struct_size: mem::size_of::<ffi::MojoCreateSharedBufferOptions>() as u32
, | |
| 122 flags: flags, | |
| 123 _align: [], | |
| 124 }; | |
| 125 let raw_opts = &opts as *const ffi::MojoCreateSharedBufferOptions; | |
| 126 let mut h: MojoHandle = 0; | |
| 127 let r = MojoResult::from_code(unsafe { | |
| 128 ffi::MojoCreateSharedBuffer(raw_opts, num_bytes, &mut h as *mut MojoHand
le) | |
| 129 }); | |
| 130 if r != MojoResult::Okay { | |
| 131 Err(r) | |
| 132 } else { | |
| 133 Ok(SharedBuffer { handle: unsafe { handle::acquire(h) } }) | |
| 134 } | |
| 135 } | |
| 136 | |
| 137 /// Represents a handle to a shared buffer in Mojo. | |
| 138 /// This data structure wraps a handle and acts | |
| 139 /// effectively as a typed handle. | |
| 140 pub struct SharedBuffer { | |
| 141 handle: handle::UntypedHandle, | |
| 142 } | |
| 143 | |
| 144 impl SharedBuffer { | |
| 145 /// Duplicates the shared buffer handle. This is NOT the same | |
| 146 /// as cloning the structure which is illegal since cloning could | |
| 147 /// lead to resource leaks. Instead this uses Mojo to duplicate the | |
| 148 /// buffer handle (though the handle itself may not be represented by | |
| 149 /// the same number) that maps to the same shared buffer as the original. | |
| 150 pub fn duplicate(&self, flags: DuplicateFlags) -> Result<SharedBuffer, MojoR
esult> { | |
| 151 let opts = ffi::MojoDuplicateBufferHandleOptions { | |
| 152 struct_size: mem::size_of::<ffi::MojoDuplicateBufferHandleOptions>()
as u32, | |
| 153 flags: flags, | |
| 154 _align: [], | |
| 155 }; | |
| 156 let raw_opts = &opts as *const ffi::MojoDuplicateBufferHandleOptions; | |
| 157 let mut dup_h: MojoHandle = 0; | |
| 158 let r = MojoResult::from_code(unsafe { | |
| 159 ffi::MojoDuplicateBufferHandle(self.handle.get_native_handle(), | |
| 160 raw_opts, | |
| 161 &mut dup_h as *mut MojoHandle) | |
| 162 }); | |
| 163 if r != MojoResult::Okay { | |
| 164 Err(r) | |
| 165 } else { | |
| 166 Ok(SharedBuffer { handle: unsafe { handle::acquire(dup_h) } }) | |
| 167 } | |
| 168 } | |
| 169 | |
| 170 /// Map the shared buffer into local memory. Generates a MappedBuffer | |
| 171 /// structure. See MappedBuffer for more information on how to use it. | |
| 172 pub fn map<'a>(&self, | |
| 173 offset: u64, | |
| 174 num_bytes: u64, | |
| 175 flags: MapFlags) | |
| 176 -> Result<MappedBuffer<'a>, MojoResult> { | |
| 177 unsafe { | |
| 178 let mut ptr: *mut ffi::c_void = mem::uninitialized(); | |
| 179 let r = MojoResult::from_code(ffi::MojoMapBuffer(self.handle.get_nat
ive_handle(), | |
| 180 offset, | |
| 181 num_bytes, | |
| 182 &mut ptr, | |
| 183 flags)); | |
| 184 if r != MojoResult::Okay { | |
| 185 Err(r) | |
| 186 } else { | |
| 187 let mut buf = slice::from_raw_parts_mut(ptr as *mut u8, num_byte
s as usize); | |
| 188 Ok(MappedBuffer { buffer: buf }) | |
| 189 } | |
| 190 } | |
| 191 } | |
| 192 | |
| 193 /// Retrieves information about a shared buffer the this handle. The return | |
| 194 /// value is a set of flags (a bit vector in a u32) representing different | |
| 195 /// aspects of the shared buffer and the size of the shared buffer. | |
| 196 pub fn get_info(&self) -> Result<(InfoFlags, u64), MojoResult> { | |
| 197 let info_size = mem::size_of::<ffi::MojoBufferInformation>() as u32; | |
| 198 let mut info = ffi::MojoBufferInformation { | |
| 199 struct_size: info_size, | |
| 200 flags: 0, | |
| 201 num_bytes: 0, | |
| 202 _align: [], | |
| 203 }; | |
| 204 let r = MojoResult::from_code(unsafe { | |
| 205 ffi::MojoGetBufferInformation(self.handle.get_native_handle(), | |
| 206 &mut info as *mut ffi::MojoBufferInfor
mation, | |
| 207 info_size) | |
| 208 }); | |
| 209 if r != MojoResult::Okay { | |
| 210 Err(r) | |
| 211 } else { | |
| 212 Ok((info.flags, info.num_bytes)) | |
| 213 } | |
| 214 } | |
| 215 } | |
| 216 | |
| 217 impl CastHandle for SharedBuffer { | |
| 218 /// Generates a SharedBuffer from an untyped handle wrapper | |
| 219 /// See mojo::system::handle for information on untyped vs. typed | |
| 220 unsafe fn from_untyped(handle: handle::UntypedHandle) -> Self { | |
| 221 SharedBuffer { handle: handle } | |
| 222 } | |
| 223 | |
| 224 /// Consumes this object and produces a plain handle wrapper | |
| 225 /// See mojo::system::handle for information on untyped vs. typed | |
| 226 fn as_untyped(self) -> handle::UntypedHandle { | |
| 227 self.handle | |
| 228 } | |
| 229 } | |
| 230 | |
| 231 impl Handle for SharedBuffer { | |
| 232 /// Returns the native handle wrapped by this structure. | |
| 233 /// | |
| 234 /// See mojo::system::handle for information on handle wrappers | |
| 235 fn get_native_handle(&self) -> MojoHandle { | |
| 236 self.handle.get_native_handle() | |
| 237 } | |
| 238 } | |
| OLD | NEW |