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