servo_base/generic_channel/
shared_memory.rs1use std::fmt;
6use std::ops::Deref;
7use std::sync::Arc;
8
9use ipc_channel::ipc::IpcSharedMemory;
10use malloc_size_of::MallocSizeOf;
11use serde::de::VariantAccess;
12use serde::{Deserialize, Deserializer, Serialize, Serializer};
13use servo_config::opts;
14
15#[derive(Clone)]
16pub struct GenericSharedMemory(GenericSharedMemoryVariant);
17
18#[derive(Clone)]
19enum GenericSharedMemoryVariant {
20 Ipc(IpcSharedMemory),
21 InProcess(Arc<Vec<u8>>),
22}
23
24impl Deref for GenericSharedMemory {
25 type Target = [u8];
26
27 #[inline]
28 fn deref(&self) -> &[u8] {
29 match &self.0 {
30 GenericSharedMemoryVariant::Ipc(ipc_shared_memory) => ipc_shared_memory,
31 GenericSharedMemoryVariant::InProcess(items) => items.as_slice(),
32 }
33 }
34}
35
36impl MallocSizeOf for GenericSharedMemory {
37 fn size_of(&self, ops: &mut malloc_size_of::MallocSizeOfOps) -> usize {
38 match &self.0 {
39 GenericSharedMemoryVariant::Ipc(_) => 0,
40 GenericSharedMemoryVariant::InProcess(items) => items.size_of(ops),
41 }
42 }
43}
44
45impl GenericSharedMemory {
46 pub fn from_bytes(bytes: &[u8]) -> Self {
47 if servo_config::opts::get().multiprocess || servo_config::opts::get().force_ipc {
48 GenericSharedMemory(GenericSharedMemoryVariant::Ipc(
49 IpcSharedMemory::from_bytes(bytes),
50 ))
51 } else {
52 GenericSharedMemory(GenericSharedMemoryVariant::InProcess(Arc::new(
53 bytes.to_owned(),
54 )))
55 }
56 }
57
58 pub fn from_byte(data: u8, length: usize) -> Self {
59 if servo_config::opts::get().multiprocess || servo_config::opts::get().force_ipc {
60 GenericSharedMemory(GenericSharedMemoryVariant::Ipc(IpcSharedMemory::from_byte(
61 data, length,
62 )))
63 } else {
64 GenericSharedMemory(GenericSharedMemoryVariant::InProcess(Arc::new(vec![
65 data;
66 length
67 ])))
68 }
69 }
70
71 pub fn from_vec(bytes: Vec<u8>) -> Self {
77 if servo_config::opts::get().multiprocess || servo_config::opts::get().force_ipc {
78 GenericSharedMemory(GenericSharedMemoryVariant::Ipc(
79 IpcSharedMemory::from_bytes(&bytes),
80 ))
81 } else {
82 GenericSharedMemory(GenericSharedMemoryVariant::InProcess(Arc::new(bytes)))
83 }
84 }
85
86 pub fn from_arc_vec(arc: Arc<Vec<u8>>) -> Self {
90 if servo_config::opts::get().multiprocess || servo_config::opts::get().force_ipc {
91 GenericSharedMemory(GenericSharedMemoryVariant::Ipc(
92 IpcSharedMemory::from_bytes(&arc),
93 ))
94 } else {
95 GenericSharedMemory(GenericSharedMemoryVariant::InProcess(arc))
96 }
97 }
98
99 pub fn into_arc_vec(self) -> Arc<Vec<u8>> {
102 match self.0 {
103 GenericSharedMemoryVariant::Ipc(ipc_shared_memory) => {
104 Arc::new(ipc_shared_memory.to_vec())
105 },
106 GenericSharedMemoryVariant::InProcess(arc) => arc,
107 }
108 }
109
110 pub fn from_bytes_with_mutator(bytes: &[u8], mutator: impl FnOnce(&mut [u8])) -> Self {
111 let mut shared_memory = Self::from_bytes(bytes);
112 match &mut shared_memory.0 {
113 GenericSharedMemoryVariant::Ipc(ipc_shared_memory) => {
114 #[expect(unsafe_code)]
115 unsafe {
116 mutator(ipc_shared_memory.deref_mut())
117 }
118 },
119 GenericSharedMemoryVariant::InProcess(arc) => mutator(
120 Arc::get_mut(arc)
121 .expect("Arc just created from bytes")
122 .as_mut_slice(),
123 ),
124 }
125 shared_memory
126 }
127}
128
129impl fmt::Debug for GenericSharedMemory {
130 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131 f.debug_tuple("GenericSharedMemory").finish()
132 }
133}
134
135impl Serialize for GenericSharedMemory {
136 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
137 match &self.0 {
138 GenericSharedMemoryVariant::Ipc(memory) => {
139 s.serialize_newtype_variant("GenericSharedMemory", 0, "Ipc", memory)
140 },
141 GenericSharedMemoryVariant::InProcess(arc) => {
142 if opts::get().multiprocess || opts::get().force_ipc {
143 return Err(serde::ser::Error::custom(
144 "Arc<Vec<u8>> found in multiprocess mode!",
145 ));
146 } let address = Arc::into_raw(arc.clone()) as *mut Vec<u8> as usize;
149 s.serialize_newtype_variant("GenericSharedMemory", 1, "InProcess", &address)
150 },
151 }
152 }
153}
154
155struct GenericSharedMemoryVisitor {}
156
157impl<'de> serde::de::Visitor<'de> for GenericSharedMemoryVisitor {
158 type Value = GenericSharedMemory;
159
160 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
161 formatter.write_str("a GenericReceiver variant")
162 }
163
164 fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
165 where
166 A: serde::de::EnumAccess<'de>,
167 {
168 #[derive(Deserialize)]
169 enum GenericSharedMemoryVariantNames {
170 Ipc,
171 InProcess,
172 }
173
174 let (variant_name, variant_data): (GenericSharedMemoryVariantNames, _) = data.variant()?;
175
176 match variant_name {
177 GenericSharedMemoryVariantNames::Ipc => variant_data
178 .newtype_variant::<IpcSharedMemory>()
179 .map(|receiver| GenericSharedMemory(GenericSharedMemoryVariant::Ipc(receiver))),
180 GenericSharedMemoryVariantNames::InProcess => {
181 if opts::get().multiprocess || servo_config::opts::get().force_ipc {
182 return Err(serde::de::Error::custom(
183 "Arc data found in multiprocess mode!",
184 ));
185 }
186 let addr = variant_data.newtype_variant::<usize>()?;
187 let ptr = addr as *mut Vec<u8>;
188 #[expect(unsafe_code)]
191 let arc = unsafe { Arc::from_raw(ptr) };
192 Ok(GenericSharedMemory(GenericSharedMemoryVariant::InProcess(
193 arc,
194 )))
195 },
196 }
197 }
198}
199
200impl<'a> Deserialize<'a> for GenericSharedMemory {
201 fn deserialize<D>(d: D) -> Result<GenericSharedMemory, D::Error>
202 where
203 D: Deserializer<'a>,
204 {
205 d.deserialize_enum(
206 "GenericSharedMemory",
207 &["Ipc", "InProcess"],
208 GenericSharedMemoryVisitor {},
209 )
210 }
211}
212
213#[cfg(test)]
214mod single_process_shared_memory_test {
215 use std::sync::Arc;
216
217 use ipc_channel::ipc::IpcSharedMemory;
218
219 use super::GenericSharedMemory;
220 use crate::generic_channel::{self};
221
222 #[test]
223 fn test_ipc() {
224 let bytes = vec![0xba; 10];
225 let bytes_copy = bytes.clone();
226 let shared_memory = GenericSharedMemory(super::GenericSharedMemoryVariant::Ipc(
227 IpcSharedMemory::from_bytes(&bytes),
228 ));
229
230 let (send, recv) = generic_channel::channel().unwrap();
231 send.send(shared_memory).expect("Could not send");
232 assert_eq!(recv.recv().unwrap().to_vec(), bytes_copy);
233 }
234
235 #[test]
236 fn test_inprocess() {
237 let bytes = vec![0xba; 10];
238 let bytes_copy = bytes.clone();
239 let shared_memory = GenericSharedMemory(super::GenericSharedMemoryVariant::InProcess(
240 Arc::new(bytes.clone()),
241 ));
242
243 let (send, recv) = generic_channel::channel().unwrap();
244 send.send(shared_memory).expect("Could not send");
245 assert_eq!(recv.recv().unwrap().to_vec(), bytes_copy);
246 }
247}