1mod ring_allocator;
6pub use ring_allocator::AllocationToken;
7use ring_allocator::RingAllocator;
8
9mod signal;
10pub use signal::SIG_SHUTDOWN;
11use signal::{
12 EventSignal, SIG_DATA_AVAILABLE_0, SIG_DATA_AVAILABLE_1, SIG_SPACE_AVAILABLE_0,
13 SIG_SPACE_AVAILABLE_1,
14};
15use std::fmt::{Debug, Formatter};
16use std::sync::atomic::{AtomicU64, Ordering};
17use storage_ptr_slice::{MutPtrByteSlice, PtrByteSlice};
18use zerocopy::{FromBytes, IntoBytes, KnownLayout};
19
20struct MappedVmo {
21 vmo: zx::Vmo,
22 addr: usize,
23 size: usize,
24}
25
26impl MappedVmo {
27 fn new(vmo: zx::Vmo) -> Result<Self, zx::Status> {
28 let size = vmo.get_size()? as usize;
29 let addr = fuchsia_runtime::vmar_root_self().map(
30 0,
31 &vmo,
32 0,
33 size,
34 zx::VmarFlags::PERM_READ | zx::VmarFlags::PERM_WRITE,
35 )?;
36 Ok(Self { vmo, addr, size })
37 }
38
39 fn vmo(&self) -> &zx::Vmo {
40 &self.vmo
41 }
42
43 fn addr(&self) -> usize {
44 self.addr
45 }
46
47 fn size(&self) -> usize {
48 self.size
49 }
50}
51
52impl Drop for MappedVmo {
53 fn drop(&mut self) {
54 unsafe {
56 let _ = fuchsia_runtime::vmar_root_self().unmap(self.addr, self.size);
58 }
59 }
60}
61
62#[repr(transparent)]
64#[derive(Copy, Clone)]
65struct State(u64);
66
67impl State {
68 const HAS_WAITER: u64 = 1 << 63;
70 const INDEX_MASK: u64 = !Self::HAS_WAITER;
72
73 fn index(self) -> u64 {
74 self.0 & Self::INDEX_MASK
75 }
76
77 fn has_waiter(self) -> bool {
78 (self.0 & Self::HAS_WAITER) != 0
79 }
80
81 fn with_waiter(self) -> State {
82 State(self.0 | Self::HAS_WAITER)
83 }
84
85 fn clear_waiter_and_increment(self) -> State {
86 State(((self.0 & Self::INDEX_MASK) + 1) & Self::INDEX_MASK)
87 }
88}
89
90#[repr(C)]
94#[derive(FromBytes, IntoBytes, KnownLayout)]
95struct QueueHeader {
96 write_head: u64,
99 read_head: u64,
102}
103
104const HEADER_SIZE: usize = 64;
107
108struct SharedQueue<T> {
118 mapping: MappedVmo,
119 header: *mut QueueHeader,
120 slots: *mut T,
122 capacity: u32,
127
128 data_available: EventSignal,
130 space_available: EventSignal,
132
133 _phantom: std::marker::PhantomData<T>,
134}
135
136unsafe impl<T: Send> Send for SharedQueue<T> {}
142unsafe impl<T: Sync> Sync for SharedQueue<T> {}
143
144impl<T> SharedQueue<T>
145where
146 T: FromBytes + IntoBytes + KnownLayout + Copy,
147{
148 fn new(vmo: zx::Vmo, capacity: u32) -> Result<Self, zx::Status> {
153 if !capacity.is_power_of_two() {
155 return Err(zx::Status::INVALID_ARGS);
156 }
157
158 let mapping = MappedVmo::new(vmo)?;
160
161 let required_size = (capacity as usize)
163 .checked_mul(std::mem::size_of::<T>())
164 .and_then(|val| val.checked_add(HEADER_SIZE))
165 .ok_or(zx::Status::INVALID_ARGS)?;
166 if mapping.size < required_size {
167 return Err(zx::Status::BUFFER_TOO_SMALL);
168 }
169
170 let header = mapping.addr as *mut QueueHeader;
171 let slots = (mapping.addr + HEADER_SIZE) as *mut T;
172
173 Ok(Self {
174 mapping,
175 header,
176 slots,
177 capacity,
178 data_available: EventSignal::new(SIG_DATA_AVAILABLE_0, SIG_DATA_AVAILABLE_1),
179 space_available: EventSignal::new(SIG_SPACE_AVAILABLE_0, SIG_SPACE_AVAILABLE_1),
180 _phantom: std::marker::PhantomData,
181 })
182 }
183
184 fn vmo(&self) -> &zx::Vmo {
185 self.mapping.vmo()
186 }
187
188 fn capacity(&self) -> u32 {
189 self.capacity
190 }
191
192 fn addr(&self) -> usize {
193 self.mapping.addr()
194 }
195
196 fn vmo_size(&self) -> usize {
197 self.mapping.size()
198 }
199
200 fn payload_region_offset(&self) -> usize {
203 let raw_offset = HEADER_SIZE + self.capacity as usize * std::mem::size_of::<T>();
204 let page_size = zx::system_get_page_size() as usize;
205 (raw_offset + page_size - 1) & !(page_size - 1)
206 }
207
208 fn write_head_atomic(&self) -> &AtomicU64 {
209 unsafe {
214 let ptr = std::ptr::addr_of_mut!((*self.header).write_head);
215 AtomicU64::from_ptr(ptr)
216 }
217 }
218
219 fn read_head_atomic(&self) -> &AtomicU64 {
220 unsafe {
222 let ptr = std::ptr::addr_of_mut!((*self.header).read_head);
223 AtomicU64::from_ptr(ptr)
224 }
225 }
226
227 fn load_write_head(&self, ordering: Ordering) -> State {
228 State(self.write_head_atomic().load(ordering))
229 }
230
231 fn load_read_head(&self, ordering: Ordering) -> State {
232 State(self.read_head_atomic().load(ordering))
233 }
234
235 fn write_index(&self) -> u64 {
236 self.load_write_head(Ordering::Acquire).index()
237 }
238
239 fn read_index(&self) -> u64 {
240 self.load_read_head(Ordering::Acquire).index()
241 }
242
243 fn is_full_at(&self, write_idx: u64, read_idx: u64) -> bool {
244 (write_idx.wrapping_sub(read_idx) & State::INDEX_MASK) >= self.capacity as u64
245 }
246
247 fn is_full(&self) -> bool {
248 self.is_full_at(self.write_index(), self.read_index())
249 }
250
251 fn is_empty(&self) -> bool {
252 self.load_write_head(Ordering::Acquire).index()
253 == self.load_read_head(Ordering::Acquire).index()
254 }
255
256 fn get_slot_ptr(&self, index: u64) -> *mut T {
257 let slot_idx = ((index & State::INDEX_MASK) % self.capacity as u64) as isize;
258 unsafe { self.slots.offset(slot_idx) }
261 }
262}
263
264impl<T> SharedQueue<T> {
265 fn shutdown(&self) -> Result<(), zx::Status> {
267 self.mapping.vmo().signal(zx::Signals::empty(), SIG_SHUTDOWN)?;
268 Ok(())
269 }
270}
271
272struct SenderInner<T> {
274 inner: SharedQueue<T>,
275 allocator: RingAllocator,
276}
277impl<T: FromBytes + IntoBytes + KnownLayout + Copy> SenderInner<T> {
278 fn new(vmo: zx::Vmo, alignment: usize, capacity: u32) -> Result<Self, zx::Status> {
286 let inner = SharedQueue::new(vmo, capacity)?;
287 let payload_size = inner.vmo_size().saturating_sub(inner.payload_region_offset());
288 let allocator = RingAllocator::new(payload_size, inner.capacity() as usize, alignment);
289 Ok(Self { inner, allocator })
290 }
291
292 fn is_full(&self) -> bool {
293 self.inner.is_full()
294 }
295
296 fn capacity(&self) -> u32 {
297 self.inner.capacity()
298 }
299
300 fn index(&self) -> u64 {
301 self.inner.write_index()
302 }
303
304 fn vmo(&self) -> &zx::Vmo {
305 self.inner.vmo()
306 }
307
308 fn try_reserve_slot(
314 &mut self,
315 curr_write_head: State,
316 curr_read_head: &mut State,
317 ) -> Option<u64> {
318 let write_idx = curr_write_head.index();
319 loop {
320 if self.inner.is_full_at(write_idx, curr_read_head.index()) {
321 let next_read_head = curr_read_head.with_waiter();
323 match self.inner.read_head_atomic().compare_exchange_weak(
324 curr_read_head.0,
325 next_read_head.0,
326 Ordering::Relaxed,
328 Ordering::Acquire,
332 ) {
333 Ok(_) => return None,
334 Err(actual) => {
335 *curr_read_head = State(actual);
337 }
338 }
339 } else {
340 return Some(write_idx);
342 }
343 }
344 }
345
346 fn push_to_slot(&mut self, msg: T, mut curr_write_head: State) -> Result<u64, zx::Status> {
349 let write_idx = curr_write_head.index();
350
351 let slot_ptr = self.inner.get_slot_ptr(write_idx);
353 unsafe {
358 std::ptr::write(slot_ptr, msg);
359 }
360
361 loop {
363 let next_write_head = curr_write_head.clear_waiter_and_increment();
364 match self.inner.write_head_atomic().compare_exchange_weak(
365 curr_write_head.0,
366 next_write_head.0,
367 Ordering::Release,
370 Ordering::Relaxed,
374 ) {
375 Ok(prev_write_head) => {
376 if State(prev_write_head).has_waiter() {
378 let vmo = self.inner.mapping.vmo();
379 self.inner.data_available.signal(vmo)?;
380 }
381 return Ok(write_idx);
382 }
383 Err(actual) => curr_write_head = State(actual),
384 }
385 }
386 }
387
388 fn try_allocate_payload(
389 &mut self,
390 size: usize,
391 curr_read_head: &mut State,
392 ) -> Result<Option<AllocationToken>, zx::Status> {
393 if !self.allocator.is_within_capacity(size) {
394 return Err(zx::Status::NO_MEMORY);
395 }
396 loop {
397 let current_read_index = curr_read_head.index();
398 self.allocator.reclaim_consumed_slots(current_read_index);
399 match self.allocator.allocate(size) {
400 Some(token) => return Ok(Some(token)),
401 None => {
402 let next_read_head = curr_read_head.with_waiter();
404 match self.inner.read_head_atomic().compare_exchange_weak(
405 curr_read_head.0,
406 next_read_head.0,
407 Ordering::Relaxed,
409 Ordering::Acquire,
411 ) {
412 Ok(_) => return Ok(None),
413 Err(actual) => {
414 *curr_read_head = State(actual);
415 }
416 }
417 }
418 }
419 }
420 }
421}
422
423impl<T> SenderInner<T> {
424 fn shutdown(&self) -> Result<(), zx::Status> {
425 self.inner.shutdown()
426 }
427}
428
429impl<T> Drop for SenderInner<T> {
430 fn drop(&mut self) {
431 let _ = self.shutdown();
432 }
433}
434
435pub struct SyncSender<T>(SenderInner<T>);
437impl<T: FromBytes + IntoBytes + KnownLayout + Copy> SyncSender<T> {
438 pub fn new(vmo: zx::Vmo, alignment: usize, queue_capacity: u32) -> Result<Self, zx::Status> {
446 SenderInner::new(vmo, alignment, queue_capacity).map(Self)
447 }
448
449 pub fn capacity(&self) -> u32 {
450 self.0.capacity()
451 }
452
453 pub fn is_full(&self) -> bool {
454 self.0.is_full()
455 }
456
457 pub fn index(&self) -> u64 {
458 self.0.index()
459 }
460
461 pub fn vmo(&self) -> &zx::Vmo {
462 self.0.vmo()
463 }
464
465 pub fn shutdown(&self) -> Result<(), zx::Status> {
466 self.0.shutdown()
467 }
468
469 pub fn push(&mut self, msg: T) -> Result<u64, zx::Status> {
470 let curr_write_head = self.0.inner.load_write_head(Ordering::Relaxed);
473 let mut curr_read_head = self.0.inner.load_read_head(Ordering::Acquire);
476
477 loop {
478 match self.0.try_reserve_slot(curr_write_head, &mut curr_read_head) {
481 Some(_) => break,
482 None => {
483 let vmo = self.0.inner.mapping.vmo();
484 self.0.inner.space_available.wait(vmo, SIG_SHUTDOWN)?;
485 curr_read_head = self.0.inner.load_read_head(Ordering::Acquire);
486 }
487 }
488 }
489 self.0.push_to_slot(msg, curr_write_head)
490 }
491
492 pub fn reserve_payload(&mut self, size: usize) -> Result<PayloadBuffer<'_, T>, zx::Status> {
497 let mut curr_read_head = self.0.inner.load_read_head(Ordering::Acquire);
500
501 let token = loop {
502 match self.0.try_allocate_payload(size, &mut curr_read_head)? {
505 Some(token) => break token,
506 None => {
507 let vmo = self.0.inner.mapping.vmo();
508 self.0.inner.space_available.wait(vmo, SIG_SHUTDOWN)?;
509 curr_read_head = self.0.inner.load_read_head(Ordering::Acquire);
510 }
511 }
512 };
513
514 unsafe {
522 let abs_offset = self.0.inner.payload_region_offset() + token.offset() as usize;
523 let dest_ptr = (self.0.inner.addr() + abs_offset) as *mut u8;
524 let slice = std::ptr::slice_from_raw_parts_mut(dest_ptr, size);
525 Ok(PayloadBuffer {
526 sender: self,
527 token: Some(token),
528 slice: MutPtrByteSlice::new(slice),
529 })
530 }
531 }
532}
533
534pub struct AsyncSender<T>(SenderInner<T>);
536impl<T: FromBytes + IntoBytes + KnownLayout + Copy> AsyncSender<T> {
537 pub fn new(vmo: zx::Vmo, alignment: usize, queue_capacity: u32) -> Result<Self, zx::Status> {
545 SenderInner::new(vmo, alignment, queue_capacity).map(Self)
546 }
547
548 pub fn capacity(&self) -> u32 {
550 self.0.capacity()
551 }
552
553 pub fn is_full(&self) -> bool {
554 self.0.is_full()
555 }
556
557 pub fn vmo(&self) -> &zx::Vmo {
558 self.0.vmo()
559 }
560
561 pub async fn push(&mut self, msg: T) -> Result<u64, zx::Status> {
563 let curr_write_head = self.0.inner.load_write_head(Ordering::Relaxed);
566 let mut curr_read_head = self.0.inner.load_read_head(Ordering::Acquire);
569
570 loop {
571 match self.0.try_reserve_slot(curr_write_head, &mut curr_read_head) {
574 Some(_) => break,
575 None => {
576 let vmo = self.0.inner.mapping.vmo();
577 self.0.inner.space_available.wait_async(vmo, SIG_SHUTDOWN).await?;
580 curr_read_head = self.0.inner.load_read_head(Ordering::Acquire);
581 }
582 }
583 }
584
585 self.0.push_to_slot(msg, curr_write_head)
586 }
587
588 pub async fn reserve_payload(
592 &mut self,
593 size: usize,
594 ) -> Result<AsyncPayloadBuffer<'_, T>, zx::Status> {
595 let mut curr_read_head = self.0.inner.load_read_head(Ordering::Acquire);
598 let token = loop {
599 match self.0.try_allocate_payload(size, &mut curr_read_head)? {
602 Some(token) => break token,
603 None => {
604 let vmo = self.0.inner.mapping.vmo();
605 self.0.inner.space_available.wait_async(vmo, SIG_SHUTDOWN).await?;
606 curr_read_head = self.0.inner.load_read_head(Ordering::Acquire);
607 }
608 }
609 };
610
611 let slice = unsafe {
619 let abs_offset = self.0.inner.payload_region_offset() + token.offset() as usize;
620 let dest_ptr = (self.0.inner.addr() + abs_offset) as *mut u8;
621 MutPtrByteSlice::new(std::ptr::slice_from_raw_parts_mut(dest_ptr, size))
622 };
623 Ok(AsyncPayloadBuffer { sender: self, token: Some(token), slice })
624 }
625}
626
627pub struct PayloadBuffer<'a, T: FromBytes + IntoBytes + KnownLayout + Copy> {
630 sender: &'a mut SyncSender<T>,
633 token: Option<AllocationToken>,
634 slice: MutPtrByteSlice<'a>,
635}
636
637impl<'a, T: FromBytes + IntoBytes + KnownLayout + Copy> PayloadBuffer<'a, T> {
638 pub fn data(&mut self) -> &mut MutPtrByteSlice<'a> {
640 &mut self.slice
641 }
642
643 pub fn offset(&self) -> u32 {
645 self.token.as_ref().unwrap().offset()
646 }
647
648 pub fn commit(mut self, msg: T) -> Result<(), zx::Status> {
651 let token = self.token.take().unwrap();
652 match self.sender.push(msg) {
653 Ok(slot) => {
654 self.sender.0.allocator.commit_allocation_to_slot(slot, token);
655 Ok(())
656 }
657 Err(e) => {
658 self.sender.0.allocator.cancel_allocation(token);
659 Err(e)
660 }
661 }
662 }
663}
664
665impl<'a, T: FromBytes + IntoBytes + KnownLayout + Copy> Drop for PayloadBuffer<'a, T> {
666 fn drop(&mut self) {
667 if let Some(token) = self.token.take() {
668 self.sender.0.allocator.cancel_allocation(token);
669 }
670 }
671}
672
673pub struct AsyncPayloadBuffer<'a, T: FromBytes + IntoBytes + KnownLayout + Copy> {
676 sender: &'a mut AsyncSender<T>,
677 token: Option<AllocationToken>,
678 slice: MutPtrByteSlice<'a>,
679}
680
681impl<'a, T: FromBytes + IntoBytes + KnownLayout + Copy> AsyncPayloadBuffer<'a, T> {
682 pub fn data(&mut self) -> &mut MutPtrByteSlice<'a> {
684 &mut self.slice
685 }
686
687 pub fn offset(&self) -> u32 {
689 self.token.as_ref().unwrap().offset()
690 }
691
692 pub async fn commit(mut self, msg: T) -> Result<(), zx::Status> {
695 let token = self.token.take().unwrap();
696 match self.sender.push(msg).await {
697 Ok(slot) => {
698 self.sender.0.allocator.commit_allocation_to_slot(slot, token);
699 Ok(())
700 }
701 Err(e) => {
702 self.sender.0.allocator.cancel_allocation(token);
703 Err(e)
704 }
705 }
706 }
707}
708
709impl<'a, T: FromBytes + IntoBytes + KnownLayout + Copy> Drop for AsyncPayloadBuffer<'a, T> {
710 fn drop(&mut self) {
711 if let Some(token) = self.token.take() {
712 self.sender.0.allocator.cancel_allocation(token);
713 }
714 }
715}
716
717pub struct Receiver<T> {
719 inner: SharedQueue<T>,
720 cached_read_index: u64,
721}
722
723pub struct Message<'a, T: FromBytes + IntoBytes + KnownLayout + Copy> {
724 receiver: &'a mut Receiver<T>,
725 item: T,
726}
727
728impl<'a, T: FromBytes + IntoBytes + KnownLayout + Copy> std::ops::Deref for Message<'a, T> {
729 type Target = T;
730
731 fn deref(&self) -> &Self::Target {
732 &self.item
733 }
734}
735
736impl<'a, T: FromBytes + IntoBytes + KnownLayout + Copy + Debug> Debug for Message<'a, T> {
737 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
738 Debug::fmt(&self.item, f)
739 }
740}
741
742impl<'a, T: FromBytes + IntoBytes + KnownLayout + Copy> Message<'a, T> {
743 pub fn payload_region_offset(&self) -> usize {
744 self.receiver.payload_region_offset()
745 }
746
747 pub fn payload_slice(&self, vmo_offset: u32, len: u32) -> PtrByteSlice<'_> {
748 self.receiver.payload_slice(vmo_offset, len)
749 }
750
751 pub fn pop(self) -> Result<(), zx::Status> {
753 let mut curr_read_head = State(self.receiver.cached_read_index);
758 loop {
759 let next_read_head = curr_read_head.clear_waiter_and_increment();
760 match self.receiver.inner.read_head_atomic().compare_exchange_weak(
761 curr_read_head.0,
762 next_read_head.0,
763 Ordering::Release,
766 Ordering::Relaxed,
770 ) {
771 Ok(prev_read_head) => {
772 self.receiver.cached_read_index = next_read_head.index();
773 if State(prev_read_head).has_waiter() {
775 let vmo = self.receiver.inner.mapping.vmo();
776 self.receiver.inner.space_available.signal(vmo)?;
777 }
778 return Ok(());
779 }
780 Err(actual) => curr_read_head = State(actual),
781 }
782 }
783 }
784}
785
786impl<T: FromBytes + IntoBytes + KnownLayout + Copy> Receiver<T> {
787 pub fn new(vmo: zx::Vmo, capacity: u32) -> Result<Self, zx::Status> {
788 Ok(Self { inner: SharedQueue::new(vmo, capacity)?, cached_read_index: 0 })
789 }
790
791 #[cfg(test)]
794 fn new_from_populated_vmo(vmo: zx::Vmo, capacity: u32) -> Result<Self, zx::Status> {
795 let inner = SharedQueue::new(vmo, capacity)?;
796 let cached_read_index = inner.read_index();
797 Ok(Self { inner, cached_read_index })
798 }
799
800 pub fn is_empty(&self) -> bool {
801 self.inner.is_empty()
802 }
803
804 pub fn capacity(&self) -> u32 {
805 self.inner.capacity()
806 }
807
808 pub fn index(&self) -> u64 {
809 self.inner.read_index()
810 }
811
812 pub fn vmo(&self) -> &zx::Vmo {
813 self.inner.vmo()
814 }
815
816 pub fn payload_region_offset(&self) -> usize {
817 self.inner.payload_region_offset()
818 }
819
820 pub fn peek(&mut self) -> Result<Message<'_, T>, zx::Status> {
822 let read_idx = self.cached_read_index;
823
824 let mut curr_write_head = self.inner.load_write_head(Ordering::Acquire);
827
828 loop {
829 if read_idx != curr_write_head.index() {
830 let slot_ptr = self.inner.get_slot_ptr(read_idx);
831 let msg = unsafe { std::ptr::read(slot_ptr) };
835 return Ok(Message { receiver: self, item: msg });
836 }
837
838 let asleep_write_head = curr_write_head.with_waiter();
841 match self.inner.write_head_atomic().compare_exchange_weak(
842 curr_write_head.0,
843 asleep_write_head.0,
844 Ordering::Relaxed,
848 Ordering::Acquire,
852 ) {
853 Ok(_) => {
854 let vmo = self.inner.mapping.vmo();
857 match self.inner.data_available.wait(vmo, SIG_SHUTDOWN) {
858 Ok(()) => curr_write_head = self.inner.load_write_head(Ordering::Acquire),
859 Err(zx::Status::CANCELED) => {
860 curr_write_head = self.inner.load_write_head(Ordering::Acquire);
863 if read_idx == curr_write_head.index() {
864 return Err(zx::Status::CANCELED);
865 }
866 }
867 Err(e) => return Err(e),
868 }
869 }
870 Err(actual) => curr_write_head = State(actual),
871 }
872 }
873 }
874
875 pub fn payload_slice(&self, vmo_offset: u32, len: u32) -> PtrByteSlice<'_> {
883 unsafe {
891 let offset = self.inner.payload_region_offset() + vmo_offset as usize;
892 assert!(offset + len as usize <= self.inner.vmo_size(), "Payload out of bounds");
893 let dest_ptr = (self.inner.addr() + offset) as *const u8;
894 let slice = std::ptr::slice_from_raw_parts(dest_ptr, len as usize);
895 PtrByteSlice::new(slice)
896 }
897 }
898}
899
900impl<T> Receiver<T> {
901 pub fn shutdown(&self) -> Result<(), zx::Status> {
902 self.inner.shutdown()
903 }
904}
905
906impl<T> Drop for Receiver<T> {
907 fn drop(&mut self) {
908 let _ = self.shutdown();
909 }
910}
911
912#[cfg(test)]
913mod tests {
914 use super::*;
915 use std::thread;
916 use std::time::Duration;
917
918 #[derive(FromBytes, IntoBytes, KnownLayout, Clone, Copy, Debug, PartialEq)]
919 #[repr(C)]
920 struct TestMessage {
921 val: u32,
922 }
923
924 #[fuchsia::test]
925 fn test_push_pop() {
926 let vmo = zx::Vmo::create(4096).expect("VMO creation failed");
927 let vmo_dup =
928 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("duplicate_handle failed");
929
930 let mut sender = SyncSender::<TestMessage>::new(vmo, 1, 4).expect("Sender new failed");
931 let mut receiver = Receiver::<TestMessage>::new(vmo_dup, 4).expect("Receiver new failed");
932
933 assert!(receiver.is_empty());
934 assert!(!sender.is_full());
935
936 let expected = TestMessage { val: 42 };
937 sender.push(expected).expect("push failed");
938
939 assert!(!receiver.is_empty());
940
941 let next_msg = receiver.peek().expect("peek failed");
942 assert_eq!(*next_msg, expected);
943
944 next_msg.pop().expect("pop failed");
945 assert!(receiver.is_empty());
946 }
947
948 #[fuchsia::test]
949 fn test_blocking_push_pop() {
950 let vmo = zx::Vmo::create(4096).expect("VMO creation failed");
951 let vmo_writer =
952 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("VMO duplicate_handle failed");
953
954 let mut receiver = Receiver::<TestMessage>::new(vmo, 2).expect("receiver creation failed");
955 let mut sender =
956 SyncSender::<TestMessage>::new(vmo_writer, 8, 2).expect("sender creation failed");
957
958 let handle = std::thread::spawn(move || {
959 let msg1 = TestMessage { val: 1 };
960 let msg2 = TestMessage { val: 2 };
961 let msg3 = TestMessage { val: 3 };
962
963 sender.push(msg1).expect("push failed");
964 sender.push(msg2).expect("push failed");
965 sender.push(msg3).expect("push failed");
968 });
969
970 thread::sleep(Duration::from_millis(100));
972
973 let r1 = receiver.peek().expect("peek failed");
974 assert_eq!(r1.val, 1);
975 r1.pop().expect("pop failed");
977
978 let r2 = receiver.peek().expect("peek failed");
979 assert_eq!(r2.val, 2);
980 r2.pop().expect("pop failed");
981
982 let r3 = receiver.peek().expect("peek failed");
983 assert_eq!(r3.val, 3);
984 r3.pop().expect("pop failed");
985
986 handle.join().expect("writer thread panicked");
987 }
988
989 #[fuchsia::test]
990 fn test_index_wrap_around() {
991 let vmo = zx::Vmo::create(4096).expect("VMO creation failed");
992
993 let start_idx = State::INDEX_MASK - 1;
995 vmo.write(&start_idx.to_ne_bytes(), 0).expect("write failed");
997 vmo.write(&start_idx.to_ne_bytes(), 8).expect("write failed");
999
1000 let vmo_dup =
1001 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("duplicate_handle failed");
1002
1003 let mut sender = SyncSender::<TestMessage>::new(vmo, 8, 4).expect("Sender new failed");
1004 let mut receiver = Receiver::<TestMessage>::new_from_populated_vmo(vmo_dup, 4)
1005 .expect("Receiver new_from_populated_vmo failed");
1006
1007 assert_eq!(receiver.index(), start_idx);
1009 assert_eq!(sender.index(), start_idx);
1010
1011 sender.push(TestMessage { val: 10 }).expect("push failed");
1013 assert_eq!(sender.index(), State::INDEX_MASK);
1014
1015 sender.push(TestMessage { val: 20 }).expect("push failed");
1016 assert_eq!(sender.index(), 0);
1017
1018 sender.push(TestMessage { val: 30 }).expect("push failed");
1019 assert_eq!(sender.index(), 1);
1020
1021 let next_msg = receiver.peek().expect("peek failed");
1023 assert_eq!(next_msg.val, 10);
1024 next_msg.pop().expect("pop failed");
1025 assert_eq!(receiver.index(), State::INDEX_MASK);
1026
1027 let next_msg = receiver.peek().expect("peek failed");
1028 assert_eq!(next_msg.val, 20);
1029 next_msg.pop().expect("pop failed");
1030 assert_eq!(receiver.index(), 0);
1031
1032 let next_msg = receiver.peek().expect("peek failed");
1033 assert_eq!(next_msg.val, 30);
1034 next_msg.pop().expect("pop failed");
1035 assert_eq!(receiver.index(), 1);
1036
1037 assert!(receiver.is_empty());
1038 }
1039
1040 #[fuchsia::test]
1041 fn test_receiver_wakes_on_sender_drop() {
1042 let vmo = zx::Vmo::create(4096).expect("VMO creation failed");
1043 let vmo_dup =
1044 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("VMO duplicate_handle failed");
1045
1046 let sender = SyncSender::<TestMessage>::new(vmo, 8, 2).expect("Sender creation failed");
1047 let mut receiver =
1048 Receiver::<TestMessage>::new(vmo_dup, 2).expect("Receiver creation failed");
1049
1050 let handle = std::thread::spawn(move || {
1051 assert_eq!(receiver.peek().unwrap_err(), zx::Status::CANCELED);
1053 });
1054
1055 thread::sleep(Duration::from_millis(100));
1057
1058 drop(sender);
1060
1061 handle.join().expect("thread panicked");
1062 }
1063
1064 #[fuchsia::test]
1065 fn test_sender_wakes_on_receiver_drop() {
1066 let vmo = zx::Vmo::create(4096).expect("VMO creation failed");
1067 let vmo_dup =
1068 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("VMO duplicate_handle failed");
1069
1070 let mut sender = SyncSender::<TestMessage>::new(vmo, 8, 2).expect("Sender creation failed");
1071 let receiver = Receiver::<TestMessage>::new(vmo_dup, 2).expect("Receiver creation failed");
1072
1073 sender.push(TestMessage { val: 1 }).expect("push failed");
1075 sender.push(TestMessage { val: 2 }).expect("push failed");
1076
1077 let handle = std::thread::spawn(move || {
1078 sender.push(TestMessage { val: 3 })
1080 });
1081
1082 thread::sleep(Duration::from_millis(100));
1084
1085 drop(receiver);
1087
1088 let result = handle.join().expect("thread panicked");
1089 assert_eq!(result.unwrap_err(), zx::Status::CANCELED);
1090 }
1091
1092 #[derive(FromBytes, IntoBytes, KnownLayout, Clone, Copy, Debug, PartialEq)]
1094 #[repr(C)]
1095 struct WireTestCommand {
1096 opcode: u32,
1097 vmo_offset: u32,
1098 len: u32, _pad: u32,
1100 val: u64, }
1102
1103 #[derive(Debug, PartialEq)]
1104 enum TestCommand {
1105 WithPayload { vmo_offset: u32, len: u32 },
1106 NoPayload { val: u64 },
1107 }
1108
1109 impl TestCommand {
1110 fn to_wire(&self) -> WireTestCommand {
1111 match self {
1112 TestCommand::WithPayload { vmo_offset, len } => WireTestCommand {
1113 opcode: 0,
1114 vmo_offset: *vmo_offset,
1115 len: *len,
1116 _pad: 0,
1117 val: 0,
1118 },
1119 TestCommand::NoPayload { val } => {
1120 WireTestCommand { opcode: 1, vmo_offset: 0, len: 0, _pad: 0, val: *val }
1121 }
1122 }
1123 }
1124
1125 fn from_wire(wire: WireTestCommand) -> Self {
1126 match wire.opcode {
1127 0 => TestCommand::WithPayload { vmo_offset: wire.vmo_offset, len: wire.len },
1128 _ => TestCommand::NoPayload { val: wire.val },
1129 }
1130 }
1131 }
1132
1133 #[fuchsia::test]
1134 fn test_payload_drop_releases_allocation() {
1135 let page_size = zx::system_get_page_size() as u64;
1136 let vmo = zx::Vmo::create(page_size * 2).expect("VMO creation failed");
1137
1138 let mut sender =
1139 SyncSender::<WireTestCommand>::new(vmo, 8, 4).expect("Sender creation failed");
1140
1141 let buffer = sender.reserve_payload(10).expect("reserve failed");
1142 assert_eq!(buffer.offset(), 0);
1143
1144 drop(buffer);
1146
1147 let buffer2 = sender.reserve_payload(10).expect("reserve failed");
1149 assert_eq!(buffer2.offset(), 0);
1150 }
1151
1152 #[fuchsia::test]
1153 fn test_payload_buffer_drops_uncommitted_allocations() {
1154 let page_size = zx::system_get_page_size() as u64;
1155 let vmo = zx::Vmo::create(page_size * 2).expect("VMO creation failed");
1156
1157 let mut sender =
1158 SyncSender::<WireTestCommand>::new(vmo, 8, 4).expect("Sender creation failed");
1159
1160 let _ = (|| -> Result<(), ()> {
1163 let _buffer = sender.reserve_payload(10).expect("reserve failed");
1164
1165 Err(())
1168 })();
1169
1170 let buffer_after_bail = sender.reserve_payload(10).expect("reserve failed");
1173 assert_eq!(buffer_after_bail.offset(), 0);
1174 }
1175
1176 #[fuchsia::test]
1177 fn test_with_payload_commands() {
1178 let page_size = zx::system_get_page_size() as u64;
1179 let vmo = zx::Vmo::create(page_size * 2).expect("VMO creation failed");
1180 let vmo_dup =
1181 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("VMO duplicate_handle failed");
1182
1183 let mut sender =
1184 SyncSender::<WireTestCommand>::new(vmo, 8, 4).expect("Sender creation failed");
1185 let mut receiver =
1186 Receiver::<WireTestCommand>::new(vmo_dup, 4).expect("Receiver creation failed");
1187
1188 let mut buffer = sender.reserve_payload(10).expect("reserve failed");
1189 buffer.data().fill(0xAA);
1190 let wire_msg = TestCommand::WithPayload { vmo_offset: buffer.offset(), len: 10 }.to_wire();
1191 buffer.commit(wire_msg).expect("commit failed");
1192
1193 let standalone = TestCommand::NoPayload { val: 456 };
1194 sender.push(standalone.to_wire()).expect("push failed");
1195
1196 let msg1 = receiver.peek().expect("peek failed");
1197 let app_msg1 = TestCommand::from_wire(*msg1);
1198 if let TestCommand::WithPayload { vmo_offset, len } = app_msg1 {
1199 assert_eq!(len, 10);
1200 let read_data = msg1.payload_slice(vmo_offset, len);
1201 assert_eq!(read_data.to_vec(), vec![0xAA; 10]);
1202 } else {
1203 panic!("Expected TestCommand::WithPayload");
1204 }
1205 msg1.pop().expect("pop failed");
1206
1207 let msg2 = receiver.peek().expect("peek failed");
1208 let app_msg2 = TestCommand::from_wire(*msg2);
1209 assert_eq!(app_msg2, TestCommand::NoPayload { val: 456 });
1210 msg2.pop().expect("pop failed");
1211 }
1212
1213 #[fuchsia::test]
1214 fn test_pop_handles_canceled_race_condition() {
1215 for _ in 0..10000 {
1217 let vmo = zx::Vmo::create(4096).unwrap();
1218 let vmo_dup = vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap();
1219 let mut sender = SyncSender::<u32>::new(vmo, 4, 1).unwrap();
1220 let mut receiver = Receiver::<u32>::new(vmo_dup, 1).unwrap();
1221
1222 let handle = std::thread::spawn(move || {
1223 loop {
1225 let write_head = sender.0.inner.load_write_head(Ordering::Acquire);
1226 if write_head.has_waiter() {
1227 break;
1228 }
1229 std::thread::yield_now();
1230 }
1231
1232 sender.push(42).expect("push failed");
1234
1235 drop(sender);
1239 });
1240
1241 let val = receiver.peek().expect("peek failed on race condition");
1244 assert_eq!(*val, 42);
1245 val.pop().expect("pop failed");
1246
1247 assert_eq!(receiver.peek().unwrap_err(), zx::Status::CANCELED);
1249
1250 handle.join().unwrap();
1251 }
1252 }
1253
1254 #[fuchsia::test]
1255 async fn test_async_push_yields_when_full() {
1256 let page_size = zx::system_get_page_size() as u64;
1257 let vmo = zx::Vmo::create(page_size * 2).expect("failed to create VMO");
1258 let vmo_dup =
1259 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("failed to duplicate VMO handle");
1260
1261 let queue_capacity = 4;
1262 let mut sender = AsyncSender::<TestMessage>::new(vmo, 4, queue_capacity)
1263 .expect("failed to create AsyncSender");
1264 let mut receiver = Receiver::<TestMessage>::new(vmo_dup, queue_capacity)
1265 .expect("failed to create Receiver");
1266
1267 for i in 0..queue_capacity {
1268 sender.push(TestMessage { val: i }).await.expect("failed to push message");
1269 }
1270
1271 let push_task = async {
1272 sender
1273 .push(TestMessage { val: 42 })
1274 .await
1275 .expect("background push task failed after yielding");
1276 };
1277 let pop_thread = std::thread::spawn(move || {
1278 thread::sleep(Duration::from_millis(5));
1279 let msg = receiver.peek().expect("failed to peek message");
1280 assert_eq!(msg.val, 0); msg.pop().expect("failed to pop message");
1282 receiver
1283 });
1284
1285 push_task.await;
1286 let mut receiver = pop_thread.join().unwrap();
1287
1288 for expected in [1, 2, 3, 42] {
1289 let msg = receiver.peek().expect("failed to peek message");
1290 assert_eq!(msg.val, expected);
1291 msg.pop().expect("failed to pop message");
1292 }
1293 }
1294
1295 #[fuchsia::test]
1296 async fn test_reserve_payload_async_yields() {
1297 let page_size = zx::system_get_page_size() as u64;
1298 let vmo = zx::Vmo::create(page_size * 2).expect("failed to create VMO");
1299 let vmo_dup =
1300 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("failed to duplicate VMO handle");
1301
1302 let mut sender =
1303 AsyncSender::<TestMessage>::new(vmo, 4, 4).expect("failed to create AsyncSender");
1304 let mut receiver =
1305 Receiver::<TestMessage>::new(vmo_dup, 4).expect("failed to create Receiver");
1306
1307 let block1 = sender
1311 .reserve_payload(page_size as usize)
1312 .await
1313 .expect("failed to reserve payload capacity");
1314 block1.commit(TestMessage { val: 1 }).await.expect("failed to commit message block");
1315
1316 let reserve_task = async {
1318 let buffer = sender
1319 .reserve_payload(4)
1320 .await
1321 .expect("background reserve payload task failed after yielding");
1322 buffer.commit(TestMessage { val: 2 }).await.expect("failed to commit message block");
1323 };
1324 let pop_thread = std::thread::spawn(move || {
1325 thread::sleep(Duration::from_millis(5));
1327 let msg = receiver.peek().expect("failed to peek message");
1328 assert_eq!(msg.val, 1);
1329 msg.pop().expect("failed to pop message");
1330 receiver
1331 });
1332
1333 reserve_task.await;
1334 let mut receiver = pop_thread.join().unwrap();
1335
1336 let msg = receiver.peek().expect("failed to peek message");
1338 assert_eq!(msg.val, 2);
1339 msg.pop().expect("failed to pop message");
1340 }
1341
1342 #[fuchsia::test]
1343 async fn test_async_commit_yields_when_full() {
1344 let page_size = zx::system_get_page_size() as u64;
1345 let vmo = zx::Vmo::create(page_size * 2).expect("failed to create VMO");
1346 let vmo_dup =
1347 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("failed to duplicate VMO handle");
1348
1349 let queue_capacity = 4;
1350 let mut sender = AsyncSender::<WireTestCommand>::new(vmo, 4, queue_capacity)
1351 .expect("failed to create AsyncSender");
1352 let mut receiver = Receiver::<WireTestCommand>::new(vmo_dup, queue_capacity)
1353 .expect("failed to create Receiver");
1354
1355 for i in 0..queue_capacity {
1357 let standalone = TestCommand::NoPayload { val: i as u64 };
1358 sender.push(standalone.to_wire()).await.expect("failed to push message");
1359 }
1360
1361 let block = sender.reserve_payload(4).await.expect("failed to reserve payload capacity");
1363
1364 let commit_task = async {
1365 let msg = TestCommand::WithPayload { vmo_offset: block.offset(), len: 4 };
1366 block
1367 .commit(msg.to_wire())
1368 .await
1369 .expect("background commit task failed after yielding");
1370 };
1371
1372 let pop_thread = std::thread::spawn(move || {
1373 thread::sleep(Duration::from_millis(5));
1375
1376 for expected in 0..4 {
1378 let msg = receiver.peek().expect("failed to peek message");
1379 let app_msg = TestCommand::from_wire(*msg);
1380 assert!(matches!(app_msg, TestCommand::NoPayload { val } if val == expected));
1381 msg.pop().expect("failed to pop message");
1382 }
1383
1384 let msg2 = receiver.peek().expect("failed to pop payload message");
1386 let app_msg2 = TestCommand::from_wire(*msg2);
1387 assert!(matches!(app_msg2, TestCommand::WithPayload { .. }));
1388 msg2.pop().expect("failed to pop message");
1389 });
1390
1391 commit_task.await;
1392 pop_thread.join().unwrap();
1393 }
1394
1395 #[fuchsia::test]
1396 fn test_push_when_receiver_drops() {
1397 let vmo = zx::Vmo::create(4096).expect("VMO creation failed");
1398 let vmo_dup =
1399 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("VMO duplicate_handle failed");
1400
1401 let mut sender = SyncSender::<TestMessage>::new(vmo, 8, 4).expect("Sender creation failed");
1402 let receiver = Receiver::<TestMessage>::new(vmo_dup, 4).expect("Receiver creation failed");
1403
1404 drop(receiver);
1406
1407 sender.push(TestMessage { val: 1 }).expect("push failed");
1410 sender.push(TestMessage { val: 2 }).expect("push failed");
1411 sender.push(TestMessage { val: 3 }).expect("push failed");
1412 sender.push(TestMessage { val: 4 }).expect("push failed");
1413
1414 assert_eq!(sender.push(TestMessage { val: 5 }), Err(zx::Status::CANCELED));
1417 }
1418
1419 #[fuchsia::test]
1420 async fn test_async_push_when_receiver_drops() {
1421 let vmo = zx::Vmo::create(4096).expect("VMO creation failed");
1422 let vmo_dup =
1423 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("VMO duplicate_handle failed");
1424
1425 let mut sender =
1426 AsyncSender::<TestMessage>::new(vmo, 8, 4).expect("Sender creation failed");
1427 let receiver = Receiver::<TestMessage>::new(vmo_dup, 4).expect("Receiver creation failed");
1428
1429 drop(receiver);
1431
1432 sender.push(TestMessage { val: 1 }).await.expect("push failed");
1435 sender.push(TestMessage { val: 2 }).await.expect("push failed");
1436 sender.push(TestMessage { val: 3 }).await.expect("push failed");
1437 sender.push(TestMessage { val: 4 }).await.expect("push failed");
1438
1439 assert_eq!(sender.push(TestMessage { val: 5 }).await.unwrap_err(), zx::Status::CANCELED);
1442 }
1443
1444 #[fuchsia::test]
1445 fn test_reserve_payload_sync_exceeds_capacity() {
1446 let page_size = zx::system_get_page_size() as u64;
1447 let vmo = zx::Vmo::create(page_size * 2).expect("failed to create VMO");
1448 let vmo_dup =
1449 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("failed to duplicate VMO handle");
1450
1451 let mut sender =
1452 SyncSender::<TestMessage>::new(vmo, 4, 4).expect("failed to create Sender");
1453 let _receiver =
1454 Receiver::<TestMessage>::new(vmo_dup, 4).expect("failed to create Receiver");
1455
1456 let result = sender.reserve_payload((page_size + 10) as usize);
1459 assert_eq!(result.err(), Some(zx::Status::NO_MEMORY));
1460 }
1461
1462 #[fuchsia::test]
1463 async fn test_reserve_payload_async_exceeds_capacity() {
1464 let page_size = zx::system_get_page_size() as u64;
1465 let vmo = zx::Vmo::create(page_size * 2).expect("failed to create VMO");
1466 let vmo_dup =
1467 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("failed to duplicate VMO handle");
1468
1469 let mut sender =
1470 AsyncSender::<TestMessage>::new(vmo, 4, 4).expect("failed to create AsyncSender");
1471 let _receiver =
1472 Receiver::<TestMessage>::new(vmo_dup, 4).expect("failed to create Receiver");
1473
1474 let result = sender.reserve_payload((page_size + 10) as usize).await;
1477 assert_eq!(result.err(), Some(zx::Status::NO_MEMORY));
1478 }
1479}