| 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::marker; | |
| 6 use std::mem; | |
| 7 use std::ops; | |
| 8 use std::ptr; | |
| 9 use std::slice; | |
| 10 use std::vec; | |
| 11 | |
| 12 use system::ffi; | |
| 13 // This full import is intentional; nearly every type in mojo_types needs to be
used. | |
| 14 use system::mojo_types::*; | |
| 15 use system::handle; | |
| 16 use system::handle::{CastHandle, Handle}; | |
| 17 | |
| 18 #[repr(u32)] | |
| 19 /// Create flags for data pipes | |
| 20 pub enum Create { | |
| 21 None = 0, | |
| 22 } | |
| 23 | |
| 24 #[repr(u32)] | |
| 25 /// Write flags for data pipes | |
| 26 pub enum Write { | |
| 27 None = 0, | |
| 28 | |
| 29 /// Write all the data to the pipe if possible or none at all | |
| 30 AllOrNone = 1 << 0, | |
| 31 } | |
| 32 | |
| 33 #[repr(u32)] | |
| 34 /// Read flags for data pipes | |
| 35 pub enum Read { | |
| 36 None = 0, | |
| 37 | |
| 38 /// Read all the data from the pipe if possible, or none at all | |
| 39 AllOrNone = 1 << 0, | |
| 40 | |
| 41 /// Dequeue the message recieved rather than reading it | |
| 42 Discard = 1 << 1, | |
| 43 | |
| 44 /// Get information about the queue on the pipe but do not perform the | |
| 45 /// read | |
| 46 Query = 1 << 2, | |
| 47 | |
| 48 /// Read data off the pipe's queue but do not dequeue it | |
| 49 Peek = 1 << 3, | |
| 50 } | |
| 51 | |
| 52 /// Intermediary structure in a two-phase read. | |
| 53 /// Reads of the requested buffer must be done directly | |
| 54 /// through this data structure which must then be committed. | |
| 55 pub struct ReadDataBuffer<'b, 'p, T> | |
| 56 where 'p: 'b, | |
| 57 T: 'p | |
| 58 { | |
| 59 buffer: &'b [T], | |
| 60 | |
| 61 /// Contains a reference to parent to end commit | |
| 62 /// and prevent it from outliving its parent handle. | |
| 63 parent: &'p Consumer<T>, | |
| 64 } | |
| 65 | |
| 66 impl<'b, 'p, T> ReadDataBuffer<'b, 'p, T> | |
| 67 where 'p: 'b, | |
| 68 T: 'p | |
| 69 { | |
| 70 /// Attempts to commit the read, that is, end the two-phase read | |
| 71 /// started by the parent Consumer<T> object. On a successful | |
| 72 /// commit, consumes self, otherwise returns self to try again. | |
| 73 pub fn commit(self, bytes_read: usize) -> Option<(Self, MojoResult)> { | |
| 74 let result = unsafe { self.parent.end_read(bytes_read) }; | |
| 75 if result == MojoResult::Okay { | |
| 76 None | |
| 77 } else { | |
| 78 Some((self, result)) | |
| 79 } | |
| 80 } | |
| 81 | |
| 82 /// Returns the length of the underlying buffer | |
| 83 pub fn len(&self) -> usize { | |
| 84 self.buffer.len() | |
| 85 } | |
| 86 } | |
| 87 | |
| 88 impl<'b, 'p, T> ops::Index<usize> for ReadDataBuffer<'b, 'p, T> | |
| 89 where 'p: 'b, | |
| 90 T: 'p | |
| 91 { | |
| 92 type Output = T; | |
| 93 | |
| 94 /// Overloads the indexing ([]) operator for reads. | |
| 95 /// | |
| 96 /// Part of reimplementing the array interface to be | |
| 97 /// able to use the structure naturally. | |
| 98 fn index(&self, index: usize) -> &T { | |
| 99 &self.buffer[index] | |
| 100 } | |
| 101 } | |
| 102 | |
| 103 /// Intermediary structure in a two-phase write. | |
| 104 /// Writes to the requested buffer must be done directly | |
| 105 /// through this data structure which must then be committed. | |
| 106 pub struct WriteDataBuffer<'b, 'p, T> | |
| 107 where 'p: 'b, | |
| 108 T: 'p | |
| 109 { | |
| 110 buffer: &'b mut [T], | |
| 111 | |
| 112 /// Contains a reference to parent to end commit | |
| 113 /// and prevent it from outliving its parent handle. | |
| 114 parent: &'p Producer<T>, | |
| 115 } | |
| 116 | |
| 117 impl<'b, 'p, T> WriteDataBuffer<'b, 'p, T> | |
| 118 where 'p: 'b, | |
| 119 T: 'p | |
| 120 { | |
| 121 /// Attempts to commit the write, that is, end the two-phase | |
| 122 /// write started by a Producer. On a successful | |
| 123 /// commit, consumes self, otherwise returns self to try again. | |
| 124 pub fn commit(self, bytes_written: usize) -> Option<(Self, MojoResult)> { | |
| 125 let result = unsafe { self.parent.end_write(bytes_written) }; | |
| 126 if result == MojoResult::Okay { | |
| 127 None | |
| 128 } else { | |
| 129 Some((self, result)) | |
| 130 } | |
| 131 } | |
| 132 | |
| 133 /// Returns the length of the underlying buffer | |
| 134 pub fn len(&self) -> usize { | |
| 135 self.buffer.len() | |
| 136 } | |
| 137 } | |
| 138 | |
| 139 impl<'b, 'p, T> ops::Index<usize> for WriteDataBuffer<'b, 'p, T> | |
| 140 where 'p: 'b, | |
| 141 T: 'p | |
| 142 { | |
| 143 type Output = T; | |
| 144 | |
| 145 /// Overloads the indexing ([]) operator for reads. | |
| 146 /// | |
| 147 /// Part of reimplementing the array interface to be | |
| 148 /// able to use the structure naturally. | |
| 149 fn index(&self, index: usize) -> &T { | |
| 150 &self.buffer[index] | |
| 151 } | |
| 152 } | |
| 153 | |
| 154 impl<'b, 'p, T> ops::IndexMut<usize> for WriteDataBuffer<'b, 'p, T> | |
| 155 where 'p: 'b, | |
| 156 T: 'p | |
| 157 { | |
| 158 /// Overloads the indexing ([]) operator for writes. | |
| 159 /// | |
| 160 /// Part of reimplementing the array interface to be | |
| 161 /// able to use the structure naturally. | |
| 162 fn index_mut(&mut self, index: usize) -> &mut T { | |
| 163 &mut self.buffer[index] | |
| 164 } | |
| 165 } | |
| 166 | |
| 167 /// Creates a data pipe, represented as a consumer | |
| 168 /// and a producer. Additionally, we associate a type | |
| 169 /// T with the data pipe, as data pipes operate in terms | |
| 170 /// of elements. In this way we can enforce type safety. | |
| 171 /// | |
| 172 /// Capacity, as an input, must be given in number of elements. | |
| 173 /// Use a capacity of 0 in order to use some system-dependent | |
| 174 /// default capacity. | |
| 175 pub fn create<T>(flags: CreateFlags, | |
| 176 capacity: u32) | |
| 177 -> Result<(Consumer<T>, Producer<T>), MojoResult> { | |
| 178 let elem_size = mem::size_of::<T>() as u32; | |
| 179 let opts = ffi::MojoCreateDataPipeOptions { | |
| 180 struct_size: mem::size_of::<ffi::MojoCreateDataPipeOptions>() as u32, | |
| 181 flags: flags, | |
| 182 element_num_bytes: elem_size, | |
| 183 capacity_num_bytes: capacity * elem_size, | |
| 184 _align: [], | |
| 185 }; | |
| 186 // TODO(mknyszek): Make sure handles are valid | |
| 187 let mut chandle: MojoHandle = 0; | |
| 188 let mut phandle: MojoHandle = 0; | |
| 189 let raw_opts = &opts as *const ffi::MojoCreateDataPipeOptions; | |
| 190 let r = MojoResult::from_code(unsafe { | |
| 191 ffi::MojoCreateDataPipe(raw_opts, | |
| 192 &mut phandle as *mut MojoHandle, | |
| 193 &mut chandle as *mut MojoHandle) | |
| 194 }); | |
| 195 if r != MojoResult::Okay { | |
| 196 Err(r) | |
| 197 } else { | |
| 198 Ok((Consumer::<T> { | |
| 199 handle: unsafe { handle::acquire(chandle) }, | |
| 200 _elem_type: marker::PhantomData, | |
| 201 }, | |
| 202 Producer::<T> { | |
| 203 handle: unsafe { handle::acquire(phandle) }, | |
| 204 _elem_type: marker::PhantomData, | |
| 205 })) | |
| 206 } | |
| 207 } | |
| 208 | |
| 209 /// Creates a data pipe, represented as a consumer | |
| 210 /// and a producer, using the default Mojo options. | |
| 211 pub fn create_default() -> Result<(Consumer<u8>, Producer<u8>), MojoResult> { | |
| 212 create::<u8>(Create::None as u32, 0) | |
| 213 } | |
| 214 | |
| 215 /// Represents the consumer half of a data pipe. | |
| 216 /// This data structure wraps a handle and acts | |
| 217 /// effectively as a typed handle. | |
| 218 /// | |
| 219 /// The purpose of the _elem_type field is to associate | |
| 220 /// a type with the consumer, as a data pipe works | |
| 221 /// in elements. | |
| 222 pub struct Consumer<T> { | |
| 223 handle: handle::UntypedHandle, | |
| 224 _elem_type: marker::PhantomData<T>, | |
| 225 } | |
| 226 | |
| 227 impl<T> Consumer<T> { | |
| 228 /// Perform a read operation on the consumer end of the data pipe. As | |
| 229 /// a result, we get an std::vec::Vec filled with whatever was written. | |
| 230 pub fn read(&self, flags: ReadFlags) -> Result<vec::Vec<T>, MojoResult> { | |
| 231 let mut num_bytes: u32 = 0; | |
| 232 let r_prelim = unsafe { | |
| 233 ffi::MojoReadData(self.handle.get_native_handle(), | |
| 234 ptr::null_mut() as *mut ffi::c_void, | |
| 235 &mut num_bytes as *mut u32, | |
| 236 1 << 2 as ReadFlags) | |
| 237 }; | |
| 238 if r_prelim != 0 || num_bytes == 0 { | |
| 239 return Err(MojoResult::from_code(r_prelim)); | |
| 240 } | |
| 241 let elem_size: u32 = mem::size_of::<T>() as u32; | |
| 242 // TODO(mknyszek): make sure elem_size divides into num_bytes | |
| 243 let mut buf: vec::Vec<T> = vec::Vec::with_capacity((num_bytes / elem_siz
e) as usize); | |
| 244 let r = MojoResult::from_code(unsafe { | |
| 245 ffi::MojoReadData(self.handle.get_native_handle(), | |
| 246 buf.as_mut_ptr() as *const ffi::c_void, | |
| 247 &mut num_bytes as *mut u32, | |
| 248 flags) | |
| 249 }); | |
| 250 unsafe { buf.set_len((num_bytes / elem_size) as usize) } | |
| 251 if r != MojoResult::Okay { | |
| 252 Err(r) | |
| 253 } else { | |
| 254 Ok(buf) | |
| 255 } | |
| 256 } | |
| 257 | |
| 258 /// Start two-phase read and return a ReadDataBuffer to perform | |
| 259 /// read and commit. | |
| 260 pub fn begin(&self, flags: ReadFlags) -> Result<ReadDataBuffer<T>, MojoResul
t> { | |
| 261 let wrapped_result = unsafe { self.begin_read(flags) }; | |
| 262 match wrapped_result { | |
| 263 Ok(arr) => { | |
| 264 Ok(ReadDataBuffer::<T> { | |
| 265 buffer: arr, | |
| 266 parent: self, | |
| 267 }) | |
| 268 } | |
| 269 Err(r) => Err(r), | |
| 270 } | |
| 271 } | |
| 272 | |
| 273 /// A private function that performs the first half of two-phase reading. | |
| 274 /// Kept private because it is unsafe to use (the array received may not | |
| 275 /// be valid if end_read is performed). | |
| 276 unsafe fn begin_read(&self, flags: ReadFlags) -> Result<&[T], MojoResult> { | |
| 277 let mut buf_num_bytes: u32 = 0; | |
| 278 let mut pbuf: *mut ffi::c_void = mem::uninitialized(); | |
| 279 let r = MojoResult::from_code(ffi::MojoBeginReadData(self.handle.get_nat
ive_handle(), | |
| 280 &mut pbuf, | |
| 281 &mut buf_num_bytes
as *mut u32, | |
| 282 flags)); | |
| 283 if r != MojoResult::Okay { | |
| 284 Err(r) | |
| 285 } else { | |
| 286 let buf_elems = (buf_num_bytes as usize) / mem::size_of::<T>(); | |
| 287 let buf = slice::from_raw_parts(pbuf as *mut T, buf_elems); | |
| 288 Ok(buf) | |
| 289 } | |
| 290 } | |
| 291 | |
| 292 /// A private function that performs the second half of two-phase reading. | |
| 293 /// Kept private because it is unsafe to use (the array received from start_
read | |
| 294 /// may not be valid if end_read is performed). | |
| 295 /// | |
| 296 /// Also assumes loads/stores aren't reordered such that a load/store may be | |
| 297 /// optimized to be run AFTER MojoEndReadData(). In general, this is true as
long | |
| 298 /// as raw pointers are used, but Rust's memory model is still undefined. If
you're | |
| 299 /// getting a bad/strange runtime error, it might be for this reason. | |
| 300 unsafe fn end_read(&self, elems_read: usize) -> MojoResult { | |
| 301 let elem_size = mem::size_of::<T>(); | |
| 302 MojoResult::from_code(ffi::MojoEndReadData(self.handle.get_native_handle
(), | |
| 303 (elems_read * elem_size) as u
32)) | |
| 304 } | |
| 305 } | |
| 306 | |
| 307 impl<T> CastHandle for Consumer<T> { | |
| 308 /// Generates a Consumer from an untyped handle wrapper | |
| 309 /// See mojo::system::handle for information on untyped vs. typed | |
| 310 unsafe fn from_untyped(handle: handle::UntypedHandle) -> Self { | |
| 311 Consumer::<T> { | |
| 312 handle: handle, | |
| 313 _elem_type: marker::PhantomData, | |
| 314 } | |
| 315 } | |
| 316 | |
| 317 /// Consumes this object and produces a plain handle wrapper | |
| 318 /// See mojo::system::handle for information on untyped vs. typed | |
| 319 fn as_untyped(self) -> handle::UntypedHandle { | |
| 320 self.handle | |
| 321 } | |
| 322 } | |
| 323 | |
| 324 impl<T> Handle for Consumer<T> { | |
| 325 /// Returns the native handle wrapped by this structure. | |
| 326 /// | |
| 327 /// See mojo::system::handle for information on handle wrappers | |
| 328 fn get_native_handle(&self) -> MojoHandle { | |
| 329 self.handle.get_native_handle() | |
| 330 } | |
| 331 } | |
| 332 | |
| 333 /// Represents the consumer half of a data pipe. | |
| 334 /// This data structure wraps a handle and acts | |
| 335 /// effectively as a typed handle. | |
| 336 /// | |
| 337 /// The purpose of the _elem_type field is to associate | |
| 338 /// a type with the consumer, as a data pipe works | |
| 339 /// in elements. | |
| 340 pub struct Producer<T> { | |
| 341 handle: handle::UntypedHandle, | |
| 342 _elem_type: marker::PhantomData<T>, | |
| 343 } | |
| 344 | |
| 345 impl<T> Producer<T> { | |
| 346 /// Perform a write operation on the producer end of the data pipe. | |
| 347 /// Returns the number of elements actually written. | |
| 348 pub fn write(&self, data: &[T], flags: WriteFlags) -> Result<usize, MojoResu
lt> { | |
| 349 let mut num_bytes = (data.len() * mem::size_of::<T>()) as u32; | |
| 350 let r = MojoResult::from_code(unsafe { | |
| 351 ffi::MojoWriteData(self.handle.get_native_handle(), | |
| 352 data.as_ptr() as *const ffi::c_void, | |
| 353 &mut num_bytes as *mut u32, | |
| 354 flags) | |
| 355 }); | |
| 356 if r != MojoResult::Okay { | |
| 357 Err(r) | |
| 358 } else { | |
| 359 Ok(num_bytes as usize) | |
| 360 } | |
| 361 } | |
| 362 | |
| 363 /// Start two-phase write and return a WriteDataBuffer to perform | |
| 364 /// write and commit. | |
| 365 /// | |
| 366 /// Borrows self as mutable so that no other operation may happen on | |
| 367 /// the producer until the two-phase write is committed. | |
| 368 pub fn begin(&self, flags: WriteFlags) -> Result<WriteDataBuffer<T>, MojoRes
ult> { | |
| 369 let wrapped_result = unsafe { self.begin_write(flags) }; | |
| 370 match wrapped_result { | |
| 371 Ok(arr) => { | |
| 372 Ok(WriteDataBuffer::<T> { | |
| 373 buffer: arr, | |
| 374 parent: self, | |
| 375 }) | |
| 376 } | |
| 377 Err(r) => Err(r), | |
| 378 } | |
| 379 } | |
| 380 | |
| 381 /// A private function that performs the first half of two-phase writing. | |
| 382 /// Kept private because it is unsafe to use (the array received may not | |
| 383 /// be valid if end_write is performed). | |
| 384 unsafe fn begin_write(&self, flags: WriteFlags) -> Result<&mut [T], MojoResu
lt> { | |
| 385 let mut buf_num_bytes: u32 = 0; | |
| 386 let mut pbuf: *mut ffi::c_void = mem::uninitialized(); | |
| 387 let r = MojoResult::from_code(ffi::MojoBeginWriteData(self.handle.get_na
tive_handle(), | |
| 388 &mut pbuf, | |
| 389 &mut buf_num_bytes
as *mut u32, | |
| 390 flags)); | |
| 391 if r != MojoResult::Okay { | |
| 392 Err(r) | |
| 393 } else { | |
| 394 let buf_elems = (buf_num_bytes as usize) / mem::size_of::<T>(); | |
| 395 let buf = slice::from_raw_parts_mut(pbuf as *mut T, buf_elems); | |
| 396 Ok(buf) | |
| 397 } | |
| 398 } | |
| 399 | |
| 400 /// A private function that performs the second half of two-phase writing. | |
| 401 /// Kept private because it is unsafe to use (the array received from start_
write | |
| 402 /// may not be valid if end_write is performed). | |
| 403 /// | |
| 404 /// Also assumes loads/stores aren't reordered such that a load/store may be | |
| 405 /// optimized to be run AFTER MojoEndWriteData(). In general, this is true a
s long | |
| 406 /// as raw pointers are used, but Rust's memory model is still undefined. If
you're | |
| 407 /// getting a bad/strange runtime error, it might be for this reason. | |
| 408 unsafe fn end_write(&self, elems_written: usize) -> MojoResult { | |
| 409 let elem_size = mem::size_of::<T>(); | |
| 410 MojoResult::from_code(ffi::MojoEndWriteData(self.handle.get_native_handl
e(), | |
| 411 (elems_written * elem_size)
as u32)) | |
| 412 } | |
| 413 } | |
| 414 | |
| 415 impl<T> CastHandle for Producer<T> { | |
| 416 /// Generates a Consumer from an untyped handle wrapper | |
| 417 /// See mojo::system::handle for information on untyped vs. typed | |
| 418 unsafe fn from_untyped(handle: handle::UntypedHandle) -> Self { | |
| 419 Producer::<T> { | |
| 420 handle: handle, | |
| 421 _elem_type: marker::PhantomData, | |
| 422 } | |
| 423 } | |
| 424 | |
| 425 /// Consumes this object and produces a plain handle wrapper | |
| 426 /// See mojo::system::handle for information on untyped vs. typed | |
| 427 fn as_untyped(self) -> handle::UntypedHandle { | |
| 428 self.handle | |
| 429 } | |
| 430 } | |
| 431 | |
| 432 impl<T> Handle for Producer<T> { | |
| 433 /// Returns the native handle wrapped by this structure. | |
| 434 /// | |
| 435 /// See mojo::system::handle for information on handle wrappers | |
| 436 fn get_native_handle(&self) -> MojoHandle { | |
| 437 self.handle.get_native_handle() | |
| 438 } | |
| 439 } | |
| OLD | NEW |