kotauskas / interprocess

Multifunctional cross-platform interprocess communication toolkit for Rust.
Apache License 2.0
401 stars 48 forks source link

Windows LocalSocketListener hangs in nonblocking mode #22

Closed mkolopanis closed 2 years ago

mkolopanis commented 2 years ago

Describe the bug First off thanks for this package it is a nice abstraction for socket-like behavior. I use this in a project of mine aimed at providing OS agnostic functionality: cfdp-rs.

Even when set to non_blocking, a Windows local_socket::LocalSocketListener can hang waiting for connections. I do not see this problem on Linux of Macos. Presumably an issue related to named_pipes on windows since the other OSes use sockets.

I'm using win11 build 22000.978 in the accompanying gif, but I have noticed this behavior on github action "windows-latest" runner.

To Reproduce

Attached a simple program that runs a listener in a thread and will exit on the first valid connection. The main thread waits 1s, then makes a LocalSocketStream connection to signal for the child thread to end.

MWE
```rust use interprocess::local_socket::{LocalSocketListener, LocalSocketStream}; use std::{ io::Error, sync::{ atomic::{AtomicBool, Ordering}, Arc, }, thread::{self, JoinHandle}, time::{Duration, Instant}, }; fn main() -> Result<(), Box> { let terminate = Arc::new(AtomicBool::new(false)); let local_signal = terminate; println!("Starting up"); let _handle: JoinHandle> = thread::spawn(move || { let listener = LocalSocketListener::bind("test_connection")?; listener.set_nonblocking(true)?; let mut tracker = Instant::now(); while !local_signal.load(Ordering::Relaxed) { println!("tracker at {:?}", tracker.elapsed()); if tracker.elapsed() >= Duration::from_secs_f32(0.01) { println!("Ping"); tracker = Instant::now(); } if let Ok(_conn) = listener.accept() { local_signal.store(true, Ordering::Relaxed); } thread::sleep(Duration::from_millis(100)); } Ok(()) }); thread::sleep(Duration::from_secs(1)); let _ = LocalSocketStream::connect("test_connection")?; _handle.join().expect("Unable to join handle.").unwrap(); println!("Shutting Down"); Ok(()) } ```
Cargo.toml
```toml [package] name = "playground" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] interprocess = "*" ```

Expected behavior Expected behavior from this script is to see a "Ping" line 10 times before being shut down when the Stream finally connects. total time ~1s. The "tracker at" debug print will only count a few times a seen in the gif, indicating a hang in the second block.

Actual Behavior Hangs indefinitely.

interprocess_hang gif

kotauskas commented 2 years ago

1.2.0, which I just published, should fix this, since it tackled a very similar type of issue. I'll wait for your feedback before closing this one.

mkolopanis commented 2 years ago

I have verified this has fixed the issue in my test case.