parity-tokio-ipc
parity-tokio-ipc copied to clipboard
Simple pipe-server hanging forever
Thanks for providing this crate. I'm new to rust and tokio, so please forgive me if this looks dumb.
However, I encountered a hanging issue when using it on Windows. I'm building an IpcServer
as a Future
from an Incoming
and then I run it with tokio. I got an IPC client which can connect (with CreateFile
) to the pipe successfully. The client can even write to the pipe asynchronously. But IpcServer::poll
never fires again except for the first time.
I'm pretty sure this is related to my code. Would you please kindly point it out? Thanks.
use futures::prelude::*;
use parity_tokio_ipc::{Endpoint, Incoming};
use tokio;
use std::io::ErrorKind;
const DAEMON_PIPE_NAME: &str = "\\\\.\\pipe\\TestPipe\\ServiceControl\0";
pub struct IpcServer {
incoming: Incoming,
}
impl IpcServer {
pub fn new() -> Self {
let endpoint = Endpoint::new(DAEMON_PIPE_NAME.to_string());
let incoming = match endpoint.incoming(&tokio::reactor::Handle::default()) {
Ok(inc) => inc,
Err(e) => {
println!("IpcServer: Endpoint creation failed {:?}", e);
panic!("Check the pipe");
}
};
IpcServer {
incoming,
}
}
}
impl Future for IpcServer {
type Item = ();
type Error = ();
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
loop {
match self.incoming.poll() {
Ok(Async::Ready(Some((_, _)))) => {
println!("IpcServer: new pipe incoming");
continue;
}
Ok(Async::Ready(None)) => {
panic!("impossible!");
}
Ok(Async::NotReady) => return Ok(Async::NotReady),
Err(e) => {
match e.kind() {
ErrorKind::BrokenPipe | ErrorKind::Interrupted => continue,
_ => {
println!("IpcServer: endpoint connection error {:?}", e);
return Err(());
}
}
}
}
}
}
}
fn main() {
tokio::run(IpcServer::new());
}
Ah, I figured it out.
The first time Incoming::poll
being called is meant to register itself to the underlying IOCP writable event. To do that, it first needs to register the internal PollEvented2
as a mio Registration
.
tokio-named-pipe relies on the mio registration taking place during NamedPipe::from_pipe
. But that depends on the handle
passed in being a bound tokio::reactor::Reactor
handle. Otherwise, it fails silently and never gets notified again.
In the earlier version of tokio, there is a tokio::reactor::Handle::current()
method to provide us a bound handle. So everything is fine at that time. But that method is deprecated in the current version. And the new tokio::reactor::Handle::default()
method makes things worse by providing a lazy-bind handle which let the code compile but fail to register during NamedPipe::from_pipe
at runtime. So the IpcServer
hangs eventually after its first poll
.
@hankbao Hi,I also encountered this problem, is there any fix?
@hankbao Hi,I also encountered this problem, is there any fix?
I just use tokio::reactor::Handle::current()
and ignore the deprecation warning for now.