sel4_shared_ring_buffer_block_io/
lib.rs

1//
2// Copyright 2023, Colias Group, LLC
3//
4// SPDX-License-Identifier: BSD-2-Clause
5//
6
7#![no_std]
8#![allow(clippy::useless_conversion)]
9
10extern crate alloc;
11
12use alloc::rc::Rc;
13use core::cell::RefCell;
14use core::future::Future;
15use core::marker::PhantomData;
16use core::pin::Pin;
17use core::task::{Context, Poll};
18
19use async_unsync::semaphore::Semaphore;
20
21use sel4_abstract_allocator::AbstractAllocator;
22use sel4_async_block_io::{access::Access, BlockIO, BlockIOLayout, BlockSize, Operation};
23use sel4_shared_memory::SharedMemoryRef;
24use sel4_shared_ring_buffer::{roles::Provide, RingBuffers};
25use sel4_shared_ring_buffer_block_io_types::BlockIORequest;
26
27mod errors;
28mod owned;
29
30pub use errors::{Error, ErrorOrUserError, IOError, PeerMisbehaviorError, UserError};
31pub use owned::{IssueRequestBuf, OwnedSharedRingBufferBlockIO, PollRequestBuf};
32
33pub struct SharedRingBufferBlockIO<N, P, A: AbstractAllocator, F> {
34    shared: Rc<RefCell<Inner<N, P, A, F>>>,
35}
36
37struct Inner<N, P, A: AbstractAllocator, F> {
38    owned: OwnedSharedRingBufferBlockIO<Rc<Semaphore>, A, F>,
39    block_size: N,
40    num_blocks: u64,
41    _phantom: PhantomData<P>,
42}
43
44impl<N, P: Access, A: AbstractAllocator, F: FnMut()> SharedRingBufferBlockIO<N, P, A, F> {
45    pub fn new(
46        block_size: N,
47        num_blocks: u64,
48        dma_region: SharedMemoryRef<'static, [u8]>,
49        bounce_buffer_allocator: A,
50        ring_buffers: RingBuffers<'static, Provide, F, BlockIORequest>,
51    ) -> Self {
52        Self {
53            shared: Rc::new(RefCell::new(Inner {
54                owned: OwnedSharedRingBufferBlockIO::new(
55                    dma_region,
56                    bounce_buffer_allocator,
57                    ring_buffers,
58                ),
59                block_size,
60                num_blocks,
61                _phantom: PhantomData,
62            })),
63        }
64    }
65
66    pub fn poll(&self) -> Result<bool, Error> {
67        self.shared
68            .borrow_mut()
69            .owned
70            .poll()
71            .map_err(ErrorOrUserError::unwrap_error)
72    }
73
74    async fn request<'a>(
75        &'a self,
76        start_block_idx: u64,
77        operation: Operation<'a, P>,
78    ) -> Result<(), Error> {
79        let request_index = {
80            let sem = self.shared.borrow().owned.slot_set_semaphore().clone();
81            let mut reservation = sem.reserve(1).await.unwrap();
82            self.shared
83                .borrow_mut()
84                .owned
85                .issue_request(
86                    &mut reservation,
87                    start_block_idx,
88                    &mut IssueRequestBuf::new(&operation),
89                )
90                .map_err(ErrorOrUserError::unwrap_error)?
91        };
92        RequestFuture {
93            io: self,
94            operation,
95            request_index,
96            poll_returned_ready: false,
97        }
98        .await
99    }
100}
101
102impl<N, P, A: AbstractAllocator, F> Clone for SharedRingBufferBlockIO<N, P, A, F> {
103    fn clone(&self) -> Self {
104        Self {
105            shared: self.shared.clone(),
106        }
107    }
108}
109
110impl<N: BlockSize + Copy, P: Access, A: AbstractAllocator, F: FnMut()> BlockIOLayout
111    for SharedRingBufferBlockIO<N, P, A, F>
112{
113    type Error = Error;
114
115    type BlockSize = N;
116
117    fn block_size(&self) -> Self::BlockSize {
118        self.shared.borrow().block_size
119    }
120
121    fn num_blocks(&self) -> u64 {
122        self.shared.borrow().num_blocks
123    }
124}
125
126impl<N: BlockSize + Copy, P: Access, A: AbstractAllocator, F: FnMut()> BlockIO<P>
127    for SharedRingBufferBlockIO<N, P, A, F>
128{
129    async fn read_or_write_blocks(
130        &self,
131        start_block_idx: u64,
132        operation: Operation<'_, P>,
133    ) -> Result<(), Self::Error> {
134        self.request(start_block_idx, operation).await
135    }
136}
137
138pub struct RequestFuture<'a, N, P: Access, A: AbstractAllocator, F: FnMut()> {
139    io: &'a SharedRingBufferBlockIO<N, P, A, F>,
140    operation: Operation<'a, P>,
141    request_index: usize,
142    poll_returned_ready: bool,
143}
144
145impl<'a, N, P: Access, A: AbstractAllocator, F: FnMut()> RequestFuture<'a, N, P, A, F> {
146    fn poll_inner<'b>(&'b mut self, cx: &Context<'_>) -> Poll<Result<(), Error>>
147    where
148        'a: 'b,
149    {
150        assert!(!self.poll_returned_ready);
151        let ret = match self
152            .io
153            .shared
154            .borrow_mut()
155            .owned
156            .poll_request(
157                self.request_index,
158                &mut PollRequestBuf::new(&mut self.operation),
159                Some(cx.waker().clone()),
160            )
161            .map_err(ErrorOrUserError::unwrap_error)
162        {
163            Ok(val) => val.map_err(Error::from),
164            Err(err) => Poll::Ready(Err(err)),
165        };
166        if ret.is_ready() {
167            self.poll_returned_ready = true;
168        }
169        ret
170    }
171}
172
173impl<N, P: Access, A: AbstractAllocator, F: FnMut()> Future for RequestFuture<'_, N, P, A, F> {
174    type Output = Result<(), Error>;
175
176    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
177        self.poll_inner(cx)
178    }
179}
180
181impl<N, P: Access, A: AbstractAllocator, F: FnMut()> Drop for RequestFuture<'_, N, P, A, F> {
182    fn drop(&mut self) {
183        if !self.poll_returned_ready {
184            self.io
185                .shared
186                .borrow_mut()
187                .owned
188                .cancel_request(self.request_index)
189                .unwrap();
190        }
191    }
192}