1mod ring_allocator;
6pub use ring_allocator::AllocationToken;
7use ring_allocator::RingAllocator;
8
9mod signal;
10use fuchsia_sync::Mutex;
11pub use signal::SIG_SHUTDOWN;
12use signal::{
13 EventSignal, SIG_DATA_AVAILABLE_0, SIG_DATA_AVAILABLE_1, SIG_SPACE_AVAILABLE_0,
14 SIG_SPACE_AVAILABLE_1,
15};
16use std::fmt::{Debug, Formatter};
17use std::sync::atomic::{AtomicU64, Ordering};
18use storage_ptr_slice::{MutPtrByteSlice, PtrByteSlice};
19use zerocopy::{FromBytes, IntoBytes, KnownLayout};
20
21struct MappedVmo {
22 vmo: zx::Vmo,
23 addr: usize,
24 size: usize,
25}
26
27impl MappedVmo {
28 fn new(vmo: zx::Vmo) -> Result<Self, zx::Status> {
29 let size = vmo.get_size()? as usize;
30 let addr = fuchsia_runtime::vmar_root_self().map(
31 0,
32 &vmo,
33 0,
34 size,
35 zx::VmarFlags::PERM_READ | zx::VmarFlags::PERM_WRITE,
36 )?;
37 Ok(Self { vmo, addr, size })
38 }
39
40 fn vmo(&self) -> &zx::Vmo {
41 &self.vmo
42 }
43
44 fn addr(&self) -> usize {
45 self.addr
46 }
47
48 fn size(&self) -> usize {
49 self.size
50 }
51}
52
53impl Drop for MappedVmo {
54 fn drop(&mut self) {
55 unsafe {
57 let _ = fuchsia_runtime::vmar_root_self().unmap(self.addr, self.size);
59 }
60 }
61}
62
63#[repr(transparent)]
65#[derive(Copy, Clone)]
66struct State(u64);
67
68impl State {
69 const HAS_WAITER: u64 = 1 << 63;
71 const INDEX_MASK: u64 = !Self::HAS_WAITER;
73
74 fn index(self) -> u64 {
75 self.0 & Self::INDEX_MASK
76 }
77
78 fn has_waiter(self) -> bool {
79 (self.0 & Self::HAS_WAITER) != 0
80 }
81
82 fn with_waiter(self) -> State {
83 State(self.0 | Self::HAS_WAITER)
84 }
85
86 fn clear_waiter_and_increment(self) -> State {
87 State(((self.0 & Self::INDEX_MASK) + 1) & Self::INDEX_MASK)
88 }
89}
90
91#[repr(C)]
95#[derive(FromBytes, IntoBytes, KnownLayout)]
96struct QueueHeader {
97 write_head: u64,
100 read_head: u64,
103}
104
105const HEADER_SIZE: usize = 64;
108
109struct SharedQueue<T> {
119 mapping: MappedVmo,
120 header: *mut QueueHeader,
121 slots: *mut T,
123 capacity: u32,
128
129 data_available: EventSignal,
131 space_available: EventSignal,
133
134 _phantom: std::marker::PhantomData<T>,
135}
136
137unsafe impl<T: Send> Send for SharedQueue<T> {}
143unsafe impl<T: Sync> Sync for SharedQueue<T> {}
144
145impl<T> SharedQueue<T>
146where
147 T: FromBytes + IntoBytes + KnownLayout + Copy,
148{
149 fn new(vmo: zx::Vmo, capacity: u32) -> Result<Self, zx::Status> {
154 if !capacity.is_power_of_two() {
156 return Err(zx::Status::INVALID_ARGS);
157 }
158
159 let mapping = MappedVmo::new(vmo)?;
161
162 let required_size = (capacity as usize)
164 .checked_mul(std::mem::size_of::<T>())
165 .and_then(|val| val.checked_add(HEADER_SIZE))
166 .ok_or(zx::Status::INVALID_ARGS)?;
167 if mapping.size < required_size {
168 return Err(zx::Status::BUFFER_TOO_SMALL);
169 }
170
171 let header = mapping.addr as *mut QueueHeader;
172 let slots = (mapping.addr + HEADER_SIZE) as *mut T;
173
174 Ok(Self {
175 mapping,
176 header,
177 slots,
178 capacity,
179 data_available: EventSignal::new(SIG_DATA_AVAILABLE_0, SIG_DATA_AVAILABLE_1),
180 space_available: EventSignal::new(SIG_SPACE_AVAILABLE_0, SIG_SPACE_AVAILABLE_1),
181 _phantom: std::marker::PhantomData,
182 })
183 }
184
185 fn vmo(&self) -> &zx::Vmo {
186 self.mapping.vmo()
187 }
188
189 fn capacity(&self) -> u32 {
190 self.capacity
191 }
192
193 fn addr(&self) -> usize {
194 self.mapping.addr()
195 }
196
197 fn vmo_size(&self) -> usize {
198 self.mapping.size()
199 }
200
201 fn payload_region_offset(&self) -> usize {
204 let raw_offset = HEADER_SIZE + self.capacity as usize * std::mem::size_of::<T>();
205 let page_size = zx::system_get_page_size() as usize;
206 (raw_offset + page_size - 1) & !(page_size - 1)
207 }
208
209 fn write_head_atomic(&self) -> &AtomicU64 {
210 unsafe {
215 let ptr = std::ptr::addr_of_mut!((*self.header).write_head);
216 AtomicU64::from_ptr(ptr)
217 }
218 }
219
220 fn read_head_atomic(&self) -> &AtomicU64 {
221 unsafe {
223 let ptr = std::ptr::addr_of_mut!((*self.header).read_head);
224 AtomicU64::from_ptr(ptr)
225 }
226 }
227
228 fn load_write_head(&self, ordering: Ordering) -> State {
229 State(self.write_head_atomic().load(ordering))
230 }
231
232 fn load_read_head(&self, ordering: Ordering) -> State {
233 State(self.read_head_atomic().load(ordering))
234 }
235
236 fn write_index(&self) -> u64 {
237 self.load_write_head(Ordering::Acquire).index()
238 }
239
240 fn read_index(&self) -> u64 {
241 self.load_read_head(Ordering::Acquire).index()
242 }
243
244 fn is_full_at(&self, write_idx: u64, read_idx: u64) -> bool {
245 (write_idx.wrapping_sub(read_idx) & State::INDEX_MASK) >= self.capacity as u64
246 }
247
248 fn is_full(&self) -> bool {
249 self.is_full_at(self.write_index(), self.read_index())
250 }
251
252 fn is_empty(&self) -> bool {
253 self.load_write_head(Ordering::Acquire).index()
254 == self.load_read_head(Ordering::Acquire).index()
255 }
256
257 fn get_slot_ptr(&self, index: u64) -> *mut T {
258 let slot_idx = ((index & State::INDEX_MASK) % self.capacity as u64) as isize;
259 unsafe { self.slots.offset(slot_idx) }
262 }
263}
264
265impl<T> SharedQueue<T> {
266 fn shutdown(&self) -> Result<(), zx::Status> {
268 self.mapping.vmo().signal(zx::Signals::empty(), SIG_SHUTDOWN)?;
269 Ok(())
270 }
271}
272
273struct SenderInner<T> {
275 inner: SharedQueue<T>,
276 allocator: RingAllocator,
277}
278impl<T: FromBytes + IntoBytes + KnownLayout + Copy> SenderInner<T> {
279 fn new(vmo: zx::Vmo, alignment: usize, capacity: u32) -> Result<Self, zx::Status> {
287 let inner = SharedQueue::new(vmo, capacity)?;
288 let payload_size = inner.vmo_size().saturating_sub(inner.payload_region_offset());
289 let allocator = RingAllocator::new(payload_size, inner.capacity() as usize, alignment);
290 Ok(Self { inner, allocator })
291 }
292
293 fn is_full(&self) -> bool {
294 self.inner.is_full()
295 }
296
297 fn capacity(&self) -> u32 {
298 self.inner.capacity()
299 }
300
301 fn index(&self) -> u64 {
302 self.inner.write_index()
303 }
304
305 fn vmo(&self) -> &zx::Vmo {
306 self.inner.vmo()
307 }
308
309 fn try_reserve_slot(
315 &mut self,
316 curr_write_head: State,
317 curr_read_head: &mut State,
318 ) -> Option<u64> {
319 let write_idx = curr_write_head.index();
320 loop {
321 if self.inner.is_full_at(write_idx, curr_read_head.index()) {
322 let next_read_head = curr_read_head.with_waiter();
324 match self.inner.read_head_atomic().compare_exchange_weak(
325 curr_read_head.0,
326 next_read_head.0,
327 Ordering::Relaxed,
329 Ordering::Acquire,
333 ) {
334 Ok(_) => return None,
335 Err(actual) => {
336 *curr_read_head = State(actual);
338 }
339 }
340 } else {
341 return Some(write_idx);
343 }
344 }
345 }
346
347 fn push_to_slot(&mut self, msg: T, mut curr_write_head: State) -> Result<u64, zx::Status> {
350 let write_idx = curr_write_head.index();
351
352 let slot_ptr = self.inner.get_slot_ptr(write_idx);
354 unsafe {
359 std::ptr::write(slot_ptr, msg);
360 }
361
362 loop {
364 let next_write_head = curr_write_head.clear_waiter_and_increment();
365 match self.inner.write_head_atomic().compare_exchange_weak(
366 curr_write_head.0,
367 next_write_head.0,
368 Ordering::Release,
371 Ordering::Relaxed,
375 ) {
376 Ok(prev_write_head) => {
377 if State(prev_write_head).has_waiter() {
379 let vmo = self.inner.mapping.vmo();
380 self.inner.data_available.signal(vmo)?;
381 }
382 return Ok(write_idx);
383 }
384 Err(actual) => curr_write_head = State(actual),
385 }
386 }
387 }
388
389 fn try_allocate_payload(
390 &mut self,
391 size: usize,
392 curr_read_head: &mut State,
393 ) -> Result<Option<AllocationToken>, zx::Status> {
394 if !self.allocator.is_within_capacity(size) {
395 return Err(zx::Status::NO_MEMORY);
396 }
397 loop {
398 let current_read_index = curr_read_head.index();
399 self.allocator.reclaim_consumed_slots(current_read_index);
400 match self.allocator.allocate(size) {
401 Some(token) => return Ok(Some(token)),
402 None => {
403 let next_read_head = curr_read_head.with_waiter();
405 match self.inner.read_head_atomic().compare_exchange_weak(
406 curr_read_head.0,
407 next_read_head.0,
408 Ordering::Relaxed,
410 Ordering::Acquire,
412 ) {
413 Ok(_) => return Ok(None),
414 Err(actual) => {
415 *curr_read_head = State(actual);
416 }
417 }
418 }
419 }
420 }
421 }
422}
423
424impl<T> SenderInner<T> {
425 fn shutdown(&self) -> Result<(), zx::Status> {
426 self.inner.shutdown()
427 }
428}
429
430impl<T> Drop for SenderInner<T> {
431 fn drop(&mut self) {
432 let _ = self.shutdown();
433 }
434}
435
436pub struct SyncSender<T>(SenderInner<T>);
438impl<T: FromBytes + IntoBytes + KnownLayout + Copy> SyncSender<T> {
439 pub fn new(vmo: zx::Vmo, alignment: usize, queue_capacity: u32) -> Result<Self, zx::Status> {
447 SenderInner::new(vmo, alignment, queue_capacity).map(Self)
448 }
449
450 pub fn capacity(&self) -> u32 {
451 self.0.capacity()
452 }
453
454 pub fn is_full(&self) -> bool {
455 self.0.is_full()
456 }
457
458 pub fn index(&self) -> u64 {
459 self.0.index()
460 }
461
462 pub fn vmo(&self) -> &zx::Vmo {
463 self.0.vmo()
464 }
465
466 pub fn shutdown(&self) -> Result<(), zx::Status> {
467 self.0.shutdown()
468 }
469
470 pub fn push(&mut self, msg: T) -> Result<u64, zx::Status> {
471 let curr_write_head = self.0.inner.load_write_head(Ordering::Relaxed);
474 let mut curr_read_head = self.0.inner.load_read_head(Ordering::Acquire);
477
478 loop {
479 match self.0.try_reserve_slot(curr_write_head, &mut curr_read_head) {
482 Some(_) => break,
483 None => {
484 let vmo = self.0.inner.mapping.vmo();
485 self.0.inner.space_available.wait(vmo, SIG_SHUTDOWN)?;
486 curr_read_head = self.0.inner.load_read_head(Ordering::Acquire);
487 }
488 }
489 }
490 self.0.push_to_slot(msg, curr_write_head)
491 }
492
493 pub fn reserve_payload(&mut self, size: usize) -> Result<PayloadBuffer<'_, T>, zx::Status> {
498 let mut curr_read_head = self.0.inner.load_read_head(Ordering::Acquire);
501
502 let token = loop {
503 match self.0.try_allocate_payload(size, &mut curr_read_head)? {
506 Some(token) => break token,
507 None => {
508 let vmo = self.0.inner.mapping.vmo();
509 self.0.inner.space_available.wait(vmo, SIG_SHUTDOWN)?;
510 curr_read_head = self.0.inner.load_read_head(Ordering::Acquire);
511 }
512 }
513 };
514
515 unsafe {
523 let abs_offset = self.0.inner.payload_region_offset() + token.offset() as usize;
524 let dest_ptr = (self.0.inner.addr() + abs_offset) as *mut u8;
525 let slice = std::ptr::slice_from_raw_parts_mut(dest_ptr, size);
526 Ok(PayloadBuffer {
527 sender: self,
528 token: Some(token),
529 slice: MutPtrByteSlice::new(slice),
530 })
531 }
532 }
533}
534
535pub struct AsyncSender<T>(SenderInner<T>);
537impl<T: FromBytes + IntoBytes + KnownLayout + Copy> AsyncSender<T> {
538 pub fn new(vmo: zx::Vmo, alignment: usize, queue_capacity: u32) -> Result<Self, zx::Status> {
546 SenderInner::new(vmo, alignment, queue_capacity).map(Self)
547 }
548
549 pub fn capacity(&self) -> u32 {
551 self.0.capacity()
552 }
553
554 pub fn is_full(&self) -> bool {
555 self.0.is_full()
556 }
557
558 pub fn vmo(&self) -> &zx::Vmo {
559 self.0.vmo()
560 }
561
562 pub async fn push(&mut self, msg: T) -> Result<u64, zx::Status> {
564 let curr_write_head = self.0.inner.load_write_head(Ordering::Relaxed);
567 let mut curr_read_head = self.0.inner.load_read_head(Ordering::Acquire);
570
571 loop {
572 match self.0.try_reserve_slot(curr_write_head, &mut curr_read_head) {
575 Some(_) => break,
576 None => {
577 let vmo = self.0.inner.mapping.vmo();
578 self.0.inner.space_available.wait_async(vmo, SIG_SHUTDOWN).await?;
581 curr_read_head = self.0.inner.load_read_head(Ordering::Acquire);
582 }
583 }
584 }
585
586 self.0.push_to_slot(msg, curr_write_head)
587 }
588
589 pub async fn reserve_payload(
593 &mut self,
594 size: usize,
595 ) -> Result<AsyncPayloadBuffer<'_, T>, zx::Status> {
596 let mut curr_read_head = self.0.inner.load_read_head(Ordering::Acquire);
599 let token = loop {
600 match self.0.try_allocate_payload(size, &mut curr_read_head)? {
603 Some(token) => break token,
604 None => {
605 let vmo = self.0.inner.mapping.vmo();
606 self.0.inner.space_available.wait_async(vmo, SIG_SHUTDOWN).await?;
607 curr_read_head = self.0.inner.load_read_head(Ordering::Acquire);
608 }
609 }
610 };
611
612 let slice = unsafe {
620 let abs_offset = self.0.inner.payload_region_offset() + token.offset() as usize;
621 let dest_ptr = (self.0.inner.addr() + abs_offset) as *mut u8;
622 MutPtrByteSlice::new(std::ptr::slice_from_raw_parts_mut(dest_ptr, size))
623 };
624 Ok(AsyncPayloadBuffer { sender: self, token: Some(token), slice })
625 }
626}
627
628pub struct PayloadBuffer<'a, T: FromBytes + IntoBytes + KnownLayout + Copy> {
631 sender: &'a mut SyncSender<T>,
634 token: Option<AllocationToken>,
635 slice: MutPtrByteSlice<'a>,
636}
637
638impl<'a, T: FromBytes + IntoBytes + KnownLayout + Copy> PayloadBuffer<'a, T> {
639 pub fn data(&mut self) -> &mut MutPtrByteSlice<'a> {
641 &mut self.slice
642 }
643
644 pub fn offset(&self) -> u32 {
646 self.token.as_ref().unwrap().offset()
647 }
648
649 pub fn commit(mut self, msg: T) -> Result<(), zx::Status> {
652 let token = self.token.take().unwrap();
653 match self.sender.push(msg) {
654 Ok(slot) => {
655 self.sender.0.allocator.commit_allocation_to_slot(slot, token);
656 Ok(())
657 }
658 Err(e) => {
659 self.sender.0.allocator.cancel_allocation(token);
660 Err(e)
661 }
662 }
663 }
664}
665
666impl<'a, T: FromBytes + IntoBytes + KnownLayout + Copy> Drop for PayloadBuffer<'a, T> {
667 fn drop(&mut self) {
668 if let Some(token) = self.token.take() {
669 self.sender.0.allocator.cancel_allocation(token);
670 }
671 }
672}
673
674pub struct AsyncPayloadBuffer<'a, T: FromBytes + IntoBytes + KnownLayout + Copy> {
677 sender: &'a mut AsyncSender<T>,
678 token: Option<AllocationToken>,
679 slice: MutPtrByteSlice<'a>,
680}
681
682impl<'a, T: FromBytes + IntoBytes + KnownLayout + Copy> AsyncPayloadBuffer<'a, T> {
683 pub fn data(&mut self) -> &mut MutPtrByteSlice<'a> {
685 &mut self.slice
686 }
687
688 pub fn offset(&self) -> u32 {
690 self.token.as_ref().unwrap().offset()
691 }
692
693 pub async fn commit(mut self, msg: T) -> Result<(), zx::Status> {
696 let token = self.token.take().unwrap();
697 match self.sender.push(msg).await {
698 Ok(slot) => {
699 self.sender.0.allocator.commit_allocation_to_slot(slot, token);
700 Ok(())
701 }
702 Err(e) => {
703 self.sender.0.allocator.cancel_allocation(token);
704 Err(e)
705 }
706 }
707 }
708}
709
710impl<'a, T: FromBytes + IntoBytes + KnownLayout + Copy> Drop for AsyncPayloadBuffer<'a, T> {
711 fn drop(&mut self) {
712 if let Some(token) = self.token.take() {
713 self.sender.0.allocator.cancel_allocation(token);
714 }
715 }
716}
717
718const PORT_KEY_SIGNAL: u64 = 1;
719const PORT_KEY_WAKE: u64 = 2;
720
721struct ReceiverState {
722 claim_index: u64,
723 committed_read_index: u64,
724 last_claim_write_index: u64,
725 completed_slots: Box<[bool]>,
726 data_available: EventSignal,
727 space_available: EventSignal,
728 wait_async_armed: bool,
729 shutting_down: bool,
730 sleeping_workers: usize,
731 active_workers: usize,
732}
733
734impl ReceiverState {
735 fn new(capacity: u32, initial_index: u64) -> Self {
737 Self {
738 claim_index: initial_index,
739 committed_read_index: initial_index,
740 last_claim_write_index: initial_index,
741 completed_slots: vec![false; capacity as usize].into_boxed_slice(),
742 data_available: EventSignal::new(SIG_DATA_AVAILABLE_0, SIG_DATA_AVAILABLE_1),
743 space_available: EventSignal::new(SIG_SPACE_AVAILABLE_0, SIG_SPACE_AVAILABLE_1),
744 wait_async_armed: false,
745 shutting_down: false,
746 sleeping_workers: 0,
747 active_workers: 0,
748 }
749 }
750}
751
752pub struct Receiver<T> {
754 inner: SharedQueue<T>,
755 port: zx::Port,
756 state: Mutex<ReceiverState>,
757}
758
759pub struct Message<'a, T: FromBytes + IntoBytes + KnownLayout + Copy> {
760 receiver: &'a Receiver<T>,
761 slot_index: u64,
762 claimed: bool,
763 popped: bool,
764 item: T,
765}
766
767impl<'a, T: FromBytes + IntoBytes + KnownLayout + Copy> std::ops::Deref for Message<'a, T> {
768 type Target = T;
769
770 fn deref(&self) -> &Self::Target {
771 &self.item
772 }
773}
774
775impl<'a, T: FromBytes + IntoBytes + KnownLayout + Copy + Debug> Debug for Message<'a, T> {
776 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
777 Debug::fmt(&self.item, f)
778 }
779}
780
781impl<'a, T: FromBytes + IntoBytes + KnownLayout + Copy> Message<'a, T> {
782 pub fn payload_region_offset(&self) -> usize {
783 self.receiver.payload_region_offset()
784 }
785
786 pub fn payload_slice(&self, vmo_offset: u32, len: u32) -> PtrByteSlice<'_> {
787 self.receiver.payload_slice(vmo_offset, len)
788 }
789
790 pub fn payload_mut_slice(&mut self, vmo_offset: u32, len: u32) -> MutPtrByteSlice<'_> {
796 unsafe { self.receiver.payload_mut_slice_unchecked(vmo_offset, len) }
799 }
800
801 pub fn pop(mut self) -> Result<(), zx::Status> {
803 self.pop_internal()
804 }
805
806 fn pop_internal(&mut self) -> Result<(), zx::Status> {
808 if self.popped {
809 return Ok(());
810 }
811 self.popped = true;
812 self.receiver.retire_slot(self.slot_index, self.claimed)
813 }
814}
815
816impl<'a, T: FromBytes + IntoBytes + KnownLayout + Copy> Drop for Message<'a, T> {
817 fn drop(&mut self) {
818 if self.claimed && !self.popped {
819 let _ = self.pop_internal();
820 }
821 }
822}
823
824impl<T: FromBytes + IntoBytes + KnownLayout + Copy> Receiver<T> {
825 pub fn new(vmo: zx::Vmo, capacity: u32) -> Result<Self, zx::Status> {
826 let inner = SharedQueue::new(vmo, capacity)?;
827 let port = zx::Port::create();
828 Ok(Self { inner, port, state: Mutex::new(ReceiverState::new(capacity, 0)) })
829 }
830
831 #[cfg(test)]
834 fn new_from_populated_vmo(vmo: zx::Vmo, capacity: u32) -> Result<Self, zx::Status> {
835 let inner = SharedQueue::new(vmo, capacity)?;
836 let initial_index = inner.read_index();
837 let port = zx::Port::create();
838 Ok(Self { inner, port, state: Mutex::new(ReceiverState::new(capacity, initial_index)) })
839 }
840
841 pub fn is_empty(&self) -> bool {
842 self.inner.is_empty()
843 }
844
845 pub fn capacity(&self) -> u32 {
846 self.inner.capacity()
847 }
848
849 pub fn index(&self) -> u64 {
850 self.inner.read_index()
851 }
852
853 pub fn vmo(&self) -> &zx::Vmo {
854 self.inner.vmo()
855 }
856
857 pub fn payload_region_offset(&self) -> usize {
858 self.inner.payload_region_offset()
859 }
860
861 pub fn peek(&mut self) -> Result<Message<'_, T>, zx::Status> {
863 self.next_internal(false, |_| ()).map(|(msg, ())| msg)
864 }
865
866 pub fn claim(&self) -> Result<Message<'_, T>, zx::Status> {
868 self.next_internal(true, |_| ()).map(|(msg, ())| msg)
869 }
870
871 pub fn claim_with<F, R>(&self, on_claim: F) -> Result<(Message<'_, T>, R), zx::Status>
875 where
876 F: FnOnce(&mut Message<'_, T>) -> R,
877 {
878 self.next_internal(true, on_claim)
879 }
880
881 pub fn will_maybe_reenter(&self) {
886 let state = self.state.lock();
887 if state.active_workers == 0
888 && state.sleeping_workers > 0
889 && state.claim_index != state.last_claim_write_index
890 {
891 let _ = self.port.queue(&zx::Packet::from_user_packet(
892 PORT_KEY_WAKE,
893 0,
894 zx::UserPacket::from_u8_array([0; 32]),
895 ));
896 }
897 }
898
899 fn next_internal<F, R>(
902 &self,
903 claim: bool,
904 on_claim: F,
905 ) -> Result<(Message<'_, T>, R), zx::Status>
906 where
907 F: FnOnce(&mut Message<'_, T>) -> R,
908 {
909 let mut state = self.state.lock();
910 loop {
911 let mut curr_write_head = self.inner.load_write_head(Ordering::Acquire);
914 if state.claim_index != curr_write_head.index() {
915 let slot_index = state.claim_index;
916 let slot_ptr = self.inner.get_slot_ptr(slot_index);
917 let item = unsafe { std::ptr::read(slot_ptr) };
921 if claim {
922 state.claim_index = (state.claim_index + 1) & State::INDEX_MASK;
923 state.active_workers += 1;
924 }
925
926 let mut msg =
927 Message { receiver: self, slot_index, claimed: claim, popped: false, item };
928 let res = on_claim(&mut msg);
929
930 if claim {
934 while state.sleeping_workers > 0
935 && !state.wait_async_armed
936 && !state.shutting_down
937 {
938 let asleep_write_head = curr_write_head.with_waiter();
939 match self.inner.write_head_atomic().compare_exchange_weak(
940 curr_write_head.0,
941 asleep_write_head.0,
942 Ordering::Relaxed,
943 Ordering::Acquire,
944 ) {
945 Ok(_) => {
946 let vmo = self.inner.mapping.vmo();
947 let mask = state.data_available.current_mask(SIG_SHUTDOWN);
948 vmo.wait_async(
949 &self.port,
950 PORT_KEY_SIGNAL,
951 mask,
952 zx::WaitAsyncOpts::empty(),
953 )?;
954 state.wait_async_armed = true;
955 }
956 Err(actual) => curr_write_head = State(actual),
957 }
958 }
959 state.last_claim_write_index = curr_write_head.index();
960 }
961
962 return Ok((msg, res));
963 }
964
965 if state.shutting_down {
966 return Err(zx::Status::CANCELED);
967 }
968
969 if !state.wait_async_armed {
972 let asleep_write_head = curr_write_head.with_waiter();
973 if self
974 .inner
975 .write_head_atomic()
976 .compare_exchange_weak(
977 curr_write_head.0,
978 asleep_write_head.0,
979 Ordering::Relaxed,
981 Ordering::Acquire,
983 )
984 .is_err()
985 {
986 continue;
987 }
988
989 let vmo = self.inner.mapping.vmo();
990 let mask = state.data_available.current_mask(SIG_SHUTDOWN);
991 vmo.wait_async(&self.port, PORT_KEY_SIGNAL, mask, zx::WaitAsyncOpts::empty())?;
992 state.wait_async_armed = true;
993 }
994
995 state.sleeping_workers += 1;
996 drop(state);
997
998 let wait_res = self.port.wait(zx::MonotonicInstant::INFINITE);
999 state = self.state.lock();
1000 state.sleeping_workers -= 1;
1001 let packet = wait_res?;
1002
1003 if packet.key() == PORT_KEY_SIGNAL {
1004 state.wait_async_armed = false;
1005 if let zx::PacketContents::SignalOne(signals) = packet.contents() {
1006 let observed = signals.observed();
1007 if observed.contains(state.data_available.current_mask(zx::Signals::empty())) {
1008 state.data_available.advance();
1009 }
1010 if observed.contains(SIG_SHUTDOWN) && !state.shutting_down {
1011 state.shutting_down = true;
1012 for _ in 0..state.sleeping_workers {
1013 let _ = self.port.queue(&zx::Packet::from_user_packet(
1014 PORT_KEY_WAKE,
1015 0,
1016 zx::UserPacket::from_u8_array([0; 32]),
1017 ));
1018 }
1019 }
1020 }
1021 }
1022 }
1023 }
1024
1025 fn retire_slot(&self, slot_index: u64, claimed: bool) -> Result<(), zx::Status> {
1028 let mut state = self.state.lock();
1029 if claimed {
1030 state.active_workers -= 1;
1031 } else if state.claim_index == slot_index {
1032 state.claim_index = (state.claim_index + 1) & State::INDEX_MASK;
1033 }
1034 let cap = self.inner.capacity() as u64;
1035 state.completed_slots[(slot_index % cap) as usize] = true;
1036 let mut advanced = false;
1037 loop {
1038 let committed_slot = (state.committed_read_index % cap) as usize;
1039 if !state.completed_slots[committed_slot] {
1040 break;
1041 }
1042 state.completed_slots[committed_slot] = false;
1043 state.committed_read_index = (state.committed_read_index + 1) & State::INDEX_MASK;
1044 advanced = true;
1045 }
1046
1047 if advanced {
1048 let target_read_index = state.committed_read_index;
1049 let mut curr_read_head = self.inner.load_read_head(Ordering::Relaxed);
1050 loop {
1051 let next_read_head = State(target_read_index);
1052 match self.inner.read_head_atomic().compare_exchange_weak(
1053 curr_read_head.0,
1054 next_read_head.0,
1055 Ordering::Release,
1058 Ordering::Relaxed,
1061 ) {
1062 Ok(prev_read_head) => {
1063 if State(prev_read_head).has_waiter() {
1065 let vmo = self.inner.mapping.vmo();
1066 state.space_available.signal(vmo)?;
1067 }
1068 break;
1069 }
1070 Err(actual) => curr_read_head = State(actual),
1071 }
1072 }
1073 }
1074 Ok(())
1075 }
1076
1077 pub fn payload_slice(&self, vmo_offset: u32, len: u32) -> PtrByteSlice<'_> {
1085 unsafe {
1093 let offset = self.inner.payload_region_offset() + vmo_offset as usize;
1094 assert!(offset + len as usize <= self.inner.vmo_size(), "Payload out of bounds");
1095 let dest_ptr = (self.inner.addr() + offset) as *const u8;
1096 let slice = std::ptr::slice_from_raw_parts(dest_ptr, len as usize);
1097 PtrByteSlice::new(slice)
1098 }
1099 }
1100
1101 pub fn payload_mut_slice(&mut self, vmo_offset: u32, len: u32) -> MutPtrByteSlice<'_> {
1107 unsafe { self.payload_mut_slice_unchecked(vmo_offset, len) }
1109 }
1110
1111 unsafe fn payload_mut_slice_unchecked(&self, vmo_offset: u32, len: u32) -> MutPtrByteSlice<'_> {
1114 unsafe {
1122 let offset = self.inner.payload_region_offset() + vmo_offset as usize;
1123 assert!(offset + len as usize <= self.inner.vmo_size(), "Payload out of bounds");
1124 let dest_ptr = (self.inner.addr() + offset) as *mut u8;
1125 let slice = std::ptr::slice_from_raw_parts_mut(dest_ptr, len as usize);
1126 MutPtrByteSlice::new(slice)
1127 }
1128 }
1129}
1130
1131impl<T> Receiver<T> {
1132 pub fn shutdown(&self) -> Result<(), zx::Status> {
1133 self.inner.shutdown()
1134 }
1135}
1136
1137impl<T> Drop for Receiver<T> {
1138 fn drop(&mut self) {
1139 let _ = self.shutdown();
1140 }
1141}
1142
1143#[cfg(test)]
1144mod tests {
1145 use super::*;
1146 use std::sync::Arc;
1147 use std::thread;
1148 use std::time::Duration;
1149
1150 #[derive(FromBytes, IntoBytes, KnownLayout, Clone, Copy, Debug, PartialEq)]
1151 #[repr(C)]
1152 struct TestMessage {
1153 val: u32,
1154 }
1155
1156 #[fuchsia::test]
1157 fn test_push_pop() {
1158 let vmo = zx::Vmo::create(4096).expect("VMO creation failed");
1159 let vmo_dup =
1160 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("duplicate_handle failed");
1161
1162 let mut sender = SyncSender::<TestMessage>::new(vmo, 1, 4).expect("Sender new failed");
1163 let mut receiver = Receiver::<TestMessage>::new(vmo_dup, 4).expect("Receiver new failed");
1164
1165 assert!(receiver.is_empty());
1166 assert!(!sender.is_full());
1167
1168 let expected = TestMessage { val: 42 };
1169 sender.push(expected).expect("push failed");
1170
1171 assert!(!receiver.is_empty());
1172
1173 let next_msg = receiver.peek().expect("peek failed");
1174 assert_eq!(*next_msg, expected);
1175
1176 next_msg.pop().expect("pop failed");
1177 assert!(receiver.is_empty());
1178 }
1179
1180 #[fuchsia::test]
1181 fn test_blocking_push_pop() {
1182 let vmo = zx::Vmo::create(4096).expect("VMO creation failed");
1183 let vmo_writer =
1184 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("VMO duplicate_handle failed");
1185
1186 let mut receiver = Receiver::<TestMessage>::new(vmo, 2).expect("receiver creation failed");
1187 let mut sender =
1188 SyncSender::<TestMessage>::new(vmo_writer, 8, 2).expect("sender creation failed");
1189
1190 let handle = std::thread::spawn(move || {
1191 let msg1 = TestMessage { val: 1 };
1192 let msg2 = TestMessage { val: 2 };
1193 let msg3 = TestMessage { val: 3 };
1194
1195 sender.push(msg1).expect("push failed");
1196 sender.push(msg2).expect("push failed");
1197 sender.push(msg3).expect("push failed");
1200 });
1201
1202 thread::sleep(Duration::from_millis(100));
1204
1205 let r1 = receiver.peek().expect("peek failed");
1206 assert_eq!(r1.val, 1);
1207 r1.pop().expect("pop failed");
1209
1210 let r2 = receiver.peek().expect("peek failed");
1211 assert_eq!(r2.val, 2);
1212 r2.pop().expect("pop failed");
1213
1214 let r3 = receiver.peek().expect("peek failed");
1215 assert_eq!(r3.val, 3);
1216 r3.pop().expect("pop failed");
1217
1218 handle.join().expect("writer thread panicked");
1219 }
1220
1221 #[fuchsia::test]
1222 fn test_index_wrap_around() {
1223 let vmo = zx::Vmo::create(4096).expect("VMO creation failed");
1224
1225 let start_idx = State::INDEX_MASK - 1;
1227 vmo.write(&start_idx.to_ne_bytes(), 0).expect("write failed");
1229 vmo.write(&start_idx.to_ne_bytes(), 8).expect("write failed");
1231
1232 let vmo_dup =
1233 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("duplicate_handle failed");
1234
1235 let mut sender = SyncSender::<TestMessage>::new(vmo, 8, 4).expect("Sender new failed");
1236 let mut receiver = Receiver::<TestMessage>::new_from_populated_vmo(vmo_dup, 4)
1237 .expect("Receiver new_from_populated_vmo failed");
1238
1239 assert_eq!(receiver.index(), start_idx);
1241 assert_eq!(sender.index(), start_idx);
1242
1243 sender.push(TestMessage { val: 10 }).expect("push failed");
1245 assert_eq!(sender.index(), State::INDEX_MASK);
1246
1247 sender.push(TestMessage { val: 20 }).expect("push failed");
1248 assert_eq!(sender.index(), 0);
1249
1250 sender.push(TestMessage { val: 30 }).expect("push failed");
1251 assert_eq!(sender.index(), 1);
1252
1253 let next_msg = receiver.peek().expect("peek failed");
1255 assert_eq!(next_msg.val, 10);
1256 next_msg.pop().expect("pop failed");
1257 assert_eq!(receiver.index(), State::INDEX_MASK);
1258
1259 let next_msg = receiver.peek().expect("peek failed");
1260 assert_eq!(next_msg.val, 20);
1261 next_msg.pop().expect("pop failed");
1262 assert_eq!(receiver.index(), 0);
1263
1264 let next_msg = receiver.peek().expect("peek failed");
1265 assert_eq!(next_msg.val, 30);
1266 next_msg.pop().expect("pop failed");
1267 assert_eq!(receiver.index(), 1);
1268
1269 assert!(receiver.is_empty());
1270 }
1271
1272 #[fuchsia::test]
1273 fn test_receiver_wakes_on_sender_drop() {
1274 let vmo = zx::Vmo::create(4096).expect("VMO creation failed");
1275 let vmo_dup =
1276 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("VMO duplicate_handle failed");
1277
1278 let sender = SyncSender::<TestMessage>::new(vmo, 8, 2).expect("Sender creation failed");
1279 let mut receiver =
1280 Receiver::<TestMessage>::new(vmo_dup, 2).expect("Receiver creation failed");
1281
1282 let handle = std::thread::spawn(move || {
1283 assert_eq!(receiver.peek().unwrap_err(), zx::Status::CANCELED);
1285 });
1286
1287 thread::sleep(Duration::from_millis(100));
1289
1290 drop(sender);
1292
1293 handle.join().expect("thread panicked");
1294 }
1295
1296 #[fuchsia::test]
1297 fn test_sender_wakes_on_receiver_drop() {
1298 let vmo = zx::Vmo::create(4096).expect("VMO creation failed");
1299 let vmo_dup =
1300 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("VMO duplicate_handle failed");
1301
1302 let mut sender = SyncSender::<TestMessage>::new(vmo, 8, 2).expect("Sender creation failed");
1303 let receiver = Receiver::<TestMessage>::new(vmo_dup, 2).expect("Receiver creation failed");
1304
1305 sender.push(TestMessage { val: 1 }).expect("push failed");
1307 sender.push(TestMessage { val: 2 }).expect("push failed");
1308
1309 let handle = std::thread::spawn(move || {
1310 sender.push(TestMessage { val: 3 })
1312 });
1313
1314 thread::sleep(Duration::from_millis(100));
1316
1317 drop(receiver);
1319
1320 let result = handle.join().expect("thread panicked");
1321 assert_eq!(result.unwrap_err(), zx::Status::CANCELED);
1322 }
1323
1324 #[derive(FromBytes, IntoBytes, KnownLayout, Clone, Copy, Debug, PartialEq)]
1326 #[repr(C)]
1327 struct WireTestCommand {
1328 opcode: u32,
1329 vmo_offset: u32,
1330 len: u32, _pad: u32,
1332 val: u64, }
1334
1335 #[derive(Debug, PartialEq)]
1336 enum TestCommand {
1337 WithPayload { vmo_offset: u32, len: u32 },
1338 NoPayload { val: u64 },
1339 }
1340
1341 impl TestCommand {
1342 fn to_wire(&self) -> WireTestCommand {
1343 match self {
1344 TestCommand::WithPayload { vmo_offset, len } => WireTestCommand {
1345 opcode: 0,
1346 vmo_offset: *vmo_offset,
1347 len: *len,
1348 _pad: 0,
1349 val: 0,
1350 },
1351 TestCommand::NoPayload { val } => {
1352 WireTestCommand { opcode: 1, vmo_offset: 0, len: 0, _pad: 0, val: *val }
1353 }
1354 }
1355 }
1356
1357 fn from_wire(wire: WireTestCommand) -> Self {
1358 match wire.opcode {
1359 0 => TestCommand::WithPayload { vmo_offset: wire.vmo_offset, len: wire.len },
1360 _ => TestCommand::NoPayload { val: wire.val },
1361 }
1362 }
1363 }
1364
1365 #[fuchsia::test]
1366 fn test_payload_drop_releases_allocation() {
1367 let page_size = zx::system_get_page_size() as u64;
1368 let vmo = zx::Vmo::create(page_size * 2).expect("VMO creation failed");
1369
1370 let mut sender =
1371 SyncSender::<WireTestCommand>::new(vmo, 8, 4).expect("Sender creation failed");
1372
1373 let buffer = sender.reserve_payload(10).expect("reserve failed");
1374 assert_eq!(buffer.offset(), 0);
1375
1376 drop(buffer);
1378
1379 let buffer2 = sender.reserve_payload(10).expect("reserve failed");
1381 assert_eq!(buffer2.offset(), 0);
1382 }
1383
1384 #[fuchsia::test]
1385 fn test_payload_buffer_drops_uncommitted_allocations() {
1386 let page_size = zx::system_get_page_size() as u64;
1387 let vmo = zx::Vmo::create(page_size * 2).expect("VMO creation failed");
1388
1389 let mut sender =
1390 SyncSender::<WireTestCommand>::new(vmo, 8, 4).expect("Sender creation failed");
1391
1392 let _ = (|| -> Result<(), ()> {
1395 let _buffer = sender.reserve_payload(10).expect("reserve failed");
1396
1397 Err(())
1400 })();
1401
1402 let buffer_after_bail = sender.reserve_payload(10).expect("reserve failed");
1405 assert_eq!(buffer_after_bail.offset(), 0);
1406 }
1407
1408 #[fuchsia::test]
1409 fn test_with_payload_commands() {
1410 let page_size = zx::system_get_page_size() as u64;
1411 let vmo = zx::Vmo::create(page_size * 2).expect("VMO creation failed");
1412 let vmo_dup =
1413 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("VMO duplicate_handle failed");
1414
1415 let mut sender =
1416 SyncSender::<WireTestCommand>::new(vmo, 8, 4).expect("Sender creation failed");
1417 let mut receiver =
1418 Receiver::<WireTestCommand>::new(vmo_dup, 4).expect("Receiver creation failed");
1419
1420 let mut buffer = sender.reserve_payload(10).expect("reserve failed");
1421 buffer.data().fill(0xAA);
1422 let wire_msg = TestCommand::WithPayload { vmo_offset: buffer.offset(), len: 10 }.to_wire();
1423 buffer.commit(wire_msg).expect("commit failed");
1424
1425 let standalone = TestCommand::NoPayload { val: 456 };
1426 sender.push(standalone.to_wire()).expect("push failed");
1427
1428 let msg1 = receiver.peek().expect("peek failed");
1429 let app_msg1 = TestCommand::from_wire(*msg1);
1430 if let TestCommand::WithPayload { vmo_offset, len } = app_msg1 {
1431 assert_eq!(len, 10);
1432 let read_data = msg1.payload_slice(vmo_offset, len);
1433 assert_eq!(read_data.to_vec(), vec![0xAA; 10]);
1434 } else {
1435 panic!("Expected TestCommand::WithPayload");
1436 }
1437 msg1.pop().expect("pop failed");
1438
1439 let msg2 = receiver.peek().expect("peek failed");
1440 let app_msg2 = TestCommand::from_wire(*msg2);
1441 assert_eq!(app_msg2, TestCommand::NoPayload { val: 456 });
1442 msg2.pop().expect("pop failed");
1443 }
1444
1445 #[fuchsia::test]
1446 fn test_pop_handles_canceled_race_condition() {
1447 for _ in 0..10000 {
1449 let vmo = zx::Vmo::create(4096).unwrap();
1450 let vmo_dup = vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap();
1451 let mut sender = SyncSender::<u32>::new(vmo, 4, 1).unwrap();
1452 let mut receiver = Receiver::<u32>::new(vmo_dup, 1).unwrap();
1453
1454 let handle = std::thread::spawn(move || {
1455 loop {
1457 let write_head = sender.0.inner.load_write_head(Ordering::Acquire);
1458 if write_head.has_waiter() {
1459 break;
1460 }
1461 std::thread::yield_now();
1462 }
1463
1464 sender.push(42).expect("push failed");
1466
1467 drop(sender);
1471 });
1472
1473 let val = receiver.peek().expect("peek failed on race condition");
1476 assert_eq!(*val, 42);
1477 val.pop().expect("pop failed");
1478
1479 assert_eq!(receiver.peek().unwrap_err(), zx::Status::CANCELED);
1481
1482 handle.join().unwrap();
1483 }
1484 }
1485
1486 #[fuchsia::test]
1487 async fn test_async_push_yields_when_full() {
1488 let page_size = zx::system_get_page_size() as u64;
1489 let vmo = zx::Vmo::create(page_size * 2).expect("failed to create VMO");
1490 let vmo_dup =
1491 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("failed to duplicate VMO handle");
1492
1493 let queue_capacity = 4;
1494 let mut sender = AsyncSender::<TestMessage>::new(vmo, 4, queue_capacity)
1495 .expect("failed to create AsyncSender");
1496 let mut receiver = Receiver::<TestMessage>::new(vmo_dup, queue_capacity)
1497 .expect("failed to create Receiver");
1498
1499 for i in 0..queue_capacity {
1500 sender.push(TestMessage { val: i }).await.expect("failed to push message");
1501 }
1502
1503 let push_task = async {
1504 sender
1505 .push(TestMessage { val: 42 })
1506 .await
1507 .expect("background push task failed after yielding");
1508 };
1509 let pop_thread = std::thread::spawn(move || {
1510 thread::sleep(Duration::from_millis(5));
1511 let msg = receiver.peek().expect("failed to peek message");
1512 assert_eq!(msg.val, 0); msg.pop().expect("failed to pop message");
1514 receiver
1515 });
1516
1517 push_task.await;
1518 let mut receiver = pop_thread.join().unwrap();
1519
1520 for expected in [1, 2, 3, 42] {
1521 let msg = receiver.peek().expect("failed to peek message");
1522 assert_eq!(msg.val, expected);
1523 msg.pop().expect("failed to pop message");
1524 }
1525 }
1526
1527 #[fuchsia::test]
1528 async fn test_reserve_payload_async_yields() {
1529 let page_size = zx::system_get_page_size() as u64;
1530 let vmo = zx::Vmo::create(page_size * 2).expect("failed to create VMO");
1531 let vmo_dup =
1532 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("failed to duplicate VMO handle");
1533
1534 let mut sender =
1535 AsyncSender::<TestMessage>::new(vmo, 4, 4).expect("failed to create AsyncSender");
1536 let mut receiver =
1537 Receiver::<TestMessage>::new(vmo_dup, 4).expect("failed to create Receiver");
1538
1539 let block1 = sender
1543 .reserve_payload(page_size as usize)
1544 .await
1545 .expect("failed to reserve payload capacity");
1546 block1.commit(TestMessage { val: 1 }).await.expect("failed to commit message block");
1547
1548 let reserve_task = async {
1550 let buffer = sender
1551 .reserve_payload(4)
1552 .await
1553 .expect("background reserve payload task failed after yielding");
1554 buffer.commit(TestMessage { val: 2 }).await.expect("failed to commit message block");
1555 };
1556 let pop_thread = std::thread::spawn(move || {
1557 thread::sleep(Duration::from_millis(5));
1559 let msg = receiver.peek().expect("failed to peek message");
1560 assert_eq!(msg.val, 1);
1561 msg.pop().expect("failed to pop message");
1562 receiver
1563 });
1564
1565 reserve_task.await;
1566 let mut receiver = pop_thread.join().unwrap();
1567
1568 let msg = receiver.peek().expect("failed to peek message");
1570 assert_eq!(msg.val, 2);
1571 msg.pop().expect("failed to pop message");
1572 }
1573
1574 #[fuchsia::test]
1575 async fn test_async_commit_yields_when_full() {
1576 let page_size = zx::system_get_page_size() as u64;
1577 let vmo = zx::Vmo::create(page_size * 2).expect("failed to create VMO");
1578 let vmo_dup =
1579 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("failed to duplicate VMO handle");
1580
1581 let queue_capacity = 4;
1582 let mut sender = AsyncSender::<WireTestCommand>::new(vmo, 4, queue_capacity)
1583 .expect("failed to create AsyncSender");
1584 let mut receiver = Receiver::<WireTestCommand>::new(vmo_dup, queue_capacity)
1585 .expect("failed to create Receiver");
1586
1587 for i in 0..queue_capacity {
1589 let standalone = TestCommand::NoPayload { val: i as u64 };
1590 sender.push(standalone.to_wire()).await.expect("failed to push message");
1591 }
1592
1593 let block = sender.reserve_payload(4).await.expect("failed to reserve payload capacity");
1595
1596 let commit_task = async {
1597 let msg = TestCommand::WithPayload { vmo_offset: block.offset(), len: 4 };
1598 block
1599 .commit(msg.to_wire())
1600 .await
1601 .expect("background commit task failed after yielding");
1602 };
1603
1604 let pop_thread = std::thread::spawn(move || {
1605 thread::sleep(Duration::from_millis(5));
1607
1608 for expected in 0..4 {
1610 let msg = receiver.peek().expect("failed to peek message");
1611 let app_msg = TestCommand::from_wire(*msg);
1612 assert!(matches!(app_msg, TestCommand::NoPayload { val } if val == expected));
1613 msg.pop().expect("failed to pop message");
1614 }
1615
1616 let msg2 = receiver.peek().expect("failed to pop payload message");
1618 let app_msg2 = TestCommand::from_wire(*msg2);
1619 assert!(matches!(app_msg2, TestCommand::WithPayload { .. }));
1620 msg2.pop().expect("failed to pop message");
1621 });
1622
1623 commit_task.await;
1624 pop_thread.join().unwrap();
1625 }
1626
1627 #[fuchsia::test]
1628 fn test_push_when_receiver_drops() {
1629 let vmo = zx::Vmo::create(4096).expect("VMO creation failed");
1630 let vmo_dup =
1631 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("VMO duplicate_handle failed");
1632
1633 let mut sender = SyncSender::<TestMessage>::new(vmo, 8, 4).expect("Sender creation failed");
1634 let receiver = Receiver::<TestMessage>::new(vmo_dup, 4).expect("Receiver creation failed");
1635
1636 drop(receiver);
1638
1639 sender.push(TestMessage { val: 1 }).expect("push failed");
1642 sender.push(TestMessage { val: 2 }).expect("push failed");
1643 sender.push(TestMessage { val: 3 }).expect("push failed");
1644 sender.push(TestMessage { val: 4 }).expect("push failed");
1645
1646 assert_eq!(sender.push(TestMessage { val: 5 }), Err(zx::Status::CANCELED));
1649 }
1650
1651 #[fuchsia::test]
1652 async fn test_async_push_when_receiver_drops() {
1653 let vmo = zx::Vmo::create(4096).expect("VMO creation failed");
1654 let vmo_dup =
1655 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("VMO duplicate_handle failed");
1656
1657 let mut sender =
1658 AsyncSender::<TestMessage>::new(vmo, 8, 4).expect("Sender creation failed");
1659 let receiver = Receiver::<TestMessage>::new(vmo_dup, 4).expect("Receiver creation failed");
1660
1661 drop(receiver);
1663
1664 sender.push(TestMessage { val: 1 }).await.expect("push failed");
1667 sender.push(TestMessage { val: 2 }).await.expect("push failed");
1668 sender.push(TestMessage { val: 3 }).await.expect("push failed");
1669 sender.push(TestMessage { val: 4 }).await.expect("push failed");
1670
1671 assert_eq!(sender.push(TestMessage { val: 5 }).await.unwrap_err(), zx::Status::CANCELED);
1674 }
1675
1676 #[fuchsia::test]
1677 fn test_reserve_payload_sync_exceeds_capacity() {
1678 let page_size = zx::system_get_page_size() as u64;
1679 let vmo = zx::Vmo::create(page_size * 2).expect("failed to create VMO");
1680 let vmo_dup =
1681 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("failed to duplicate VMO handle");
1682
1683 let mut sender =
1684 SyncSender::<TestMessage>::new(vmo, 4, 4).expect("failed to create Sender");
1685 let _receiver =
1686 Receiver::<TestMessage>::new(vmo_dup, 4).expect("failed to create Receiver");
1687
1688 let result = sender.reserve_payload((page_size + 10) as usize);
1691 assert_eq!(result.err(), Some(zx::Status::NO_MEMORY));
1692 }
1693
1694 #[fuchsia::test]
1695 async fn test_reserve_payload_async_exceeds_capacity() {
1696 let page_size = zx::system_get_page_size() as u64;
1697 let vmo = zx::Vmo::create(page_size * 2).expect("failed to create VMO");
1698 let vmo_dup =
1699 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("failed to duplicate VMO handle");
1700
1701 let mut sender =
1702 AsyncSender::<TestMessage>::new(vmo, 4, 4).expect("failed to create AsyncSender");
1703 let _receiver =
1704 Receiver::<TestMessage>::new(vmo_dup, 4).expect("failed to create Receiver");
1705
1706 let result = sender.reserve_payload((page_size + 10) as usize).await;
1709 assert_eq!(result.err(), Some(zx::Status::NO_MEMORY));
1710 }
1711
1712 #[fuchsia::test]
1713 fn test_concurrent_claim_out_of_order_retire() {
1714 let vmo = zx::Vmo::create(65536).expect("VMO creation failed");
1715 let vmo_dup =
1716 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("VMO duplicate_handle failed");
1717
1718 let mut sender = SyncSender::<TestMessage>::new(vmo, 8, 8).expect("Sender creation failed");
1719 let receiver =
1720 Arc::new(Receiver::<TestMessage>::new(vmo_dup, 8).expect("Receiver creation failed"));
1721
1722 sender.push(TestMessage { val: 10 }).expect("push 1 failed");
1723 sender.push(TestMessage { val: 20 }).expect("push 2 failed");
1724
1725 let msg1 = receiver.claim().expect("claim 1 failed");
1726 let msg2 = receiver.claim().expect("claim 2 failed");
1727 assert_eq!(msg1.val, 10);
1728 assert_eq!(msg2.val, 20);
1729 assert_eq!(receiver.index(), 0);
1730
1731 msg2.pop().expect("pop 2 failed");
1733 assert_eq!(receiver.index(), 0);
1734
1735 msg1.pop().expect("pop 1 failed");
1737 assert_eq!(receiver.index(), 2);
1738
1739 let seen = Arc::new(Mutex::new(Vec::new()));
1741 let mut threads = Vec::new();
1742 for _ in 0..2 {
1743 let rx = receiver.clone();
1744 let seen = seen.clone();
1745 threads.push(std::thread::spawn(move || {
1746 while let Ok(msg) = rx.claim() {
1747 seen.lock().push(msg.val);
1748 msg.pop().expect("pop failed");
1749 }
1750 }));
1751 }
1752
1753 for i in 0..100 {
1754 sender.push(TestMessage { val: i }).expect("push failed");
1755 }
1756 drop(sender);
1757
1758 for t in threads {
1759 t.join().expect("worker panicked");
1760 }
1761
1762 let mut results = seen.lock().clone();
1763 results.sort_unstable();
1764 assert_eq!(results, (0..100).collect::<Vec<u32>>());
1765 }
1766}