Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problems with asynchronous interfaces #151

Open
Dr-TSNG opened this issue Jul 23, 2024 · 0 comments
Open

Problems with asynchronous interfaces #151

Dr-TSNG opened this issue Jul 23, 2024 · 0 comments

Comments

@Dr-TSNG
Copy link

Dr-TSNG commented Jul 23, 2024

考虑我们有这样的结构,它主要实现了这样的功能:

  1. 发送读请求,将 waker 保存,让出 CPU。
  2. 中断到来,根据 token 取出 waker,唤醒 Future。
  3. 完成读取。

这套方案存在两个问题:

  1. 在非理想情况下,Future 可能被其他事件取消(信号/进程终止等),此时后续的 complete_read_blocks 不会被执行,因此需要驱动支持直接取消一个 token,而不需要完成数据复制工作。(不能创建一个新的 buffer 放到全局区,把 complete 操作移到 handle_irq 处,因为这会导致额外的复制开销。)
  2. peek_used 方法只会取出一个待处理的 token(而不会消费),而在这个 token 被处理前无法得知其他 token 是否完成,从而将对应任务唤醒。这会导致其他的 Future 因为后续无法收到中断信号而永远被挂起(假设中断发生时所有任务都已经就绪)。

这样的问题在目前的异步接口下很难解决。

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();
        }
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant