1mod ring_allocator;
6pub use ring_allocator::AllocationToken;
7use ring_allocator::RingAllocator;
8
9mod signal;
10use signal::{
11 EventSignal, SIG_DATA_AVAILABLE_0, SIG_DATA_AVAILABLE_1, SIG_SHUTDOWN, SIG_SPACE_AVAILABLE_0,
12 SIG_SPACE_AVAILABLE_1,
13};
14use std::sync::atomic::{AtomicU64, Ordering};
15use storage_ptr_slice::{MutPtrByteSlice, PtrByteSlice};
16use zerocopy::{FromBytes, IntoBytes, KnownLayout};
17
18struct MappedVmo {
19 vmo: zx::Vmo,
20 addr: usize,
21 size: usize,
22}
23
24impl MappedVmo {
25 fn new(vmo: zx::Vmo) -> Result<Self, zx::Status> {
26 let size = vmo.get_size()? as usize;
27 let addr = fuchsia_runtime::vmar_root_self().map(
28 0,
29 &vmo,
30 0,
31 size,
32 zx::VmarFlags::PERM_READ | zx::VmarFlags::PERM_WRITE,
33 )?;
34 Ok(Self { vmo, addr, size })
35 }
36
37 fn vmo(&self) -> &zx::Vmo {
38 &self.vmo
39 }
40
41 fn addr(&self) -> usize {
42 self.addr
43 }
44
45 fn size(&self) -> usize {
46 self.size
47 }
48}
49
50impl Drop for MappedVmo {
51 fn drop(&mut self) {
52 unsafe {
54 let _ = fuchsia_runtime::vmar_root_self().unmap(self.addr, self.size);
56 }
57 }
58}
59
60#[repr(transparent)]
62#[derive(Copy, Clone)]
63struct State(u64);
64
65impl State {
66 const HAS_WAITER: u64 = 1 << 63;
68 const INDEX_MASK: u64 = !Self::HAS_WAITER;
70
71 fn index(self) -> u64 {
72 self.0 & Self::INDEX_MASK
73 }
74
75 fn has_waiter(self) -> bool {
76 (self.0 & Self::HAS_WAITER) != 0
77 }
78
79 fn with_waiter(self) -> State {
80 State(self.0 | Self::HAS_WAITER)
81 }
82
83 fn clear_waiter_and_increment(self) -> State {
84 State(((self.0 & Self::INDEX_MASK) + 1) & Self::INDEX_MASK)
85 }
86}
87
88#[repr(C)]
92#[derive(FromBytes, IntoBytes, KnownLayout)]
93struct QueueHeader {
94 write_head: u64,
97 read_head: u64,
100}
101
102const HEADER_SIZE: usize = 64;
105
106struct SharedQueue<T> {
116 mapping: MappedVmo,
117 header: *mut QueueHeader,
118 slots: *mut T,
120 capacity: u32,
125
126 data_available: EventSignal,
128 space_available: EventSignal,
130
131 _phantom: std::marker::PhantomData<T>,
132}
133
134unsafe impl<T: Send> Send for SharedQueue<T> {}
140unsafe impl<T: Sync> Sync for SharedQueue<T> {}
141
142impl<T> SharedQueue<T>
143where
144 T: FromBytes + IntoBytes + KnownLayout + Copy,
145{
146 fn new(vmo: zx::Vmo, capacity: u32) -> Result<Self, zx::Status> {
151 if !capacity.is_power_of_two() {
153 return Err(zx::Status::INVALID_ARGS);
154 }
155
156 let mapping = MappedVmo::new(vmo)?;
158
159 let required_size = (capacity as usize)
161 .checked_mul(std::mem::size_of::<T>())
162 .and_then(|val| val.checked_add(HEADER_SIZE))
163 .ok_or(zx::Status::INVALID_ARGS)?;
164 if mapping.size < required_size {
165 return Err(zx::Status::BUFFER_TOO_SMALL);
166 }
167
168 let header = mapping.addr as *mut QueueHeader;
169 let slots = (mapping.addr + HEADER_SIZE) as *mut T;
170
171 Ok(Self {
172 mapping,
173 header,
174 slots,
175 capacity,
176 data_available: EventSignal::new(SIG_DATA_AVAILABLE_0, SIG_DATA_AVAILABLE_1),
177 space_available: EventSignal::new(SIG_SPACE_AVAILABLE_0, SIG_SPACE_AVAILABLE_1),
178 _phantom: std::marker::PhantomData,
179 })
180 }
181
182 fn vmo(&self) -> &zx::Vmo {
183 self.mapping.vmo()
184 }
185
186 fn capacity(&self) -> u32 {
187 self.capacity
188 }
189
190 fn addr(&self) -> usize {
191 self.mapping.addr()
192 }
193
194 fn vmo_size(&self) -> usize {
195 self.mapping.size()
196 }
197
198 fn payload_region_offset(&self) -> usize {
201 let raw_offset = HEADER_SIZE + self.capacity as usize * std::mem::size_of::<T>();
202 let page_size = zx::system_get_page_size() as usize;
203 (raw_offset + page_size - 1) & !(page_size - 1)
204 }
205
206 fn write_head_atomic(&self) -> &AtomicU64 {
207 unsafe {
212 let ptr = std::ptr::addr_of_mut!((*self.header).write_head);
213 AtomicU64::from_ptr(ptr)
214 }
215 }
216
217 fn read_head_atomic(&self) -> &AtomicU64 {
218 unsafe {
220 let ptr = std::ptr::addr_of_mut!((*self.header).read_head);
221 AtomicU64::from_ptr(ptr)
222 }
223 }
224
225 fn load_write_head(&self, ordering: Ordering) -> State {
226 State(self.write_head_atomic().load(ordering))
227 }
228
229 fn load_read_head(&self, ordering: Ordering) -> State {
230 State(self.read_head_atomic().load(ordering))
231 }
232
233 fn write_index(&self) -> u64 {
234 self.load_write_head(Ordering::Acquire).index()
235 }
236
237 fn read_index(&self) -> u64 {
238 self.load_read_head(Ordering::Acquire).index()
239 }
240
241 fn is_full_at(&self, write_idx: u64, read_idx: u64) -> bool {
242 (write_idx.wrapping_sub(read_idx) & State::INDEX_MASK) >= self.capacity as u64
243 }
244
245 fn is_full(&self) -> bool {
246 self.is_full_at(self.write_index(), self.read_index())
247 }
248
249 fn is_empty(&self) -> bool {
250 self.load_write_head(Ordering::Acquire).index()
251 == self.load_read_head(Ordering::Acquire).index()
252 }
253
254 fn get_slot_ptr(&self, index: u64) -> *mut T {
255 let slot_idx = ((index & State::INDEX_MASK) % self.capacity as u64) as isize;
256 unsafe { self.slots.offset(slot_idx) }
259 }
260}
261
262impl<T> SharedQueue<T> {
263 fn shutdown(&self) -> Result<(), zx::Status> {
265 self.mapping.vmo().signal(zx::Signals::empty(), SIG_SHUTDOWN)?;
266 Ok(())
267 }
268}
269
270struct SenderInner<T> {
272 inner: SharedQueue<T>,
273 allocator: RingAllocator,
274}
275impl<T: FromBytes + IntoBytes + KnownLayout + Copy> SenderInner<T> {
276 fn new(vmo: zx::Vmo, alignment: usize, capacity: u32) -> Result<Self, zx::Status> {
284 let inner = SharedQueue::new(vmo, capacity)?;
285 let payload_size = inner.vmo_size().saturating_sub(inner.payload_region_offset());
286 let allocator = RingAllocator::new(payload_size, inner.capacity() as usize, alignment);
287 Ok(Self { inner, allocator })
288 }
289
290 fn is_full(&self) -> bool {
291 self.inner.is_full()
292 }
293
294 fn capacity(&self) -> u32 {
295 self.inner.capacity()
296 }
297
298 fn index(&self) -> u64 {
299 self.inner.write_index()
300 }
301
302 fn vmo(&self) -> &zx::Vmo {
303 self.inner.vmo()
304 }
305
306 fn try_reserve_slot(
312 &mut self,
313 curr_write_head: State,
314 curr_read_head: &mut State,
315 ) -> Option<u64> {
316 let write_idx = curr_write_head.index();
317 loop {
318 if self.inner.is_full_at(write_idx, curr_read_head.index()) {
319 let next_read_head = curr_read_head.with_waiter();
321 match self.inner.read_head_atomic().compare_exchange_weak(
322 curr_read_head.0,
323 next_read_head.0,
324 Ordering::Relaxed,
326 Ordering::Acquire,
330 ) {
331 Ok(_) => return None,
332 Err(actual) => {
333 *curr_read_head = State(actual);
335 }
336 }
337 } else {
338 return Some(write_idx);
340 }
341 }
342 }
343
344 fn push_to_slot(&mut self, msg: T, mut curr_write_head: State) -> Result<u64, zx::Status> {
347 let write_idx = curr_write_head.index();
348
349 let slot_ptr = self.inner.get_slot_ptr(write_idx);
351 unsafe {
356 std::ptr::write(slot_ptr, msg);
357 }
358
359 loop {
361 let next_write_head = curr_write_head.clear_waiter_and_increment();
362 match self.inner.write_head_atomic().compare_exchange_weak(
363 curr_write_head.0,
364 next_write_head.0,
365 Ordering::Release,
368 Ordering::Relaxed,
372 ) {
373 Ok(prev_write_head) => {
374 if State(prev_write_head).has_waiter() {
376 let vmo = self.inner.mapping.vmo();
377 self.inner.data_available.signal(vmo)?;
378 }
379 return Ok(write_idx);
380 }
381 Err(actual) => curr_write_head = State(actual),
382 }
383 }
384 }
385
386 fn try_allocate_payload(
387 &mut self,
388 size: usize,
389 curr_read_head: &mut State,
390 ) -> Result<Option<AllocationToken>, zx::Status> {
391 if !self.allocator.is_within_capacity(size) {
392 return Err(zx::Status::NO_MEMORY);
393 }
394 loop {
395 let current_read_index = curr_read_head.index();
396 self.allocator.reclaim_consumed_slots(current_read_index);
397 match self.allocator.allocate(size) {
398 Some(token) => return Ok(Some(token)),
399 None => {
400 let next_read_head = curr_read_head.with_waiter();
402 match self.inner.read_head_atomic().compare_exchange_weak(
403 curr_read_head.0,
404 next_read_head.0,
405 Ordering::Relaxed,
407 Ordering::Acquire,
409 ) {
410 Ok(_) => return Ok(None),
411 Err(actual) => {
412 *curr_read_head = State(actual);
413 }
414 }
415 }
416 }
417 }
418 }
419}
420
421impl<T> SenderInner<T> {
422 fn shutdown(&self) -> Result<(), zx::Status> {
423 self.inner.shutdown()
424 }
425}
426
427impl<T> Drop for SenderInner<T> {
428 fn drop(&mut self) {
429 let _ = self.shutdown();
430 }
431}
432
433pub struct SyncSender<T>(SenderInner<T>);
435impl<T: FromBytes + IntoBytes + KnownLayout + Copy> SyncSender<T> {
436 pub fn new(vmo: zx::Vmo, alignment: usize, queue_capacity: u32) -> Result<Self, zx::Status> {
437 SenderInner::new(vmo, alignment, queue_capacity).map(Self)
438 }
439
440 pub fn capacity(&self) -> u32 {
441 self.0.capacity()
442 }
443
444 pub fn is_full(&self) -> bool {
445 self.0.is_full()
446 }
447
448 pub fn index(&self) -> u64 {
449 self.0.index()
450 }
451
452 pub fn vmo(&self) -> &zx::Vmo {
453 self.0.vmo()
454 }
455
456 pub fn shutdown(&self) -> Result<(), zx::Status> {
457 self.0.shutdown()
458 }
459
460 pub fn push(&mut self, msg: T) -> Result<u64, zx::Status> {
461 let curr_write_head = self.0.inner.load_write_head(Ordering::Relaxed);
464 let mut curr_read_head = self.0.inner.load_read_head(Ordering::Acquire);
467
468 loop {
469 match self.0.try_reserve_slot(curr_write_head, &mut curr_read_head) {
472 Some(_) => break,
473 None => {
474 let vmo = self.0.inner.mapping.vmo();
475 self.0.inner.space_available.wait(vmo, SIG_SHUTDOWN)?;
476 curr_read_head = self.0.inner.load_read_head(Ordering::Acquire);
477 }
478 }
479 }
480 self.0.push_to_slot(msg, curr_write_head)
481 }
482
483 pub fn reserve_payload(&mut self, size: usize) -> Result<PayloadBuffer<'_, T>, zx::Status> {
488 let mut curr_read_head = self.0.inner.load_read_head(Ordering::Acquire);
491
492 let token = loop {
493 match self.0.try_allocate_payload(size, &mut curr_read_head)? {
496 Some(token) => break token,
497 None => {
498 let vmo = self.0.inner.mapping.vmo();
499 self.0.inner.space_available.wait(vmo, SIG_SHUTDOWN)?;
500 curr_read_head = self.0.inner.load_read_head(Ordering::Acquire);
501 }
502 }
503 };
504
505 unsafe {
513 let abs_offset = self.0.inner.payload_region_offset() + token.offset() as usize;
514 let dest_ptr = (self.0.inner.addr() + abs_offset) as *mut u8;
515 let slice = std::ptr::slice_from_raw_parts_mut(dest_ptr, size);
516 Ok(PayloadBuffer {
517 sender: self,
518 token: Some(token),
519 slice: MutPtrByteSlice::new(slice),
520 })
521 }
522 }
523}
524
525pub struct AsyncSender<T>(SenderInner<T>);
527impl<T: FromBytes + IntoBytes + KnownLayout + Copy> AsyncSender<T> {
528 pub fn new(vmo: zx::Vmo, alignment: usize, queue_capacity: u32) -> Result<Self, zx::Status> {
529 SenderInner::new(vmo, alignment, queue_capacity).map(Self)
530 }
531
532 pub fn capacity(&self) -> u32 {
534 self.0.capacity()
535 }
536
537 pub fn is_full(&self) -> bool {
538 self.0.is_full()
539 }
540
541 pub fn vmo(&self) -> &zx::Vmo {
542 self.0.vmo()
543 }
544
545 pub async fn push(&mut self, msg: T) -> Result<u64, zx::Status> {
547 let curr_write_head = self.0.inner.load_write_head(Ordering::Relaxed);
550 let mut curr_read_head = self.0.inner.load_read_head(Ordering::Acquire);
553
554 loop {
555 match self.0.try_reserve_slot(curr_write_head, &mut curr_read_head) {
558 Some(_) => break,
559 None => {
560 let vmo = self.0.inner.mapping.vmo();
561 self.0.inner.space_available.wait_async(vmo, SIG_SHUTDOWN).await?;
564 curr_read_head = self.0.inner.load_read_head(Ordering::Acquire);
565 }
566 }
567 }
568
569 self.0.push_to_slot(msg, curr_write_head)
570 }
571
572 pub async fn reserve_payload(
576 &mut self,
577 size: usize,
578 ) -> Result<AsyncPayloadBuffer<'_, T>, zx::Status> {
579 let mut curr_read_head = self.0.inner.load_read_head(Ordering::Acquire);
582 let token = loop {
583 match self.0.try_allocate_payload(size, &mut curr_read_head)? {
586 Some(token) => break token,
587 None => {
588 let vmo = self.0.inner.mapping.vmo();
589 self.0.inner.space_available.wait_async(vmo, SIG_SHUTDOWN).await?;
590 curr_read_head = self.0.inner.load_read_head(Ordering::Acquire);
591 }
592 }
593 };
594
595 let slice = unsafe {
603 let abs_offset = self.0.inner.payload_region_offset() + token.offset() as usize;
604 let dest_ptr = (self.0.inner.addr() + abs_offset) as *mut u8;
605 MutPtrByteSlice::new(std::ptr::slice_from_raw_parts_mut(dest_ptr, size))
606 };
607 Ok(AsyncPayloadBuffer { sender: self, token: Some(token), slice })
608 }
609}
610
611pub struct PayloadBuffer<'a, T: FromBytes + IntoBytes + KnownLayout + Copy> {
614 sender: &'a mut SyncSender<T>,
617 token: Option<AllocationToken>,
618 slice: MutPtrByteSlice<'a>,
619}
620
621impl<'a, T: FromBytes + IntoBytes + KnownLayout + Copy> PayloadBuffer<'a, T> {
622 pub fn data(&mut self) -> &mut MutPtrByteSlice<'a> {
624 &mut self.slice
625 }
626
627 pub fn offset(&self) -> u32 {
629 self.token.as_ref().unwrap().offset()
630 }
631
632 pub fn commit(mut self, msg: T) -> Result<(), zx::Status> {
635 let token = self.token.take().unwrap();
636 match self.sender.push(msg) {
637 Ok(slot) => {
638 self.sender.0.allocator.commit_allocation_to_slot(slot, token);
639 Ok(())
640 }
641 Err(e) => {
642 self.sender.0.allocator.cancel_allocation(token);
643 Err(e)
644 }
645 }
646 }
647}
648
649impl<'a, T: FromBytes + IntoBytes + KnownLayout + Copy> Drop for PayloadBuffer<'a, T> {
650 fn drop(&mut self) {
651 if let Some(token) = self.token.take() {
652 self.sender.0.allocator.cancel_allocation(token);
653 }
654 }
655}
656
657pub struct AsyncPayloadBuffer<'a, T: FromBytes + IntoBytes + KnownLayout + Copy> {
660 sender: &'a mut AsyncSender<T>,
661 token: Option<AllocationToken>,
662 slice: MutPtrByteSlice<'a>,
663}
664
665impl<'a, T: FromBytes + IntoBytes + KnownLayout + Copy> AsyncPayloadBuffer<'a, T> {
666 pub fn data(&mut self) -> &mut MutPtrByteSlice<'a> {
668 &mut self.slice
669 }
670
671 pub fn offset(&self) -> u32 {
673 self.token.as_ref().unwrap().offset()
674 }
675
676 pub async fn commit(mut self, msg: T) -> Result<(), zx::Status> {
679 let token = self.token.take().unwrap();
680 match self.sender.push(msg).await {
681 Ok(slot) => {
682 self.sender.0.allocator.commit_allocation_to_slot(slot, token);
683 Ok(())
684 }
685 Err(e) => {
686 self.sender.0.allocator.cancel_allocation(token);
687 Err(e)
688 }
689 }
690 }
691}
692
693impl<'a, T: FromBytes + IntoBytes + KnownLayout + Copy> Drop for AsyncPayloadBuffer<'a, T> {
694 fn drop(&mut self) {
695 if let Some(token) = self.token.take() {
696 self.sender.0.allocator.cancel_allocation(token);
697 }
698 }
699}
700
701pub struct Receiver<T> {
703 inner: SharedQueue<T>,
704 cached_read_index: u64,
705}
706
707impl<T: FromBytes + IntoBytes + KnownLayout + Copy> Receiver<T> {
708 pub fn new(vmo: zx::Vmo, capacity: u32) -> Result<Self, zx::Status> {
709 Ok(Self { inner: SharedQueue::new(vmo, capacity)?, cached_read_index: 0 })
710 }
711
712 #[cfg(test)]
715 fn new_from_populated_vmo(vmo: zx::Vmo, capacity: u32) -> Result<Self, zx::Status> {
716 let inner = SharedQueue::new(vmo, capacity)?;
717 let cached_read_index = inner.read_index();
718 Ok(Self { inner, cached_read_index })
719 }
720
721 pub fn is_empty(&self) -> bool {
722 self.inner.is_empty()
723 }
724
725 pub fn capacity(&self) -> u32 {
726 self.inner.capacity()
727 }
728
729 pub fn index(&self) -> u64 {
730 self.inner.read_index()
731 }
732
733 pub fn vmo(&self) -> &zx::Vmo {
734 self.inner.vmo()
735 }
736
737 pub fn pop_reserve(&mut self) -> Result<T, zx::Status> {
739 let read_idx = self.cached_read_index;
740
741 let mut curr_write_head = self.inner.load_write_head(Ordering::Acquire);
744
745 loop {
746 if read_idx != curr_write_head.index() {
747 let slot_ptr = self.inner.get_slot_ptr(read_idx);
748 let msg = unsafe { std::ptr::read(slot_ptr) };
752 return Ok(msg);
753 }
754
755 let asleep_write_head = curr_write_head.with_waiter();
758 match self.inner.write_head_atomic().compare_exchange_weak(
759 curr_write_head.0,
760 asleep_write_head.0,
761 Ordering::Relaxed,
765 Ordering::Acquire,
769 ) {
770 Ok(_) => {
771 let vmo = self.inner.mapping.vmo();
774 match self.inner.data_available.wait(vmo, SIG_SHUTDOWN) {
775 Ok(()) => curr_write_head = self.inner.load_write_head(Ordering::Acquire),
776 Err(zx::Status::CANCELED) => {
777 curr_write_head = self.inner.load_write_head(Ordering::Acquire);
780 if read_idx == curr_write_head.index() {
781 return Err(zx::Status::CANCELED);
782 }
783 }
784 Err(e) => return Err(e),
785 }
786 }
787 Err(actual) => curr_write_head = State(actual),
788 }
789 }
790 }
791
792 pub fn pop_commit(&mut self) -> Result<(), zx::Status> {
794 let mut curr_read_head = State(self.cached_read_index);
799 loop {
800 let next_read_head = curr_read_head.clear_waiter_and_increment();
801 match self.inner.read_head_atomic().compare_exchange_weak(
802 curr_read_head.0,
803 next_read_head.0,
804 Ordering::Release,
807 Ordering::Relaxed,
811 ) {
812 Ok(prev_read_head) => {
813 self.cached_read_index = next_read_head.index();
814 if State(prev_read_head).has_waiter() {
816 let vmo = self.inner.mapping.vmo();
817 self.inner.space_available.signal(vmo)?;
818 }
819 return Ok(());
820 }
821 Err(actual) => curr_read_head = State(actual),
822 }
823 }
824 }
825
826 pub fn payload_slice(&self, vmo_offset: u32, len: u32) -> PtrByteSlice<'_> {
834 unsafe {
842 let offset = self.inner.payload_region_offset() + vmo_offset as usize;
843 assert!(offset + len as usize <= self.inner.vmo_size(), "Payload out of bounds");
844 let dest_ptr = (self.inner.addr() + offset) as *const u8;
845 let slice = std::ptr::slice_from_raw_parts(dest_ptr, len as usize);
846 PtrByteSlice::new(slice)
847 }
848 }
849}
850
851impl<T> Receiver<T> {
852 pub fn shutdown(&self) -> Result<(), zx::Status> {
853 self.inner.shutdown()
854 }
855}
856
857impl<T> Drop for Receiver<T> {
858 fn drop(&mut self) {
859 let _ = self.shutdown();
860 }
861}
862
863#[cfg(test)]
864mod tests {
865 use super::*;
866 use std::thread;
867 use std::time::Duration;
868
869 #[derive(FromBytes, IntoBytes, KnownLayout, Clone, Copy, Debug, PartialEq)]
870 #[repr(C)]
871 struct TestMessage {
872 val: u32,
873 }
874
875 #[fuchsia::test]
876 fn test_push_pop() {
877 let vmo = zx::Vmo::create(4096).expect("VMO creation failed");
878 let vmo_dup =
879 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("duplicate_handle failed");
880
881 let mut sender = SyncSender::<TestMessage>::new(vmo, 1, 4).expect("Sender new failed");
882 let mut receiver = Receiver::<TestMessage>::new(vmo_dup, 4).expect("Receiver new failed");
883
884 assert!(receiver.is_empty());
885 assert!(!sender.is_full());
886
887 let msg = TestMessage { val: 42 };
888 sender.push(msg).expect("push failed");
889
890 assert!(!receiver.is_empty());
891
892 let popped = receiver.pop_reserve().expect("pop_reserve failed");
893 assert_eq!(popped, msg);
894
895 receiver.pop_commit().expect("pop_commit failed");
896 assert!(receiver.is_empty());
897 }
898
899 #[fuchsia::test]
900 fn test_blocking_push_pop() {
901 let vmo = zx::Vmo::create(4096).expect("VMO creation failed");
902 let vmo_writer =
903 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("VMO duplicate_handle failed");
904
905 let mut receiver = Receiver::<TestMessage>::new(vmo, 2).expect("receiver creation failed");
906 let mut sender =
907 SyncSender::<TestMessage>::new(vmo_writer, 8, 2).expect("sender creation failed");
908
909 let handle = std::thread::spawn(move || {
910 let msg1 = TestMessage { val: 1 };
911 let msg2 = TestMessage { val: 2 };
912 let msg3 = TestMessage { val: 3 };
913
914 sender.push(msg1).expect("push failed");
915 sender.push(msg2).expect("push failed");
916 sender.push(msg3).expect("push failed");
919 });
920
921 thread::sleep(Duration::from_millis(100));
923
924 let r1 = receiver.pop_reserve().expect("pop_reserve failed");
925 assert_eq!(r1.val, 1);
926 receiver.pop_commit().expect("pop_commit failed");
928
929 let r2 = receiver.pop_reserve().expect("pop_reserve failed");
930 assert_eq!(r2.val, 2);
931 receiver.pop_commit().expect("pop_commit failed");
932
933 let r3 = receiver.pop_reserve().expect("pop_reserve failed");
934 assert_eq!(r3.val, 3);
935 receiver.pop_commit().expect("pop_commit failed");
936
937 handle.join().expect("writer thread panicked");
938 }
939
940 #[fuchsia::test]
941 fn test_index_wrap_around() {
942 let vmo = zx::Vmo::create(4096).expect("VMO creation failed");
943
944 let start_idx = State::INDEX_MASK - 1;
946 vmo.write(&start_idx.to_ne_bytes(), 0).expect("write failed");
948 vmo.write(&start_idx.to_ne_bytes(), 8).expect("write failed");
950
951 let vmo_dup =
952 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("duplicate_handle failed");
953
954 let mut sender = SyncSender::<TestMessage>::new(vmo, 8, 4).expect("Sender new failed");
955 let mut receiver = Receiver::<TestMessage>::new_from_populated_vmo(vmo_dup, 4)
956 .expect("Receiver new_from_populated_vmo failed");
957
958 assert_eq!(receiver.index(), start_idx);
960 assert_eq!(sender.index(), start_idx);
961
962 sender.push(TestMessage { val: 10 }).expect("push failed");
964 assert_eq!(sender.index(), State::INDEX_MASK);
965
966 sender.push(TestMessage { val: 20 }).expect("push failed");
967 assert_eq!(sender.index(), 0);
968
969 sender.push(TestMessage { val: 30 }).expect("push failed");
970 assert_eq!(sender.index(), 1);
971
972 assert_eq!(receiver.pop_reserve().expect("pop_reserve failed").val, 10);
974 receiver.pop_commit().expect("pop_commit failed");
975 assert_eq!(receiver.index(), State::INDEX_MASK);
976
977 assert_eq!(receiver.pop_reserve().expect("pop_reserve failed").val, 20);
978 receiver.pop_commit().expect("pop_commit failed");
979 assert_eq!(receiver.index(), 0);
980
981 assert_eq!(receiver.pop_reserve().expect("pop_reserve failed").val, 30);
982 receiver.pop_commit().expect("pop_commit failed");
983 assert_eq!(receiver.index(), 1);
984
985 assert!(receiver.is_empty());
986 }
987
988 #[fuchsia::test]
989 fn test_receiver_wakes_on_sender_drop() {
990 let vmo = zx::Vmo::create(4096).expect("VMO creation failed");
991 let vmo_dup =
992 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("VMO duplicate_handle failed");
993
994 let sender = SyncSender::<TestMessage>::new(vmo, 8, 2).expect("Sender creation failed");
995 let mut receiver =
996 Receiver::<TestMessage>::new(vmo_dup, 2).expect("Receiver creation failed");
997
998 let handle = std::thread::spawn(move || {
999 receiver.pop_reserve()
1001 });
1002
1003 thread::sleep(Duration::from_millis(100));
1005
1006 drop(sender);
1008
1009 let result = handle.join().expect("thread panicked");
1010 assert_eq!(result, Err(zx::Status::CANCELED));
1011 }
1012
1013 #[fuchsia::test]
1014 fn test_sender_wakes_on_receiver_drop() {
1015 let vmo = zx::Vmo::create(4096).expect("VMO creation failed");
1016 let vmo_dup =
1017 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("VMO duplicate_handle failed");
1018
1019 let mut sender = SyncSender::<TestMessage>::new(vmo, 8, 2).expect("Sender creation failed");
1020 let receiver = Receiver::<TestMessage>::new(vmo_dup, 2).expect("Receiver creation failed");
1021
1022 sender.push(TestMessage { val: 1 }).expect("push failed");
1024 sender.push(TestMessage { val: 2 }).expect("push failed");
1025
1026 let handle = std::thread::spawn(move || {
1027 sender.push(TestMessage { val: 3 })
1029 });
1030
1031 thread::sleep(Duration::from_millis(100));
1033
1034 drop(receiver);
1036
1037 let result = handle.join().expect("thread panicked");
1038 assert_eq!(result, Err(zx::Status::CANCELED));
1039 }
1040
1041 #[derive(FromBytes, IntoBytes, KnownLayout, Clone, Copy, Debug, PartialEq)]
1043 #[repr(C)]
1044 struct WireTestCommand {
1045 opcode: u32,
1046 vmo_offset: u32,
1047 len: u32, _pad: u32,
1049 val: u64, }
1051
1052 #[derive(Debug, PartialEq)]
1053 enum TestCommand {
1054 WithPayload { vmo_offset: u32, len: u32 },
1055 NoPayload { val: u64 },
1056 }
1057
1058 impl TestCommand {
1059 fn to_wire(&self) -> WireTestCommand {
1060 match self {
1061 TestCommand::WithPayload { vmo_offset, len } => WireTestCommand {
1062 opcode: 0,
1063 vmo_offset: *vmo_offset,
1064 len: *len,
1065 _pad: 0,
1066 val: 0,
1067 },
1068 TestCommand::NoPayload { val } => {
1069 WireTestCommand { opcode: 1, vmo_offset: 0, len: 0, _pad: 0, val: *val }
1070 }
1071 }
1072 }
1073
1074 fn from_wire(wire: WireTestCommand) -> Self {
1075 match wire.opcode {
1076 0 => TestCommand::WithPayload { vmo_offset: wire.vmo_offset, len: wire.len },
1077 _ => TestCommand::NoPayload { val: wire.val },
1078 }
1079 }
1080 }
1081
1082 #[fuchsia::test]
1083 fn test_payload_drop_releases_allocation() {
1084 let page_size = zx::system_get_page_size() as u64;
1085 let vmo = zx::Vmo::create(page_size * 2).expect("VMO creation failed");
1086
1087 let mut sender =
1088 SyncSender::<WireTestCommand>::new(vmo, 8, 4).expect("Sender creation failed");
1089
1090 let buffer = sender.reserve_payload(10).expect("reserve failed");
1091 assert_eq!(buffer.offset(), 0);
1092
1093 drop(buffer);
1095
1096 let buffer2 = sender.reserve_payload(10).expect("reserve failed");
1098 assert_eq!(buffer2.offset(), 0);
1099 }
1100
1101 #[fuchsia::test]
1102 fn test_payload_buffer_drops_uncommitted_allocations() {
1103 let page_size = zx::system_get_page_size() as u64;
1104 let vmo = zx::Vmo::create(page_size * 2).expect("VMO creation failed");
1105
1106 let mut sender =
1107 SyncSender::<WireTestCommand>::new(vmo, 8, 4).expect("Sender creation failed");
1108
1109 let _ = (|| -> Result<(), ()> {
1112 let _buffer = sender.reserve_payload(10).expect("reserve failed");
1113
1114 Err(())
1117 })();
1118
1119 let buffer_after_bail = sender.reserve_payload(10).expect("reserve failed");
1122 assert_eq!(buffer_after_bail.offset(), 0);
1123 }
1124
1125 #[fuchsia::test]
1126 fn test_with_payload_commands() {
1127 let page_size = zx::system_get_page_size() as u64;
1128 let vmo = zx::Vmo::create(page_size * 2).expect("VMO creation failed");
1129 let vmo_dup =
1130 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("VMO duplicate_handle failed");
1131
1132 let mut sender =
1133 SyncSender::<WireTestCommand>::new(vmo, 8, 4).expect("Sender creation failed");
1134 let mut receiver =
1135 Receiver::<WireTestCommand>::new(vmo_dup, 4).expect("Receiver creation failed");
1136
1137 let mut buffer = sender.reserve_payload(10).expect("reserve failed");
1138 buffer.data().fill(0xAA);
1139 let wire_msg = TestCommand::WithPayload { vmo_offset: buffer.offset(), len: 10 }.to_wire();
1140 buffer.commit(wire_msg).expect("commit failed");
1141
1142 let standalone = TestCommand::NoPayload { val: 456 };
1143 sender.push(standalone.to_wire()).expect("push failed");
1144
1145 let msg1 = receiver.pop_reserve().expect("pop_reserve failed");
1146 let app_msg1 = TestCommand::from_wire(msg1);
1147 if let TestCommand::WithPayload { vmo_offset, len } = app_msg1 {
1148 assert_eq!(len, 10);
1149 let read_data = receiver.payload_slice(vmo_offset, len);
1150 assert_eq!(read_data.to_vec(), vec![0xAA; 10]);
1151 } else {
1152 panic!("Expected TestCommand::WithPayload");
1153 }
1154 receiver.pop_commit().expect("pop_commit failed");
1155
1156 let msg2 = receiver.pop_reserve().expect("pop_reserve failed");
1157 let app_msg2 = TestCommand::from_wire(msg2);
1158 assert_eq!(app_msg2, TestCommand::NoPayload { val: 456 });
1159 receiver.pop_commit().expect("pop_commit failed");
1160 }
1161
1162 #[fuchsia::test]
1163 fn test_pop_handles_canceled_race_condition() {
1164 for _ in 0..10000 {
1166 let vmo = zx::Vmo::create(4096).unwrap();
1167 let vmo_dup = vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap();
1168 let mut sender = SyncSender::<u32>::new(vmo, 4, 1).unwrap();
1169 let mut receiver = Receiver::<u32>::new(vmo_dup, 1).unwrap();
1170
1171 let handle = std::thread::spawn(move || {
1172 loop {
1174 let write_head = sender.0.inner.load_write_head(Ordering::Acquire);
1175 if write_head.has_waiter() {
1176 break;
1177 }
1178 std::thread::yield_now();
1179 }
1180
1181 sender.push(42).expect("push failed");
1183
1184 drop(sender);
1188 });
1189
1190 let val = receiver.pop_reserve().expect("pop_reserve failed on race condition");
1193 assert_eq!(val, 42);
1194 receiver.pop_commit().expect("pop_commit failed");
1195
1196 assert_eq!(receiver.pop_reserve().unwrap_err(), zx::Status::CANCELED);
1198
1199 handle.join().unwrap();
1200 }
1201 }
1202
1203 #[fuchsia::test]
1204 async fn test_async_push_yields_when_full() {
1205 let page_size = zx::system_get_page_size() as u64;
1206 let vmo = zx::Vmo::create(page_size * 2).expect("failed to create VMO");
1207 let vmo_dup =
1208 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("failed to duplicate VMO handle");
1209
1210 let queue_capacity = 4;
1211 let mut sender = AsyncSender::<TestMessage>::new(vmo, 4, queue_capacity)
1212 .expect("failed to create AsyncSender");
1213 let mut receiver = Receiver::<TestMessage>::new(vmo_dup, queue_capacity)
1214 .expect("failed to create Receiver");
1215
1216 for i in 0..queue_capacity {
1217 sender.push(TestMessage { val: i }).await.expect("failed to push message");
1218 }
1219
1220 let push_task = async {
1221 sender
1222 .push(TestMessage { val: 42 })
1223 .await
1224 .expect("background push task failed after yielding");
1225 };
1226 let pop_thread = std::thread::spawn(move || {
1227 thread::sleep(Duration::from_millis(5));
1228 let msg = receiver.pop_reserve().expect("failed to pop_reserve message");
1229 assert_eq!(msg.val, 0); receiver.pop_commit().expect("failed to pop_commit message");
1231 receiver
1232 });
1233
1234 push_task.await;
1235 let mut receiver = pop_thread.join().unwrap();
1236
1237 for expected in [1, 2, 3, 42] {
1238 let msg = receiver.pop_reserve().expect("failed to pop_reserve message");
1239 assert_eq!(msg.val, expected);
1240 receiver.pop_commit().expect("failed to pop_commit message");
1241 }
1242 }
1243
1244 #[fuchsia::test]
1245 async fn test_reserve_payload_async_yields() {
1246 let page_size = zx::system_get_page_size() as u64;
1247 let vmo = zx::Vmo::create(page_size * 2).expect("failed to create VMO");
1248 let vmo_dup =
1249 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("failed to duplicate VMO handle");
1250
1251 let mut sender =
1252 AsyncSender::<TestMessage>::new(vmo, 4, 4).expect("failed to create AsyncSender");
1253 let mut receiver =
1254 Receiver::<TestMessage>::new(vmo_dup, 4).expect("failed to create Receiver");
1255
1256 let block1 = sender
1260 .reserve_payload(page_size as usize)
1261 .await
1262 .expect("failed to reserve payload capacity");
1263 block1.commit(TestMessage { val: 1 }).await.expect("failed to commit message block");
1264
1265 let reserve_task = async {
1267 let buffer = sender
1268 .reserve_payload(4)
1269 .await
1270 .expect("background reserve payload task failed after yielding");
1271 buffer.commit(TestMessage { val: 2 }).await.expect("failed to commit message block");
1272 };
1273 let pop_thread = std::thread::spawn(move || {
1274 thread::sleep(Duration::from_millis(5));
1276 let msg = receiver.pop_reserve().expect("failed to pop_reserve message");
1277 assert_eq!(msg.val, 1);
1278 receiver.pop_commit().expect("failed to pop_commit message");
1279 receiver
1280 });
1281
1282 reserve_task.await;
1283 let mut receiver = pop_thread.join().unwrap();
1284
1285 let msg = receiver.pop_reserve().expect("failed to pop_reserve message");
1287 assert_eq!(msg.val, 2);
1288 receiver.pop_commit().expect("failed to pop_commit message");
1289 }
1290
1291 #[fuchsia::test]
1292 async fn test_async_commit_yields_when_full() {
1293 let page_size = zx::system_get_page_size() as u64;
1294 let vmo = zx::Vmo::create(page_size * 2).expect("failed to create VMO");
1295 let vmo_dup =
1296 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("failed to duplicate VMO handle");
1297
1298 let queue_capacity = 4;
1299 let mut sender = AsyncSender::<WireTestCommand>::new(vmo, 4, queue_capacity)
1300 .expect("failed to create AsyncSender");
1301 let mut receiver = Receiver::<WireTestCommand>::new(vmo_dup, queue_capacity)
1302 .expect("failed to create Receiver");
1303
1304 for i in 0..queue_capacity {
1306 let standalone = TestCommand::NoPayload { val: i as u64 };
1307 sender.push(standalone.to_wire()).await.expect("failed to push message");
1308 }
1309
1310 let block = sender.reserve_payload(4).await.expect("failed to reserve payload capacity");
1312
1313 let commit_task = async {
1314 let msg = TestCommand::WithPayload { vmo_offset: block.offset(), len: 4 };
1315 block
1316 .commit(msg.to_wire())
1317 .await
1318 .expect("background commit task failed after yielding");
1319 };
1320
1321 let pop_thread = std::thread::spawn(move || {
1322 thread::sleep(Duration::from_millis(5));
1324
1325 for expected in 0..4 {
1327 let msg = receiver.pop_reserve().expect("failed to pop_reserve message");
1328 let app_msg = TestCommand::from_wire(msg);
1329 assert!(matches!(app_msg, TestCommand::NoPayload { val } if val == expected));
1330 receiver.pop_commit().expect("failed to pop_commit message");
1331 }
1332
1333 let msg2 = receiver.pop_reserve().expect("failed to pop payload message");
1335 let app_msg2 = TestCommand::from_wire(msg2);
1336 assert!(matches!(app_msg2, TestCommand::WithPayload { .. }));
1337 receiver.pop_commit().expect("failed to pop_commit message");
1338 });
1339
1340 commit_task.await;
1341 pop_thread.join().unwrap();
1342 }
1343
1344 #[fuchsia::test]
1345 fn test_push_when_receiver_drops() {
1346 let vmo = zx::Vmo::create(4096).expect("VMO creation failed");
1347 let vmo_dup =
1348 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("VMO duplicate_handle failed");
1349
1350 let mut sender = SyncSender::<TestMessage>::new(vmo, 8, 4).expect("Sender creation failed");
1351 let receiver = Receiver::<TestMessage>::new(vmo_dup, 4).expect("Receiver creation failed");
1352
1353 drop(receiver);
1355
1356 sender.push(TestMessage { val: 1 }).expect("push failed");
1359 sender.push(TestMessage { val: 2 }).expect("push failed");
1360 sender.push(TestMessage { val: 3 }).expect("push failed");
1361 sender.push(TestMessage { val: 4 }).expect("push failed");
1362
1363 assert_eq!(sender.push(TestMessage { val: 5 }), Err(zx::Status::CANCELED));
1366 }
1367
1368 #[fuchsia::test]
1369 async fn test_async_push_when_receiver_drops() {
1370 let vmo = zx::Vmo::create(4096).expect("VMO creation failed");
1371 let vmo_dup =
1372 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("VMO duplicate_handle failed");
1373
1374 let mut sender =
1375 AsyncSender::<TestMessage>::new(vmo, 8, 4).expect("Sender creation failed");
1376 let receiver = Receiver::<TestMessage>::new(vmo_dup, 4).expect("Receiver creation failed");
1377
1378 drop(receiver);
1380
1381 sender.push(TestMessage { val: 1 }).await.expect("push failed");
1384 sender.push(TestMessage { val: 2 }).await.expect("push failed");
1385 sender.push(TestMessage { val: 3 }).await.expect("push failed");
1386 sender.push(TestMessage { val: 4 }).await.expect("push failed");
1387
1388 assert_eq!(sender.push(TestMessage { val: 5 }).await.unwrap_err(), zx::Status::CANCELED);
1391 }
1392
1393 #[fuchsia::test]
1394 fn test_reserve_payload_sync_exceeds_capacity() {
1395 let page_size = zx::system_get_page_size() as u64;
1396 let vmo = zx::Vmo::create(page_size * 2).expect("failed to create VMO");
1397 let vmo_dup =
1398 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("failed to duplicate VMO handle");
1399
1400 let mut sender =
1401 SyncSender::<TestMessage>::new(vmo, 4, 4).expect("failed to create Sender");
1402 let _receiver =
1403 Receiver::<TestMessage>::new(vmo_dup, 4).expect("failed to create Receiver");
1404
1405 let result = sender.reserve_payload((page_size + 10) as usize);
1408 assert_eq!(result.err(), Some(zx::Status::NO_MEMORY));
1409 }
1410
1411 #[fuchsia::test]
1412 async fn test_reserve_payload_async_exceeds_capacity() {
1413 let page_size = zx::system_get_page_size() as u64;
1414 let vmo = zx::Vmo::create(page_size * 2).expect("failed to create VMO");
1415 let vmo_dup =
1416 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("failed to duplicate VMO handle");
1417
1418 let mut sender =
1419 AsyncSender::<TestMessage>::new(vmo, 4, 4).expect("failed to create AsyncSender");
1420 let _receiver =
1421 Receiver::<TestMessage>::new(vmo_dup, 4).expect("failed to create Receiver");
1422
1423 let result = sender.reserve_payload((page_size + 10) as usize).await;
1426 assert_eq!(result.err(), Some(zx::Status::NO_MEMORY));
1427 }
1428}