Verified Commit da017f79 authored by jD91mZM2's avatar jD91mZM2
Browse files

Basic nonblocking I/O

parent 1624dead
......@@ -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(())
}
......@@ -2,18 +2,28 @@ use std::collections::BTreeMap;
use syscall::{flag::*, error::*, Error, SchemeBlockMut, Result};
pub struct Handle {
flags: usize,
path: Option<String>,
remote: Option<usize>,
buffer: Vec<u8>
}
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<Option<usize>> {
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<Option<usize>> {
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<Option<usize>> {
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<Option<usize>> {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment