summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRoma Sokolov <sokolov.r.v@gmail.com>2014-10-11 00:18:32 +0400
committerRoma Sokolov <sokolov.r.v@gmail.com>2014-10-11 00:18:32 +0400
commit28caf48e6fd199eb13b54239d67cf609964aa83e (patch)
tree06d349e37d7dec77712a4b9d74a419b73cf9acea /src
parent4297e6598ca696403c27a1efdf04d4e5157d521b (diff)
downloadnix-28caf48e6fd199eb13b54239d67cf609964aa83e.zip
Implement scatter/gather IO: writev & readv.
Also added tests to check them.
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs1
-rw-r--r--src/unistd.rs82
2 files changed, 82 insertions, 1 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 68424196..4f2d01cb 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -6,6 +6,7 @@
#![allow(non_camel_case_types)]
extern crate libc;
+extern crate core;
// Re-export some libc constants
pub use libc::{c_int, c_void};
diff --git a/src/unistd.rs b/src/unistd.rs
index 4f3140dd..7abaf410 100644
--- a/src/unistd.rs
+++ b/src/unistd.rs
@@ -3,14 +3,17 @@ use std::c_str::{CString, ToCStr};
use libc::{c_char, c_void, c_int, size_t, pid_t};
use fcntl::{fcntl, Fd, OFlag, O_NONBLOCK, O_CLOEXEC, FD_CLOEXEC, F_SETFD, F_SETFL};
use errno::{SysResult, SysError, from_ffi};
+use core::raw::Slice as RawSlice;
#[cfg(target_os = "linux")]
pub use self::linux::*;
mod ffi {
- use libc::{c_char, c_int, size_t};
+ use super::{IovecR,IovecW};
+ use libc::{c_char, c_int, size_t, ssize_t};
pub use libc::{close, read, write, pipe};
pub use libc::funcs::posix88::unistd::fork;
+ use fcntl::Fd;
extern {
// duplicate a file descriptor
@@ -37,6 +40,14 @@ mod ffi {
// gets the hostname
// doc: http://man7.org/linux/man-pages/man2/gethostname.2.html
pub fn sethostname(name: *const c_char, len: size_t) -> c_int;
+
+ // vectorized version of write
+ // doc: http://man7.org/linux/man-pages/man2/writev.2.html
+ pub fn writev(fd: Fd, iov: *const IovecW, iovcnt: c_int) -> ssize_t;
+
+ // vectorized version of read
+ // doc: http://man7.org/linux/man-pages/man2/readv.2.html
+ pub fn readv(fd: Fd, iov: *const IovecR, iovcnt: c_int) -> ssize_t;
}
}
@@ -73,6 +84,56 @@ pub fn fork() -> SysResult<Fork> {
}
}
+// We use phantom types to maintain memory safety.
+// If readv/writev were using simple &[Iovec] we could initialize
+// Iovec with immutable slice and then pass it to readv, overwriting content
+// we dont have write access to:
+// let mut v = Vec::new();
+// let iov = Iovec::from_slice(immutable_vec.as_slice());
+// v.push(iov);
+// let _:SysResult<uint> = readv(fd, v.as_slice());
+
+// We do not want <T> to appear in ffi functions, so we provide this aliases.
+type IovecR = Iovec<ToRead>;
+type IovecW = Iovec<ToWrite>;
+
+pub struct ToRead;
+pub struct ToWrite;
+
+#[repr(C)]
+pub struct Iovec<T> {
+ iov_base: *mut c_void,
+ iov_len: size_t,
+}
+
+impl <T> Iovec<T> {
+ #[inline]
+ pub fn as_slice<'a>(&'a self) -> &'a [u8] {
+ unsafe { mem::transmute(RawSlice { data: self.iov_base as *const u8, len: self.iov_len as uint }) }
+ }
+}
+
+impl Iovec<ToWrite> {
+ #[inline]
+ pub fn from_slice(buf: &[u8]) -> Iovec<ToWrite> {
+ Iovec {
+ iov_base: buf.as_ptr() as *mut c_void,
+ iov_len: buf.len() as size_t
+ }
+ }
+}
+
+impl Iovec<ToRead> {
+ #[inline]
+ pub fn from_mut_slice(buf: &mut [u8]) -> Iovec<ToRead> {
+ Iovec {
+ iov_base: buf.as_ptr() as *mut c_void,
+ iov_len: buf.len() as size_t
+ }
+ }
+}
+
+
#[inline]
pub fn dup(oldfd: Fd) -> SysResult<Fd> {
let res = unsafe { ffi::dup(oldfd) };
@@ -222,6 +283,25 @@ pub fn write(fd: Fd, buf: &[u8]) -> SysResult<uint> {
return Ok(res as uint)
}
+pub fn writev(fd: Fd, iov: &[Iovec<ToWrite>]) -> SysResult<uint> {
+ let res = unsafe { ffi::writev(fd, iov.as_ptr(), iov.len() as c_int) };
+ if res < 0 {
+ return Err(SysError::last());
+ }
+
+ return Ok(res as uint)
+}
+
+pub fn readv(fd: Fd, iov: &mut [Iovec<ToRead>]) -> SysResult<uint> {
+ let res = unsafe { ffi::readv(fd, iov.as_ptr(), iov.len() as c_int) };
+ if res < 0 {
+ return Err(SysError::last());
+ }
+
+ return Ok(res as uint)
+}
+
+
pub fn pipe() -> SysResult<(Fd, Fd)> {
unsafe {
let mut res;