Skip to content

Commit 0527b8e

Browse files
authored
Refactor: blk (#16)
* refactor: 更新 rdif-block 接口,重构读写块方法,改进错误处理 * feat: 添加请求结构体和请求类型枚举以支持读写操作 * feat: 更新 RamDisk 结构体,重命名字段并添加队列 ID 支持,改进请求处理逻辑 * feat: 更新 rdif-block 和 rdrive 的版本号,添加 Block 类的实现以支持驱动注册 * feat: 更新 rdif_base 导入,添加 AsAny 以支持类型转换
1 parent e229aae commit 0527b8e

7 files changed

Lines changed: 1103 additions & 26 deletions

File tree

interface/rdif-block/Cargo.toml

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
[package]
2-
name = "rdif-block"
3-
version = "0.5.0"
4-
edition.workspace = true
52
authors = ["周睿 <zrufo747@outlook.com>"]
6-
repository.workspace = true
7-
license = "MIT"
3+
categories = ["embedded", "no-std"]
84
description = "Driver Interface block definition."
5+
edition.workspace = true
96
keywords = ["os", "driver"]
10-
categories = ["embedded", "no-std"]
7+
license = "MIT"
8+
name = "rdif-block"
9+
repository.workspace = true
10+
version = "0.6.0"
1111

1212
[dependencies]
13-
rdif-base = { workspace = true }
1413
cfg-if = "1.0"
14+
dma-api = {path = "/home/zhourui/opensource/dma-api", features = ["alloc"]}
15+
futures = {version = "0.3", features = ["alloc"], default-features = false}
16+
rdif-base = {workspace = true}
17+
thiserror = {version = "2", default-features = false}
18+
spin_on = "0.1"
19+
20+
[dev-dependencies]
21+
tokio = {version = "1", features = ["full"]}
Lines changed: 347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,347 @@
1+
use dma_api::Osal;
2+
use rdif_block::*;
3+
use std::boxed::Box;
4+
use std::ptr::NonNull;
5+
use std::sync::{Arc, Mutex};
6+
use std::time::Duration;
7+
use std::vec::Vec;
8+
9+
struct ExampleOsal;
10+
11+
impl Osal for ExampleOsal {
12+
fn map(&self, addr: NonNull<u8>, _size: usize, _direction: dma_api::Direction) -> u64 {
13+
addr.as_ptr() as u64
14+
}
15+
16+
fn unmap(&self, _addr: NonNull<u8>, _size: usize) {}
17+
}
18+
19+
static EX_OSAL: ExampleOsal = ExampleOsal;
20+
21+
/// A simple in-memory ramdisk that implements `rdif_block::Interface`.
22+
///
23+
/// Internally it keeps a vector of blocks. Each block is initialized
24+
/// so every byte equals the block id as u8 (truncated).
25+
/// It spawns a worker thread that processes requests pushed by the
26+
/// ReadQueue implementation and sets an event bit to signal completion.
27+
struct RamDisk {
28+
block_size: usize,
29+
num_blocks: usize,
30+
// storage: Vec<[u8]> is not possible, use single Vec<u8>
31+
_storage: Arc<Vec<u8>>,
32+
33+
// Shared request/response queue between interface and worker
34+
inner: Arc<Mutex<RamInner>>,
35+
}
36+
37+
struct RamInner {
38+
// map request id -> (queue_id, block_id, buffer pointer/size)
39+
// we keep a simple Vec of pending requests
40+
pending: Vec<(usize, RequestId, usize, usize, usize)>,
41+
// pending write requests: (queue_id, req_id, block_id, src_ptr, size)
42+
pending_writes: Vec<(usize, RequestId, usize, usize, usize)>,
43+
// set when there is new data to be processed
44+
irq_rx: IdList,
45+
irq_enabled: bool,
46+
next_req_id: usize,
47+
// next queue id to hand out from create_queue()
48+
next_queue_id: usize,
49+
completed: Vec<RequestId>,
50+
completed_writes: Vec<RequestId>,
51+
}
52+
53+
impl RamDisk {
54+
pub fn new(block_size: usize, num_blocks: usize) -> Self {
55+
// fill storage so that each block's bytes == block_id as u8
56+
let mut storage = Vec::with_capacity(block_size * num_blocks);
57+
for i in 0..num_blocks {
58+
let v = i as u8;
59+
storage.extend(std::iter::repeat_n(v, block_size));
60+
}
61+
62+
let storage = Arc::new(storage);
63+
64+
let inner = Arc::new(Mutex::new(RamInner {
65+
pending: Vec::new(),
66+
pending_writes: Vec::new(),
67+
irq_rx: IdList::none(),
68+
irq_enabled: true,
69+
next_req_id: 1,
70+
next_queue_id: 0,
71+
completed: Vec::new(),
72+
completed_writes: Vec::new(),
73+
}));
74+
75+
// spawn worker thread to process requests
76+
let storage_cloned = storage.clone();
77+
let inner_cloned = inner.clone();
78+
std::thread::spawn(move || {
79+
loop {
80+
// take a snapshot of pending requests
81+
let (reqs, writes) = {
82+
let mut guard = inner_cloned.lock().unwrap();
83+
if guard.pending.is_empty() && guard.pending_writes.is_empty() {
84+
// no work - sleep briefly
85+
drop(guard);
86+
std::thread::sleep(Duration::from_millis(5));
87+
continue;
88+
}
89+
90+
// take requests and release lock immediately
91+
let reqs = core::mem::take(&mut guard.pending);
92+
let writes = core::mem::take(&mut guard.pending_writes);
93+
(reqs, writes)
94+
// lock is automatically released here
95+
};
96+
97+
// process all pending read requests without holding the lock
98+
let mut completed_reads = Vec::new();
99+
// reqs contain (queue_id, req_id, block_id, buf_ptr, size)
100+
for (_q_id, req_id, block_id, buf_ptr_usize, sz) in &reqs {
101+
// copy block data into user buffer
102+
let start = block_id * sz;
103+
let buf_ptr = *buf_ptr_usize as *mut u8;
104+
unsafe {
105+
core::ptr::copy_nonoverlapping(
106+
storage_cloned.as_ptr().add(start),
107+
buf_ptr,
108+
*sz,
109+
);
110+
}
111+
completed_reads.push(*req_id);
112+
// mark that this queue has an event
113+
// we'll insert queue id into irq_rx when updating the guard
114+
}
115+
116+
// process pending write requests without holding the lock
117+
let mut completed_writes = Vec::new();
118+
for (_q_id, req_id, block_id, src_ptr_usize, sz) in &writes {
119+
let start = block_id * sz;
120+
let src_ptr = *src_ptr_usize as *const u8;
121+
unsafe {
122+
core::ptr::copy_nonoverlapping(
123+
src_ptr,
124+
storage_cloned.as_ptr().add(start) as *mut u8,
125+
*sz,
126+
);
127+
}
128+
completed_writes.push(*req_id);
129+
// same as reads, queue id will be inserted into irq bits below
130+
}
131+
132+
// acquire lock again only to update completion status
133+
{
134+
let mut guard = inner_cloned.lock().unwrap();
135+
guard.completed.extend(completed_reads);
136+
guard.completed_writes.extend(completed_writes);
137+
// insert queue ids for all processed requests into irq_rx
138+
for (q_id, _req_id, _blk, _p, _s) in reqs.iter() {
139+
guard.irq_rx.insert(*q_id);
140+
}
141+
for (q_id, _req_id, _blk, _p, _s) in writes.iter() {
142+
guard.irq_rx.insert(*q_id);
143+
}
144+
}
145+
146+
// small delay to simulate device latency
147+
std::thread::sleep(Duration::from_millis(1));
148+
}
149+
});
150+
151+
Self {
152+
block_size,
153+
num_blocks,
154+
_storage: storage,
155+
inner,
156+
}
157+
}
158+
}
159+
160+
impl rdif_base::DriverGeneric for RamDisk {
161+
fn open(&mut self) -> Result<(), KError> {
162+
Ok(())
163+
}
164+
165+
fn close(&mut self) -> Result<(), KError> {
166+
Ok(())
167+
}
168+
}
169+
170+
impl Interface for RamDisk {
171+
fn create_queue(&mut self) -> Option<Box<dyn IQueue>> {
172+
let mut g = self.inner.lock().unwrap();
173+
let id = g.next_queue_id;
174+
g.next_queue_id += 1;
175+
Some(Box::new(RamQueue::new(
176+
id,
177+
self.block_size,
178+
self.num_blocks,
179+
self.inner.clone(),
180+
)))
181+
}
182+
183+
fn enable_irq(&mut self) {
184+
let mut g = self.inner.lock().unwrap();
185+
g.irq_enabled = true;
186+
}
187+
188+
fn disable_irq(&mut self) {
189+
let mut g = self.inner.lock().unwrap();
190+
g.irq_enabled = false;
191+
}
192+
193+
fn is_irq_enabled(&self) -> bool {
194+
let g = self.inner.lock().unwrap();
195+
g.irq_enabled
196+
}
197+
198+
fn handle_irq(&mut self) -> Event {
199+
let mut g = self.inner.lock().unwrap();
200+
let mut ev = Event::none();
201+
core::mem::swap(&mut ev.queue, &mut g.irq_rx);
202+
ev
203+
}
204+
}
205+
206+
struct RamQueue {
207+
id: usize,
208+
block_size: usize,
209+
num_blocks: usize,
210+
inner: Arc<Mutex<RamInner>>,
211+
}
212+
213+
impl RamQueue {
214+
fn new(id: usize, block_size: usize, num_blocks: usize, inner: Arc<Mutex<RamInner>>) -> Self {
215+
Self {
216+
id,
217+
block_size,
218+
num_blocks,
219+
inner,
220+
}
221+
}
222+
}
223+
224+
impl IQueue for RamQueue {
225+
fn id(&self) -> usize {
226+
self.id
227+
}
228+
229+
fn num_blocks(&self) -> usize {
230+
self.num_blocks
231+
}
232+
233+
fn block_size(&self) -> usize {
234+
self.block_size
235+
}
236+
237+
fn buff_config(&self) -> BuffConfig {
238+
BuffConfig {
239+
dma_mask: !0u64,
240+
align: 1,
241+
size: self.block_size,
242+
}
243+
}
244+
245+
fn submit_request(&mut self, request: Request<'_>) -> Result<RequestId, BlkError> {
246+
let block_id = request.block_id;
247+
if block_id >= self.num_blocks {
248+
return Err(BlkError::InvalidBlockIndex(block_id));
249+
}
250+
251+
let mut g = self.inner.lock().unwrap();
252+
let req_id = RequestId::new(g.next_req_id);
253+
g.next_req_id += 1;
254+
255+
match request.kind {
256+
RequestKind::Read(buff) => {
257+
g.pending
258+
.push((self.id, req_id, block_id, buff.virt as usize, buff.size));
259+
}
260+
RequestKind::Write(slice) => {
261+
g.pending_writes.push((
262+
self.id,
263+
req_id,
264+
block_id,
265+
slice.as_ptr() as usize,
266+
slice.len(),
267+
));
268+
}
269+
}
270+
271+
// Indicate that the device has data for rx (so handle_irq can wake)
272+
g.irq_rx.insert(self.id);
273+
274+
Ok(req_id)
275+
}
276+
277+
fn poll_request(&mut self, request: RequestId) -> Result<(), BlkError> {
278+
let mut g = self.inner.lock().unwrap();
279+
if let Some(pos) = g.completed.iter().position(|r| *r == request) {
280+
g.completed.remove(pos);
281+
Ok(())
282+
} else if let Some(pos) = g.completed_writes.iter().position(|r| *r == request) {
283+
g.completed_writes.remove(pos);
284+
Ok(())
285+
} else {
286+
Err(BlkError::Retry)
287+
}
288+
}
289+
}
290+
291+
#[tokio::main]
292+
async fn main() {
293+
// initialize dma-api osal
294+
dma_api::init(&EX_OSAL);
295+
296+
// create a ram device with 16 byte blocks and 1024 blocks
297+
let mut ram = Block::new(RamDisk::new(16, 1024));
298+
299+
// open device (no-op here)
300+
let _ = ram.open();
301+
302+
// get a read queue via the new Interface API
303+
let mut sq = ram.create_queue().expect("read queue");
304+
305+
// spawn a thread that polls the device handle and prints events
306+
let handle = ram.irq_handler();
307+
std::thread::spawn(move || {
308+
loop {
309+
handle.handle();
310+
std::thread::sleep(std::time::Duration::from_millis(10));
311+
}
312+
});
313+
314+
// request blocks 3 and 4 and asynchronously poll for completion
315+
let res = sq.read_blocks(3, 2).await;
316+
317+
for b in res {
318+
println!("block: {:?}", b.unwrap());
319+
}
320+
let size = sq.block_size();
321+
322+
// prepare data for blocks 3 and 4: fill with 0xAA and 0xBB respectively
323+
let mut data = vec![0xAAu8; size];
324+
data.extend(vec![0xBBu8; size]);
325+
326+
let res = sq.write_blocks(3, &data).await;
327+
328+
for r in res {
329+
println!("write block result: {:?}", r);
330+
}
331+
332+
let res = sq.read_blocks(3, 2).await;
333+
334+
for b in res {
335+
println!("block: {:?}", b.unwrap());
336+
}
337+
338+
println!("done");
339+
340+
// test blocking
341+
println!("test blocking read");
342+
343+
let res = sq.read_blocks_blocking(3, 2);
344+
for b in res {
345+
println!("block: {:?}", b.unwrap());
346+
}
347+
}

0 commit comments

Comments
 (0)