1 // Copyright 2020 The ChromiumOS Authors 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::ffi::CStr; 6 use std::ffi::CString; 7 8 use libc::EINVAL; 9 use serde::Deserialize; 10 use serde::Serialize; 11 12 use crate::descriptor::AsRawDescriptor; 13 use crate::descriptor::SafeDescriptor; 14 use crate::Error; 15 use crate::RawDescriptor; 16 use crate::Result; 17 18 /// A shared memory file descriptor and its size. 19 #[derive(Debug, Deserialize, Serialize)] 20 pub struct SharedMemory { 21 #[serde(with = "crate::with_as_descriptor")] 22 pub descriptor: SafeDescriptor, 23 pub size: u64, 24 } 25 26 pub(crate) trait PlatformSharedMemory { new(debug_name: &CStr, size: u64) -> Result<SharedMemory>27 fn new(debug_name: &CStr, size: u64) -> Result<SharedMemory>; from_safe_descriptor(descriptor: SafeDescriptor, size: u64) -> Result<SharedMemory>28 fn from_safe_descriptor(descriptor: SafeDescriptor, size: u64) -> Result<SharedMemory>; 29 } 30 31 impl SharedMemory { 32 /// Creates a new shared memory object of the given size. 33 /// 34 /// |name| is purely for debugging purposes. It does not need to be unique, and it does 35 /// not affect any non-debugging related properties of the constructed shared memory. new<T: Into<Vec<u8>>>(debug_name: T, size: u64) -> Result<SharedMemory>36 pub fn new<T: Into<Vec<u8>>>(debug_name: T, size: u64) -> Result<SharedMemory> { 37 let debug_name = CString::new(debug_name).map_err(|_| super::Error::new(EINVAL))?; 38 <SharedMemory as PlatformSharedMemory>::new(&debug_name, size) 39 } 40 41 /// Gets the size in bytes of the shared memory. 42 /// 43 /// The size returned here does not reflect changes by other interfaces or users of the shared 44 /// memory file descriptor. size(&self) -> u6445 pub fn size(&self) -> u64 { 46 self.size 47 } 48 49 /// Creates a SharedMemory instance from a SafeDescriptor owning a reference to a 50 /// shared memory descriptor. Ownership of the underlying descriptor is transferred to the 51 /// new SharedMemory object. from_safe_descriptor(descriptor: SafeDescriptor, size: u64) -> Result<SharedMemory>52 pub fn from_safe_descriptor(descriptor: SafeDescriptor, size: u64) -> Result<SharedMemory> { 53 <SharedMemory as PlatformSharedMemory>::from_safe_descriptor(descriptor, size) 54 } 55 56 /// Clones the SharedMemory. The new SharedMemory will refer to the same 57 /// underlying object as the original. try_clone(&self) -> Result<SharedMemory>58 pub fn try_clone(&self) -> Result<SharedMemory> { 59 Ok(SharedMemory { 60 descriptor: self.descriptor.try_clone()?, 61 size: self.size, 62 }) 63 } 64 } 65 66 /// USE THIS CAUTIOUSLY. On Windows, the returned handle is not a file handle and cannot be used as 67 /// if it were one. It is a handle to a the associated file mapping object and should only be used 68 /// for memory-mapping the file view. 69 impl AsRawDescriptor for SharedMemory { as_raw_descriptor(&self) -> RawDescriptor70 fn as_raw_descriptor(&self) -> RawDescriptor { 71 self.descriptor.as_raw_descriptor() 72 } 73 } 74 75 impl From<SharedMemory> for SafeDescriptor { from(sm: SharedMemory) -> SafeDescriptor76 fn from(sm: SharedMemory) -> SafeDescriptor { 77 sm.descriptor 78 } 79 } 80 81 impl audio_streams::shm_streams::SharedMemory for SharedMemory { 82 type Error = Error; 83 anon(size: u64) -> Result<Self>84 fn anon(size: u64) -> Result<Self> { 85 SharedMemory::new("shm_streams", size) 86 } 87 size(&self) -> u6488 fn size(&self) -> u64 { 89 self.size() 90 } 91 92 #[cfg(any(target_os = "android", target_os = "linux"))] as_raw_fd(&self) -> RawDescriptor93 fn as_raw_fd(&self) -> RawDescriptor { 94 self.as_raw_descriptor() 95 } 96 } 97 98 #[cfg(test)] 99 mod tests { 100 use super::*; 101 102 #[test] new_1024()103 fn new_1024() { 104 let shm = SharedMemory::new("test", 1024).expect("failed to create shared memory"); 105 assert_eq!(shm.size(), 1024); 106 } 107 108 #[test] new_1028()109 fn new_1028() { 110 let shm = SharedMemory::new("name", 1028).expect("failed to create shared memory"); 111 assert_eq!(shm.size(), 1028); 112 } 113 114 #[test] new_too_huge()115 fn new_too_huge() { 116 SharedMemory::new("test", 0x8000_0000_0000_0000) 117 .expect_err("8 exabyte shared memory creation should fail"); 118 } 119 } 120