Skip to content

Commit 20ee406

Browse files
committed
zephyr: sync: channel: Add safety comments
Add comments describe the safey of unsafe blocks. Signed-off-by: David Brown <[email protected]>
1 parent 8ae23d6 commit 20ee406

File tree

1 file changed

+40
-2
lines changed

1 file changed

+40
-2
lines changed

zephyr/src/sync/channel.rs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ pub struct Sender<T> {
141141
flavor: SenderFlavor<T>,
142142
}
143143

144+
// SAFETY: We implement Send and Sync for the Sender itself, as long as the underlying data can be
145+
// sent. The underlying zephyr primitives used for the channel provide the Sync safety.
144146
unsafe impl<T: Send> Send for Sender<T> {}
145147
unsafe impl<T: Send> Sync for Sender<T> {}
146148

@@ -158,12 +160,18 @@ impl<T> Sender<T> {
158160
SenderFlavor::Unbounded { queue, .. } => {
159161
let msg = Box::new(Message::new(msg));
160162
let msg = Box::into_raw(msg);
163+
// SAFETY: Zephyr requires, for as long as the message remains in the queue, that
164+
// the first `usize` of the message be available for its use, and that the message
165+
// not be moved. The `into_raw` of the box consumes the box, so this is entirely a
166+
// raw pointer with no references from the Rust code. The item is not used until it
167+
// has been removed from the queue.
161168
unsafe {
162169
queue.send(msg as *mut c_void);
163170
}
164171
}
165172
SenderFlavor::Bounded(chan) => {
166173
// Retrieve a message buffer from the free list.
174+
// SAFETY: Please see the safety discussion on `Bounded` on what makes this safe.
167175
let buf = unsafe { chan.free.recv(timeout) };
168176
if buf.is_null() {
169177
return Err(SendError(msg));
@@ -200,13 +208,17 @@ impl<T> Drop for Sender<T> {
200208
fn drop(&mut self) {
201209
match &self.flavor {
202210
SenderFlavor::Unbounded { queue, .. } => {
211+
// SAFETY: It is not possible to free from Zephyr queues. This means drop has to
212+
// either leak or panic. We will panic for now.
203213
unsafe {
204214
queue.release(|_| {
205215
panic!("Unbounded queues cannot currently be dropped");
206216
})
207217
}
208218
}
209219
SenderFlavor::Bounded(chan) => {
220+
// SAFETY: It is not possible to free from Zephyr queues. This means drop has to
221+
// either leak or panic. We will panic for now.
210222
unsafe {
211223
chan.release(|_| {
212224
panic!("Bounded queues cannot currently be dropped");
@@ -256,6 +268,8 @@ pub struct Receiver<T> {
256268
flavor: ReceiverFlavor<T>,
257269
}
258270

271+
// SAFETY: We implement Send and Sync for the Receiver itself, as long as the underlying data can be
272+
// sent. The underlying zephyr primitives used for the channel provide the Sync safety.
259273
unsafe impl<T: Send> Send for Receiver<T> {}
260274
unsafe impl<T: Send> Sync for Receiver<T> {}
261275

@@ -270,6 +284,7 @@ impl<T> Receiver<T> {
270284
{
271285
match &self.flavor {
272286
ReceiverFlavor::Unbounded { queue, .. } => {
287+
// SAFETY: Messages were sent by converting a Box through `into_raw()`.
273288
let msg = unsafe {
274289
let msg = queue.recv(timeout);
275290
if msg.is_null() {
@@ -278,10 +293,15 @@ impl<T> Receiver<T> {
278293
msg
279294
};
280295
let msg = msg as *mut Message<T>;
296+
// SAFETY: After receiving the message from the queue's `recv` method, Zephyr will
297+
// no longer use the `usize` at the beginning, and it is safe for us to convert the
298+
// message back into a box, copy the field out of it, an allow the Box itself to be
299+
// freed.
281300
let msg = unsafe { Box::from_raw(msg) };
282301
Ok(msg.data)
283302
}
284303
ReceiverFlavor::Bounded(chan) => {
304+
// SAFETY: Please see the safety discussion on Bounded.
285305
let rawbuf = unsafe {
286306
let buf = chan.chan.recv(timeout);
287307
if buf.is_null() {
@@ -324,14 +344,17 @@ impl<T> Drop for Receiver<T> {
324344
fn drop(&mut self) {
325345
match &self.flavor {
326346
ReceiverFlavor::Unbounded { queue, .. } => {
347+
// SAFETY: As the Zephyr channel cannot be freed we must either leak or panic.
348+
// Chose panic for now.
327349
unsafe {
328350
queue.release(|_| {
329-
crate::printkln!("Release");
330-
true
351+
panic!("Unnbounded channel cannot be dropped");
331352
})
332353
}
333354
}
334355
ReceiverFlavor::Bounded(chan) => {
356+
// SAFETY: As the Zephyr channel cannot be freed we must either leak or panic.
357+
// Chose panic for now.
335358
unsafe {
336359
chan.release(|_| {
337360
panic!("Bounded channels cannot be dropped");
@@ -378,6 +401,20 @@ enum ReceiverFlavor<T> {
378401

379402
type Slot<T> = UnsafeCell<MaybeUninit<Message<T>>>;
380403

404+
// SAFETY: A Bounded channel contains an array of messages that are allocated together in a Box.
405+
// This Box is held for an eventual future implementation that is able to free the messages, once
406+
// they have all been taken from Zephyr's knowledge. For now, they could also be leaked.
407+
//
408+
// There are two `Queue`s used here: `free` is the free list of messages that are not being sent,
409+
// and `chan` for messages that have been sent but not received. Initially, all slots are placed on
410+
// the `free` queue. At any time, outside of the calls in this module, each slot must live inside
411+
// of one of the two queues. This means that the messages cannot be moved or accessed, except
412+
// inside of the individual send/receive operations. Zephyr makes use of the initial `usize` field
413+
// at the beginning of each Slot.
414+
//
415+
// We use MaybeUninit for the messages to avoid needing to initialize the messages. The individual
416+
// messages are accessed through pointers when they are retrieved from the Zephyr `Queue`, so these
417+
// values are never marked as initialized.
381418
/// Bounded channel implementation.
382419
struct Bounded<T> {
383420
/// The messages themselves. This Box owns the allocation of the messages, although it is
@@ -405,6 +442,7 @@ impl<T> Bounded<T> {
405442

406443
// Add each of the boxes to the free list.
407444
for slot in &slots {
445+
// SAFETY: See safety discussion on `Bounded`.
408446
unsafe {
409447
free.send(slot.get() as *mut c_void);
410448
}

0 commit comments

Comments
 (0)