Replies: 1 comment 1 reply
|
The implementation
pub fn open(&self, addr: impl AsRef<OsStr>) -> io::Result<NamedPipeClient> {
// Safety: We're calling open_with_security_attributes_raw w/ a null
// pointer which disables it.
unsafe { self.open_with_security_attributes_raw(addr, ptr::null_mut()) }
}pub unsafe fn open_with_security_attributes_raw(
&self,
addr: impl AsRef<OsStr>,
attrs: *mut c_void,
) -> io::Result<NamedPipeClient> {
...
let h = unsafe {
windows_sys::CreateFileW(
addr.as_ptr(),
desired_access,
0,
attrs as *mut _,
windows_sys::OPEN_EXISTING,
self.get_flags(),
null_mut(),
)
};
if h == windows_sys::INVALID_HANDLE_VALUE {
return Err(io::Error::last_os_error());
}
...
unsafe { NamedPipeClient::from_raw_handle(h as _) }
}
fn get_flags(&self) -> u32 {
self.security_qos_flags | windows_sys::FILE_FLAG_OVERLAPPED
}
Why This is the part worth being precise about, because it's easy to reach for the wrong explanation. So the fail-fast behavior the docs describe ( The doc example shows this is the pattern in practice The doc comment directly above /// # #[tokio::main] async fn main() -> std::io::Result<()> {
/// let client = loop {
/// match ClientOptions::new().open(PIPE_NAME) {
/// Ok(client) => break client,
/// Err(e) if e.raw_os_error() == Some(ERROR_PIPE_BUSY as i32) => (),
/// Err(e) => return Err(e),
/// }
///
/// time::sleep(Duration::from_millis(50)).await;
/// };
Contrast with the server side
pub async fn connect(&self) -> io::Result<()> {
match self.io.connect() {
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
self.io
.registration()
.async_io(Interest::WRITABLE, || self.io.connect())
.await
}
x => x,
}
}This works because Practical takeaway for the reqwest PR Given the above, Tokio's public API doesn't require |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Hi,
I’m working on a reqwest PR seanmonstar/reqwest#3086 involving Windows named pipes and wanted to clarify the intended behavior of Tokio’s
ClientOptions::open().ClientOptions::open()calls the WindowsCreateFileWAPI synchronously, while the resulting pipe handle usesFILE_FLAG_OVERLAPPED.Is
ClientOptions::open()intentionally synchronous, and is it expected to be called directly from an async task? Or should callers take any precautions to avoid potentially blocking a Tokio worker thread during pipe creation?I’d like to understand the intended API semantics before deciding whether this belongs in reqwest or Tokio.
Thanks!
All reactions