Skip to content

Commit

Permalink
Support empty IpcSharedMemory (#335)
Browse files Browse the repository at this point in the history
* Add tests for empty shared mem

* Simple empty slice

* Bump version to 0.18.1
  • Loading branch information
sagudev authored May 31, 2024
1 parent 25040c9 commit d8b7f32
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 27 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ipc-channel"
version = "0.18.0"
version = "0.18.1"
description = "A multiprocess drop-in replacement for Rust channels"
authors = ["The Servo Project Developers"]
license = "MIT OR Apache-2.0"
Expand Down
83 changes: 57 additions & 26 deletions src/ipc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -553,15 +553,20 @@ impl IpcReceiverSet {
derive(PartialEq)
)]
pub struct IpcSharedMemory {
os_shared_memory: OsIpcSharedMemory,
/// None represents no data (empty slice)
os_shared_memory: Option<OsIpcSharedMemory>,
}

impl Deref for IpcSharedMemory {
type Target = [u8];

#[inline]
fn deref(&self) -> &[u8] {
&self.os_shared_memory
if let Some(os_shared_memory) = &self.os_shared_memory {
os_shared_memory
} else {
&[]
}
}
}

Expand All @@ -571,16 +576,22 @@ impl<'de> Deserialize<'de> for IpcSharedMemory {
D: Deserializer<'de>,
{
let index: usize = Deserialize::deserialize(deserializer)?;
let os_shared_memory = OS_IPC_SHARED_MEMORY_REGIONS_FOR_DESERIALIZATION.with(
|os_ipc_shared_memory_regions_for_deserialization| {
// FIXME(pcwalton): This could panic if the data was corrupt and the index was out
// of bounds. We should return an `Err` result instead.
os_ipc_shared_memory_regions_for_deserialization.borrow_mut()[index]
.take()
.unwrap()
},
);
Ok(IpcSharedMemory { os_shared_memory })
if index == usize::MAX {
Ok(IpcSharedMemory::empty())
} else {
let os_shared_memory = OS_IPC_SHARED_MEMORY_REGIONS_FOR_DESERIALIZATION.with(
|os_ipc_shared_memory_regions_for_deserialization| {
// FIXME(pcwalton): This could panic if the data was corrupt and the index was out
// of bounds. We should return an `Err` result instead.
os_ipc_shared_memory_regions_for_deserialization.borrow_mut()[index]
.take()
.unwrap()
},
);
Ok(IpcSharedMemory {
os_shared_memory: Some(os_shared_memory),
})
}
}
}

Expand All @@ -589,32 +600,52 @@ impl Serialize for IpcSharedMemory {
where
S: Serializer,
{
let index = OS_IPC_SHARED_MEMORY_REGIONS_FOR_SERIALIZATION.with(
|os_ipc_shared_memory_regions_for_serialization| {
let mut os_ipc_shared_memory_regions_for_serialization =
os_ipc_shared_memory_regions_for_serialization.borrow_mut();
let index = os_ipc_shared_memory_regions_for_serialization.len();
os_ipc_shared_memory_regions_for_serialization.push(self.os_shared_memory.clone());
index
},
);
index.serialize(serializer)
if let Some(os_shared_memory) = &self.os_shared_memory {
let index = OS_IPC_SHARED_MEMORY_REGIONS_FOR_SERIALIZATION.with(
|os_ipc_shared_memory_regions_for_serialization| {
let mut os_ipc_shared_memory_regions_for_serialization =
os_ipc_shared_memory_regions_for_serialization.borrow_mut();
let index = os_ipc_shared_memory_regions_for_serialization.len();
os_ipc_shared_memory_regions_for_serialization.push(os_shared_memory.clone());
index
},
);
debug_assert!(index < usize::MAX);
index
} else {
usize::MAX
}
.serialize(serializer)
}
}

impl IpcSharedMemory {
const fn empty() -> Self {
Self {
os_shared_memory: None,
}
}

/// Create shared memory initialized with the bytes provided.
pub fn from_bytes(bytes: &[u8]) -> IpcSharedMemory {
IpcSharedMemory {
os_shared_memory: OsIpcSharedMemory::from_bytes(bytes),
if bytes.is_empty() {
IpcSharedMemory::empty()
} else {
IpcSharedMemory {
os_shared_memory: Some(OsIpcSharedMemory::from_bytes(bytes)),
}
}
}

/// Create a chunk of shared memory that is filled with the byte
/// provided.
pub fn from_byte(byte: u8, length: usize) -> IpcSharedMemory {
IpcSharedMemory {
os_shared_memory: OsIpcSharedMemory::from_byte(byte, length),
if length == 0 {
IpcSharedMemory::empty()
} else {
IpcSharedMemory {
os_shared_memory: Some(OsIpcSharedMemory::from_byte(byte, length)),
}
}
}
}
Expand Down
20 changes: 20 additions & 0 deletions src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,26 @@ fn shared_memory() {
.all(|byte| *byte == 0xba));
}

#[test]
fn shared_memory_slice() {
let (tx, rx) = ipc::channel().unwrap();
// test byte of size 0
let shared_memory = IpcSharedMemory::from_byte(42, 0);
tx.send(shared_memory.clone()).unwrap();
let received_shared_memory = rx.recv().unwrap();
assert_eq!(*received_shared_memory, *shared_memory);
// test empty slice
let shared_memory = IpcSharedMemory::from_bytes(&[]);
tx.send(shared_memory.clone()).unwrap();
let received_shared_memory = rx.recv().unwrap();
assert_eq!(*received_shared_memory, *shared_memory);
// test non-empty slice
let shared_memory = IpcSharedMemory::from_bytes(&[4, 2, 42]);
tx.send(shared_memory.clone()).unwrap();
let received_shared_memory = rx.recv().unwrap();
assert_eq!(*received_shared_memory, *shared_memory);
}

#[test]
#[cfg(any(
not(target_os = "windows"),
Expand Down

0 comments on commit d8b7f32

Please sign in to comment.