1#![no_std]
8
9use core::ptr::NonNull;
10use pin_init::PinInit;
11use zx_status::Status;
12
13#[derive(Copy, Clone, Debug, PartialEq, Eq)]
15pub struct ReadContext {
16 pub c: u8,
18 pub transitioned_from_full: bool,
20}
21
22#[ksync::guarded]
24#[repr(C)]
25pub struct Cbuf {
26 #[guarded_by(lock)]
27 head: u32,
28
29 #[guarded_by(lock)]
30 tail: u32,
31
32 #[guarded_by(lock)]
33 len_pow2: u32,
34
35 #[guarded_by(lock)]
36 buf: Option<NonNull<u8>>,
37
38 #[pin]
39 event: ksync::KEvent,
40
41 #[mutex]
42 lock: ksync::KMutex<ksync::RawSpinlock>,
43}
44
45unsafe impl Send for Cbuf {}
48
49unsafe impl Sync for Cbuf {}
52
53impl Cbuf {
54 pub fn init() -> impl PinInit<Self, core::convert::Infallible> {
56 pin_init::pin_init!(Self {
57 head: 0.into(),
58 tail: 0.into(),
59 len_pow2: 0.into(),
60 buf: None.into(),
61 event <- ksync::KEvent::init(false),
62 lock <- ksync::KMutex::init(),
63 })
64 }
65
66 pub unsafe fn initialize(&self, len: usize, buf: *mut u8) -> Result<(), Status> {
73 if len == 0 || !len.is_power_of_two() {
74 return Err(Status::INVALID_ARGS);
75 }
76 let len_pow2 = len.trailing_zeros();
77
78 ksync::lock!(let mut guard = self.lock_lock());
79 let fields = guard.as_mut().fields_mut();
80 *fields.len_pow2 = len_pow2;
81 *fields.buf = NonNull::new(buf);
82 *fields.head = 0;
83 *fields.tail = 0;
84
85 Ok(())
86 }
87
88 pub fn full(&self) -> bool {
90 ksync::lock!(let guard = self.lock_lock());
91 let fields = guard.fields();
92 is_full(*fields.head, *fields.tail, *fields.len_pow2)
93 }
94
95 pub fn write_char(&self, c: u8) -> usize {
99 let wrote = {
100 ksync::lock!(let mut guard = self.lock_lock());
101 let fields = guard.fields_mut();
102 if is_full(*fields.head, *fields.tail, *fields.len_pow2) {
103 0
104 } else {
105 if let Some(buf) = fields.buf {
106 unsafe {
108 buf.as_ptr().add(*fields.head as usize).write(c);
109 }
110 inc_pointer(fields.head, 1, *fields.len_pow2);
111 1
112 } else {
113 0
114 }
115 }
116 };
117
118 if wrote > 0 {
119 self.event.signal();
120 }
121 wrote
122 }
123
124 pub fn read_char_with_context(&self, block: bool) -> Result<ReadContext, Status> {
129 loop {
130 {
131 ksync::lock!(let mut guard = self.lock_lock());
132 let fields = guard.fields_mut();
133 if *fields.tail != *fields.head {
134 if let Some(buf) = fields.buf {
135 let c = unsafe { buf.as_ptr().add(*fields.tail as usize).read() };
137 let transitioned_from_full =
138 is_full(*fields.head, *fields.tail, *fields.len_pow2);
139
140 inc_pointer(fields.tail, 1, *fields.len_pow2);
141 if *fields.tail == *fields.head {
142 self.event.unsignal();
143 }
144 return Ok(ReadContext { c, transitioned_from_full });
145 }
146 }
147
148 self.event.unsignal();
152 }
153
154 if !block {
155 return Err(Status::SHOULD_WAIT);
156 }
157
158 self.event.wait()?;
159 }
160 }
161
162 pub fn read_char(&self, block: bool) -> Result<u8, Status> {
167 self.read_char_with_context(block).map(|ctx| ctx.c)
168 }
169}
170
171#[inline]
172fn inc_pointer(ptr: &mut u32, inc: u32, len_pow2: u32) {
173 let mask = (1u32 << len_pow2) - 1;
174 *ptr = ptr.wrapping_add(inc) & mask;
175}
176
177#[inline]
178fn is_full(head: u32, tail: u32, len_pow2: u32) -> bool {
179 if len_pow2 == 0 {
180 return true;
181 }
182 let mask = (1u32 << len_pow2) - 1;
183 let consumed = head.wrapping_sub(tail) & mask;
184 let avail = (1u32 << len_pow2) - consumed - 1;
185 avail == 0
186}