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