base/
shm.rs

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
5use std::ffi::CStr;
6use std::ffi::CString;
7
8use libc::EINVAL;
9use serde::Deserialize;
10use serde::Serialize;
11
12use crate::descriptor::AsRawDescriptor;
13use crate::descriptor::SafeDescriptor;
14use crate::Error;
15use crate::RawDescriptor;
16use crate::Result;
17
18/// A shared memory file descriptor and its size.
19#[derive(Debug, Deserialize, Serialize)]
20pub struct SharedMemory {
21    #[serde(with = "crate::with_as_descriptor")]
22    pub descriptor: SafeDescriptor,
23    pub size: u64,
24}
25
26pub(crate) trait PlatformSharedMemory {
27    fn new(debug_name: &CStr, size: u64) -> Result<SharedMemory>;
28    fn from_safe_descriptor(descriptor: SafeDescriptor, size: u64) -> Result<SharedMemory>;
29}
30
31impl 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.
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.
45    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.
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.
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.
69impl AsRawDescriptor for SharedMemory {
70    fn as_raw_descriptor(&self) -> RawDescriptor {
71        self.descriptor.as_raw_descriptor()
72    }
73}
74
75impl From<SharedMemory> for SafeDescriptor {
76    fn from(sm: SharedMemory) -> SafeDescriptor {
77        sm.descriptor
78    }
79}
80
81impl audio_streams::shm_streams::SharedMemory for SharedMemory {
82    type Error = Error;
83
84    fn anon(size: u64) -> Result<Self> {
85        SharedMemory::new("shm_streams", size)
86    }
87
88    fn size(&self) -> u64 {
89        self.size()
90    }
91
92    #[cfg(any(target_os = "android", target_os = "linux"))]
93    fn as_raw_fd(&self) -> RawDescriptor {
94        self.as_raw_descriptor()
95    }
96}
97
98#[cfg(test)]
99mod tests {
100    use super::*;
101
102    #[test]
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]
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]
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}