From da017f7941c613119e1d6f0a256230d34146e3aa Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Sat, 2 Jun 2018 09:27:54 +0200 Subject: [PATCH] Basic nonblocking I/O --- examples/chan.rs | 14 ++++++++++++-- src/scheme.rs | 44 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/examples/chan.rs b/examples/chan.rs index 06954e18f5..b4aa478730 100644 --- a/examples/chan.rs +++ b/examples/chan.rs @@ -19,6 +19,8 @@ fn main() -> io::Result<()> { let dup = syscall::dup(server.as_raw_fd(), b"listen").map_err(from_syscall_error)?; let mut dup = unsafe { File::from_raw_fd(dup) }; + println!("Testing basic I/O..."); + dup.write(b"abc")?; dup.flush()?; @@ -26,7 +28,8 @@ fn main() -> io::Result<()> { assert_eq!(client.read(&mut buf)?, 3); assert_eq!(&buf[..3], b"abc"); - // Tada, you can clone handles properly! + println!("Testing blocking I/O..."); + let mut client_clone = client.try_clone()?; let thread = thread::spawn(move || -> io::Result<()> { @@ -36,11 +39,18 @@ fn main() -> io::Result<()> { Ok(()) }); - let mut buf = [0; 5]; assert_eq!(dup.read(&mut buf)?, 3); assert_eq!(&buf[..3], b"def"); thread.join().unwrap().unwrap(); + println!("Testing non-blocking I/O..."); + + syscall::fcntl(client.as_raw_fd(), syscall::F_SETFL, syscall::O_NONBLOCK) + .map_err(from_syscall_error)?; + assert_eq!(client.read(&mut buf).unwrap_err().kind(), io::ErrorKind::WouldBlock); + + println!("It works!"); + Ok(()) } diff --git a/src/scheme.rs b/src/scheme.rs index d104e221cc..37507422e1 100644 --- a/src/scheme.rs +++ b/src/scheme.rs @@ -2,18 +2,28 @@ use std::collections::BTreeMap; use syscall::{flag::*, error::*, Error, SchemeBlockMut, Result}; pub struct Handle { + flags: usize, path: Option, remote: Option, buffer: Vec } impl Handle { - pub fn dup(&mut self) -> Self { + pub fn accept(&mut self) -> Self { Self { + flags: 0, path: None, remote: self.remote.take(), buffer: Vec::new() } } + pub fn copy(&self) -> Self { + Self { + flags: self.flags, + path: None, + remote: self.remote, + buffer: Vec::new() + } + } } #[derive(Default)] @@ -35,6 +45,7 @@ impl SchemeBlockMut for ChanScheme { } let mut handle = Handle { + flags: 0, path: None, remote: None, buffer: Vec::new() @@ -56,13 +67,13 @@ impl SchemeBlockMut for ChanScheme { fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { match buf { b"listen" => { - let mut remote = match self.handles.get(&id) { - Some(ref handle) if handle.path.is_some() => handle.remote, + let mut handle = match self.handles.get(&id) { + Some(ref handle) if handle.path.is_some() => handle.copy(), _ => return Err(Error::new(EBADF)) }; - if let Some(remote) = remote { + if let Some(remote) = handle.remote { let new_id = self.next_id; - let mut clone = self.handles.get_mut(&id).map(Handle::dup).unwrap(); + let mut clone = self.handles.get_mut(&id).map(Handle::accept).unwrap(); self.handles.insert(new_id, clone); self.next_id += 1; @@ -70,6 +81,8 @@ impl SchemeBlockMut for ChanScheme { let mut remote = self.handles.get_mut(&remote).unwrap(); remote.remote = Some(new_id); Ok(Some(new_id)) + } else if handle.flags & O_NONBLOCK == O_NONBLOCK { + Err(Error::new(EAGAIN)) } else { Ok(None) } @@ -79,6 +92,19 @@ impl SchemeBlockMut for ChanScheme { } } } + fn fcntl(&mut self, id: usize, cmd: usize, arg: usize) -> Result> { + match self.handles.get_mut(&id) { + Some(handle) => match cmd { + ::syscall::F_GETFL => Ok(Some(handle.flags)), + ::syscall::F_SETFL => { + handle.flags = arg; + Ok(Some(0)) + }, + _ => Err(Error::new(EINVAL)) + }, + _ => Err(Error::new(EBADF)) + } + } fn write(&mut self, id: usize, buf: &[u8]) -> Result> { let remote = match self.handles.get(&id) { Some(handle) if handle.path.is_none() => handle.remote, @@ -106,13 +132,15 @@ impl SchemeBlockMut for ChanScheme { if handle.path.is_some() { // This is a listener, not a stream. Err(Error::new(EBADF)) - } else if handle.buffer.is_empty() { - Ok(None) - } else { + } else if !handle.buffer.is_empty() { let len = buf.len().min(handle.buffer.len()); buf[..len].copy_from_slice(&handle.buffer[..len]); handle.buffer.drain(..len); Ok(Some(len)) + } else if handle.flags & O_NONBLOCK == O_NONBLOCK { + Err(Error::new(EAGAIN)) + } else { + Ok(None) } } fn close(&mut self, id: usize) -> Result> {