Open Dr-TSNG opened 3 months ago
考虑我们有这样的结构,它主要实现了这样的功能:
waker
这套方案存在两个问题:
complete_read_blocks
handle_irq
peek_used
这样的问题在目前的异步接口下很难解决。
struct ReqGuard<'a>(&'a VirtIOBlkDevice, u16); impl Drop for ReqGuard<'_> { fn drop(&mut self) { let mut inner = self.0.inner.lock(); inner.tokens.remove(&self.1); inner.block.// How: cancel_request(self.1); } } async fn read_block(&self, block_id: usize, buf: &mut [u8]) -> SyscallResult { let mut req = BlkReq::default(); let mut resp = BlkResp::default(); let token = loop { let token = unsafe { self.inner.lock().block.read_blocks_nb(block_id, &mut req, buf, &mut resp) }; // Error handling... }; let guard = ReqGuard(self, token); poll_fn(|cx| { self.inner.lock().tokens.insert(token, cx.waker().clone()); Poll::<()>::Pending }).await; core::mem::forget(guard); let res = unsafe { self.inner.lock().block.complete_read_blocks(token, &mut req, buf, &mut resp) }; // Error handling... } fn handle_irq(&self) { let mut inner = self.inner.lock(); if let Some(token) = inner.block.peek_used() { if let Some(waker) = inner.tokens.remove(&token) { waker.wake(); } } }
考虑我们有这样的结构,它主要实现了这样的功能:
waker
保存,让出 CPU。waker
,唤醒 Future。这套方案存在两个问题:
complete_read_blocks
不会被执行,因此需要驱动支持直接取消一个 token,而不需要完成数据复制工作。(不能创建一个新的 buffer 放到全局区,把 complete 操作移到handle_irq
处,因为这会导致额外的复制开销。)peek_used
方法只会取出一个待处理的 token(而不会消费),而在这个 token 被处理前无法得知其他 token 是否完成,从而将对应任务唤醒。这会导致其他的 Future 因为后续无法收到中断信号而永远被挂起(假设中断发生时所有任务都已经就绪)。这样的问题在目前的异步接口下很难解决。