nervosnetwork / tentacle

A multiplexed p2p network framework that supports custom protocols
https://docs.rs/tentacle
MIT License
54 stars 24 forks source link

fix: don't use async to impl poll function, it's wrong way #249

Closed driftluo closed 4 years ago

driftluo commented 4 years ago

should use poll to implement the async function, but cannot use the async function to implement poll

Each call to async actually regenerates a temporary future. If the future is pending, it does not save the pending state, but simply drop it. This is incorrect behavior

example:

async fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
    let len = self.socket.write(buf).await?; // ready here
    self.socket.flush().await?; // pending here, but this buf is already write to inner socket, it will cause the caller to think that the send was not successful, and try to send again
    ok(len)
}
fn poll_write(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
   let task = pin_mut!(self.write(buf));
   task.poll(cx)
}

right way: don't use async, manage state by yourself

fn poll_write(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
    let mut sink = Pin::new(&mut self.socket);
    match sink.as_mut().poll_ready(cx) {
       Poll::Ready(Ok(_)) => {
          sink.as_mut().start_send(buf)?;
          let _ignore = sink.as_mut().poll_flush(cx)?;
          Poll::Ready(Ok(buf.len()))
       }
       Poll::Pending => Poll::Pending,
       Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
}
doitian commented 4 years ago

What's the correct way to re-implement the example in your description? It can help me better understand the issue.