summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Lerche <me@carllerche.com>2014-08-21 01:13:57 -0700
committerCarl Lerche <me@carllerche.com>2014-08-21 01:13:57 -0700
commit2abaad5fbce61ec566a244c1d2eae2bc3aa5fd5b (patch)
tree3caf4bfb967e2d29eb33812ea2c2929066cdeb08
parentbbc24ea90eb9814db71a1297c4deb4eef91f9c2d (diff)
downloadnix-2abaad5fbce61ec566a244c1d2eae2bc3aa5fd5b.zip
Bind kqueue + misc cleanup
-rw-r--r--src/fcntl.rs106
-rw-r--r--src/features.rs15
-rw-r--r--src/lib.rs3
-rw-r--r--src/sys/event.rs148
-rw-r--r--src/sys/mod.rs4
-rw-r--r--src/sys/socket.rs18
6 files changed, 290 insertions, 4 deletions
diff --git a/src/fcntl.rs b/src/fcntl.rs
index ccaee9bc..80290aec 100644
--- a/src/fcntl.rs
+++ b/src/fcntl.rs
@@ -4,11 +4,66 @@ use libc::{c_int, mode_t};
use errno::{SysResult, SysError};
pub use self::consts::*;
+pub use self::ffi::flock;
pub type Fd = c_int;
mod ffi {
- pub use libc::open;
+ pub use libc::{open, fcntl};
+ pub use self::os::*;
+
+ #[cfg(target_os = "linux")]
+ mod os {
+ use libc::{c_int, c_short, off_t, pid_t};
+
+ pub struct flock {
+ pub l_type: c_short,
+ pub l_whence: c_short,
+ pub l_start: off_t,
+ pub l_len: off_t,
+ pub l_pid: pid_t,
+
+ // not actually here, but brings in line with freebsd
+ pub l_sysid: c_int,
+ }
+
+ pub static F_DUPFD: c_int = 0;
+ pub static F_DUPFD_CLOEXEC: c_int = 1030;
+ pub static F_GETFD: c_int = 1;
+ pub static F_SETFD: c_int = 2;
+ pub static F_GETFL: c_int = 3;
+ pub static F_SETFL: c_int = 4;
+ pub static F_SETLK: c_int = 6;
+ pub static F_SETLKW: c_int = 7;
+ pub static F_GETLK: c_int = 5;
+ }
+
+ #[cfg(target_os = "macos")]
+ #[cfg(target_os = "ios")]
+ mod os {
+ use libc::{c_int, c_short, off_t, pid_t};
+
+ pub struct flock {
+ pub l_start: off_t,
+ pub l_len: off_t,
+ pub l_pid: pid_t,
+ pub l_type: c_short,
+ pub l_whence: c_short,
+
+ // not actually here, but brings in line with freebsd
+ pub l_sysid: c_int,
+ }
+
+ pub static F_DUPFD: c_int = 0;
+ pub static F_DUPFD_CLOEXEC: c_int = 67;
+ pub static F_GETFD: c_int = 1;
+ pub static F_SETFD: c_int = 2;
+ pub static F_GETFL: c_int = 3;
+ pub static F_SETFL: c_int = 4;
+ pub static F_SETLK: c_int = 8;
+ pub static F_SETLKW: c_int = 9;
+ pub static F_GETLK: c_int = 7;
+ }
}
pub fn open(path: &Path, oflag: OFlag, mode: FilePermission) -> SysResult<Fd> {
@@ -21,6 +76,43 @@ pub fn open(path: &Path, oflag: OFlag, mode: FilePermission) -> SysResult<Fd> {
Ok(fd)
}
+pub enum FcntlArg<'a> {
+ F_DUPFD(Fd),
+ F_DUPFD_CLOEXEC(Fd),
+ F_GETFD,
+ F_SETFD(FdFlag), // FD_FLAGS
+ F_GETFL,
+ F_SETFL(OFlag), // O_NONBLOCK
+ F_SETLK(&'a flock),
+ F_SETLKW(&'a flock),
+ F_GETLK(&'a mut flock),
+ #[cfg(target_os = "linux")]
+ F_OFD_SETLK(&'a flock),
+ #[cfg(target_os = "linux")]
+ F_OFD_SETLKW(&'a flock),
+ #[cfg(target_os = "linux")]
+ F_OFD_GETLK(&'a mut flock)
+
+ // TODO: Rest of flags
+}
+
+// TODO: Figure out how to handle value fcntl returns
+pub fn fcntl(fd: Fd, arg: FcntlArg) -> SysResult<()> {
+ let res = unsafe {
+ match arg {
+ F_SETFD(flag) => ffi::fcntl(fd, ffi::F_SETFD, flag.bits()),
+ F_SETFL(flag) => ffi::fcntl(fd, ffi::F_SETFL, flag.bits()),
+ _ => unimplemented!()
+ }
+ };
+
+ if res < 0 {
+ return Err(SysError::last());
+ }
+
+ Ok(())
+}
+
#[cfg(target_os = "linux")]
mod consts {
use libc::c_int;
@@ -50,6 +142,12 @@ mod consts {
static O_NDELAY = O_NONBLOCK.bits
}
)
+
+ bitflags!(
+ flags FdFlag: c_int {
+ static FD_CLOEXEC = 1
+ }
+ )
}
#[cfg(target_os = "macos")]
@@ -82,4 +180,10 @@ mod consts {
static O_NDELAY = O_NONBLOCK.bits
}
)
+
+ bitflags!(
+ flags FdFlag: c_int {
+ static FD_CLOEXEC = 1
+ }
+ )
}
diff --git a/src/features.rs b/src/features.rs
index 8b137891..db8bddf0 100644
--- a/src/features.rs
+++ b/src/features.rs
@@ -1 +1,16 @@
+pub use self::os::*;
+#[cfg(target_os = "linux")]
+mod os {
+ pub fn atomic_cloexec() -> bool {
+ true // TODO: Not on all kernel versions
+ }
+}
+
+#[cfg(target_os = "macos")]
+#[cfg(target_os = "ios")]
+mod os {
+ pub fn atomic_cloexec() -> bool {
+ false
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 96579a1b..e679f7a3 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,5 +1,6 @@
#![crate_name = "nix"]
#![feature(globs)]
+#![allow(non_camel_case_types)]
extern crate libc;
@@ -11,6 +12,8 @@ pub use errno::{SysResult, SysError};
pub mod errno;
#[cfg(target_os = "linux")]
+#[cfg(target_os = "macos")]
+#[cfg(target_os = "ios")]
pub mod features;
#[cfg(target_os = "linux")]
diff --git a/src/sys/event.rs b/src/sys/event.rs
new file mode 100644
index 00000000..335f9ad8
--- /dev/null
+++ b/src/sys/event.rs
@@ -0,0 +1,148 @@
+use libc::{timespec, time_t, c_int, c_long};
+use errno::{SysResult, SysError};
+use fcntl::Fd;
+
+pub use self::ffi::kevent as KEvent;
+
+mod ffi {
+ pub use libc::{c_int, c_void, timespec};
+
+ // Packed to 32 bytes
+ pub struct kevent {
+ pub ident: uint, // 8
+ pub filter: i16, // 2
+ pub flags: u16, // 2
+ pub fflags: u32, // 4
+ pub data: int, // 8
+ pub udata: *mut c_void // 8
+ }
+
+ extern {
+ pub fn kqueue() -> c_int;
+
+ pub fn kevent(
+ kq: c_int,
+ changelist: *const kevent,
+ nchanges: c_int,
+ eventlist: *mut kevent,
+ nevents: c_int,
+ timeout: *const timespec) -> c_int;
+ }
+}
+
+#[repr(C)]
+pub enum EventFilter {
+ EVFILT_READ = -1,
+ EVFILT_WRITE = -2,
+ EVFILT_AIO = -3,
+ EVFILT_VNODE = -4,
+ EVFILT_PROC = -5,
+ EVFILT_SIGNAL = -6,
+ EVFILT_TIMER = -7,
+ EVFILT_MACHPORT = -8,
+ EVFILT_FS = -9,
+ EVFILT_USER = -10,
+ // -11: unused
+ EVFILT_VM = -12,
+ EVFILT_SYSCOUNT = 13
+}
+
+bitflags!(
+ flags EventFlag: u16 {
+ static EV_ADD = 0x0001,
+ static EV_DELETE = 0x0002,
+ static EV_ENABLE = 0x0004,
+ static EV_DISABLE = 0x0008,
+ static EV_RECEIPT = 0x0040,
+ static EV_ONESHOT = 0x0010,
+ static EV_CLEAR = 0x0020,
+ static EV_DISPATCH = 0x0080,
+ static EV_SYSFLAGS = 0xF000,
+ static EV_FLAG0 = 0x1000,
+ static EV_FLAG1 = 0x2000,
+ static EV_EOF = 0x8000,
+ static EV_ERROR = 0x4000
+ }
+)
+
+bitflags!(
+ flags FilterFlag: u32 {
+ static NOTE_TRIGGER = 0x01000000,
+ static NOTE_FFNOP = 0x00000000,
+ static NOTE_FFAND = 0x40000000,
+ static NOTE_FFOR = 0x80000000,
+ static NOTE_FFCOPY = 0xc0000000,
+ static NOTE_FFCTRLMASK = 0xc0000000,
+ static NOTE_FFLAGSMASK = 0x00ffffff,
+ static NOTE_LOWAT = 0x00000001,
+ static NOTE_DELETE = 0x00000001,
+ static NOTE_WRITE = 0x00000002,
+ static NOTE_EXTEND = 0x00000004,
+ static NOTE_ATTRIB = 0x00000008,
+ static NOTE_LINK = 0x00000010,
+ static NOTE_RENAME = 0x00000020,
+ static NOTE_REVOKE = 0x00000040,
+ static NOTE_NONE = 0x00000080,
+ static NOTE_EXIT = 0x80000000,
+ static NOTE_FORK = 0x40000000,
+ static NOTE_EXEC = 0x20000000,
+ static NOTE_REAP = 0x10000000,
+ static NOTE_SIGNAL = 0x08000000,
+ static NOTE_EXITSTATUS = 0x04000000,
+ static NOTE_RESOURCEEND = 0x02000000,
+ static NOTE_APPACTIVE = 0x00800000,
+ static NOTE_APPBACKGROUND = 0x00400000,
+ static NOTE_APPNONUI = 0x00200000,
+ static NOTE_APPINACTIVE = 0x00100000,
+ static NOTE_APPALLSTATES = 0x00f00000,
+ static NOTE_PDATAMASK = 0x000fffff,
+ static NOTE_PCTRLMASK = 0xfff00000,
+ static NOTE_EXIT_REPARENTED = 0x00080000,
+ static NOTE_VM_PRESSURE = 0x80000000,
+ static NOTE_VM_PRESSURE_TERMINATE = 0x40000000,
+ static NOTE_VM_PRESSURE_SUDDEN_TERMINATE = 0x20000000,
+ static NOTE_VM_ERROR = 0x10000000,
+ static NOTE_SECONDS = 0x00000001,
+ static NOTE_USECONDS = 0x00000002,
+ static NOTE_NSECONDS = 0x00000004,
+ static NOTE_ABSOLUTE = 0x00000008,
+ static NOTE_TRACK = 0x00000001,
+ static NOTE_TRACKERR = 0x00000002,
+ static NOTE_CHILD = 0x00000004
+ }
+)
+
+pub static EV_POLL: EventFlag = EV_FLAG0;
+pub static EV_OOBAND: EventFlag = EV_FLAG1;
+
+pub fn kqueue() -> Fd {
+ unsafe { ffi::kqueue() }
+}
+
+pub fn kevent(kq: Fd,
+ changelist: &[KEvent],
+ eventlist: &mut [KEvent],
+ timeout_ms: uint) -> SysResult<uint> {
+
+ // Convert ms to timespec
+ let timeout = timespec {
+ tv_sec: (timeout_ms / 1000) as time_t,
+ tv_nsec: ((timeout_ms % 1000) * 1_000_000) as c_long
+ };
+
+ let res = unsafe {
+ ffi::kevent(
+ kq,
+ changelist.as_ptr(),
+ changelist.len() as c_int,
+ eventlist.as_mut_ptr(),
+ eventlist.len() as c_int,
+ &timeout as *const timespec)
+ };
+
+ if res < 0 {
+ return Err(SysError::last());
+ }
+
+ return Ok(res as uint)
+}
diff --git a/src/sys/mod.rs b/src/sys/mod.rs
index ccab75fd..9e99458b 100644
--- a/src/sys/mod.rs
+++ b/src/sys/mod.rs
@@ -2,6 +2,10 @@
#[cfg(target_os = "linux")]
pub mod epoll;
+#[cfg(target_os = "macos")]
+#[cfg(target_os = "ios")]
+pub mod event;
+
#[cfg(target_os = "linux")]
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
diff --git a/src/sys/socket.rs b/src/sys/socket.rs
index 46db7ab4..e714834b 100644
--- a/src/sys/socket.rs
+++ b/src/sys/socket.rs
@@ -1,7 +1,8 @@
use std::{mem, ptr};
use libc::{c_int, socklen_t};
-use fcntl::Fd;
+use fcntl::{Fd, fcntl, F_SETFL, F_SETFD, FD_CLOEXEC, O_NONBLOCK};
use errno::{SysResult, SysError, from_ffi};
+use features;
pub use libc::{in_addr, sockaddr_in, sockaddr_in6, sockaddr_un, sa_family_t};
@@ -167,14 +168,25 @@ mod consts {
pub static SO_RESTRICT_DENYSET: SockOpt = 0x80000000;
}
-pub fn socket(domain: AddressFamily, ty: SockType, flags: SockFlag) -> SysResult<Fd> {
+pub fn socket(domain: AddressFamily, mut ty: SockType, flags: SockFlag) -> SysResult<Fd> {
+ let feat_atomic = features::atomic_cloexec(); // TODO: detect
+
+ if feat_atomic {
+ ty = ty | flags.bits();
+ }
+
// TODO: Check the kernel version
- let res = unsafe { ffi::socket(domain, ty | flags.bits(), 0) };
+ let res = unsafe { ffi::socket(domain, ty, 0) };
if res < 0 {
return Err(SysError::last());
}
+ if !feat_atomic {
+ try!(fcntl(res, F_SETFD(FD_CLOEXEC)));
+ try!(fcntl(res, F_SETFL(O_NONBLOCK)));
+ }
+
Ok(res)
}