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