diff --git a/CHANGELOG.md b/CHANGELOG.md index 04e9322f64..1dfd04cc84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,18 @@ This project adheres to [Semantic Versioning](http://semver.org/). `::nix::sched` to `Result` and `Result<()>`, respectively. They now return `EINVAL`, if an invalid argument for the `field` parameter is passed. ([#402](https://github.com/nix-rust/nix/pull/402)) +- `MqAttr` in `::nix::mqueue` is now an opaque proxy for `::libc::mq_attr`, + which has the same structure as the old `MqAttr`. The field `mq_flags` of + `::libc::mq_attr` is readable using the new method `flags()` of `MqAttr`. + `MqAttr` also no longer implements `Debug`. + ([#0](https://github.com/nix-rust/nix/pull/0)) +- The parameter `msq_prio` of `mq_receive` with type `u32` in `::nix::mqueue` + was replaced by a parameter named `msg_prio` with type `&mut u32`, so that + the message priority can be obtained by the caller. + ([#0](https://github.com/nix-rust/nix/pull/0)) +- The type alias `MQd` in `::nix::queue` was replaced by the type alias + `libc::mqd_t`, both of which are aliases for the same type. + ([#0](https://github.com/nix-rust/nix/pull/0)) ### Removed - Type alias `SigNum` from `::nix::sys::signal`. diff --git a/src/lib.rs b/src/lib.rs index b983a9c213..8dbf9fe018 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,7 +40,7 @@ pub mod fcntl; #[cfg(any(target_os = "linux", target_os = "android"))] pub mod mount; -#[cfg(any(target_os = "linux"))] +#[cfg(target_os = "linux")] pub mod mqueue; #[cfg(any(target_os = "linux", target_os = "macos"))] diff --git a/src/mqueue.rs b/src/mqueue.rs index b8a2250e06..9bf6e77edb 100644 --- a/src/mqueue.rs +++ b/src/mqueue.rs @@ -4,114 +4,117 @@ use {Errno, Result}; -use libc::{c_int, c_long, c_char, size_t, mode_t}; +use libc::{self, c_char, c_long, mode_t, mqd_t, size_t}; use std::ffi::CString; use sys::stat::Mode; -use std::ptr; - -pub use self::consts::*; - -pub type MQd = c_int; - -#[cfg(target_os = "linux")] -mod consts { - use libc::c_int; - - bitflags!( - flags MQ_OFlag: c_int { - const O_RDONLY = 0o00000000, - const O_WRONLY = 0o00000001, - const O_RDWR = 0o00000002, - const O_CREAT = 0o00000100, - const O_EXCL = 0o00000200, - const O_NONBLOCK = 0o00004000, - const O_CLOEXEC = 0o02000000, - } - ); - - bitflags!( - flags FdFlag: c_int { - const FD_CLOEXEC = 1 - } - ); +use std::mem; + +libc_bitflags!{ + flags MQ_OFlag: libc::c_int { + O_RDONLY, + O_WRONLY, + O_RDWR, + O_CREAT, + O_EXCL, + O_NONBLOCK, + O_CLOEXEC, + } } -mod ffi { - use libc::{c_char, size_t, ssize_t, c_uint, c_int}; - use super::MQd; - use super::MqAttr; - - #[allow(improper_ctypes)] - extern "C" { - pub fn mq_open(name: *const c_char, oflag: c_int, ...) -> MQd; - - pub fn mq_close (mqd: MQd) -> c_int; - - pub fn mq_unlink(name: *const c_char) -> c_int; - - pub fn mq_receive (mqd: MQd, msg_ptr: *const c_char, msg_len: size_t, msq_prio: *const c_uint) -> ssize_t; - - pub fn mq_send (mqd: MQd, msg_ptr: *const c_char, msg_len: size_t, msq_prio: c_uint) -> c_int; - - pub fn mq_getattr(mqd: MQd, attr: *mut MqAttr) -> c_int; - - pub fn mq_setattr(mqd: MQd, newattr: *const MqAttr, oldattr: *mut MqAttr) -> c_int; +libc_bitflags!{ + flags FdFlag: libc::c_int { + FD_CLOEXEC, } } #[repr(C)] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Clone, Copy)] pub struct MqAttr { - pub mq_flags: c_long, - pub mq_maxmsg: c_long, - pub mq_msgsize: c_long, - pub mq_curmsgs: c_long, - pad: [c_long; 4] + mq_attr: libc::mq_attr, } -impl MqAttr { - pub fn new(mq_flags: c_long, mq_maxmsg: c_long, mq_msgsize: c_long, mq_curmsgs: c_long) -> MqAttr { - MqAttr { mq_flags: mq_flags, mq_maxmsg: mq_maxmsg, mq_msgsize: mq_msgsize, mq_curmsgs: mq_curmsgs, pad: [0; 4] } - } +impl PartialEq for MqAttr { + fn eq(&self, other: &MqAttr) -> bool { + let self_attr = self.mq_attr; + let other_attr = other.mq_attr; + self_attr.mq_flags == other_attr.mq_flags && self_attr.mq_maxmsg == other_attr.mq_maxmsg && + self_attr.mq_msgsize == other_attr.mq_msgsize && + self_attr.mq_curmsgs == other_attr.mq_curmsgs + } } +impl MqAttr { + pub fn new(mq_flags: c_long, + mq_maxmsg: c_long, + mq_msgsize: c_long, + mq_curmsgs: c_long) + -> MqAttr { + let mut attr = unsafe { mem::uninitialized::() }; + attr.mq_flags = mq_flags; + attr.mq_maxmsg = mq_maxmsg; + attr.mq_msgsize = mq_msgsize; + attr.mq_curmsgs = mq_curmsgs; + MqAttr { mq_attr: attr } + } -pub fn mq_open(name: &CString, oflag: MQ_OFlag, mode: Mode, attr: Option<&MqAttr>) -> Result { - let attr_p = attr.map(|attr| attr as *const MqAttr).unwrap_or(ptr::null()); - let res = unsafe { ffi::mq_open(name.as_ptr(), oflag.bits(), mode.bits() as mode_t, attr_p) }; + pub fn flags(&self) -> c_long { + self.mq_attr.mq_flags + } +} + +pub fn mq_open(name: &CString, + oflag: MQ_OFlag, + mode: Mode, + attr: Option<&MqAttr>) + -> Result { + let res = match attr { + Some(mq_attr) => unsafe { + libc::mq_open(name.as_ptr(), + oflag.bits(), + mode.bits() as mode_t, + &mq_attr.mq_attr as *const libc::mq_attr) + }, + None => unsafe { libc::mq_open(name.as_ptr(), oflag.bits()) }, + }; Errno::result(res) } pub fn mq_unlink(name: &CString) -> Result<()> { - let res = unsafe { ffi::mq_unlink(name.as_ptr()) }; + let res = unsafe { libc::mq_unlink(name.as_ptr()) }; Errno::result(res).map(drop) } -pub fn mq_close(mqdes: MQd) -> Result<()> { - let res = unsafe { ffi::mq_close(mqdes) }; +pub fn mq_close(mqdes: mqd_t) -> Result<()> { + let res = unsafe { libc::mq_close(mqdes) }; Errno::result(res).map(drop) } - -pub fn mq_receive(mqdes: MQd, message: &mut [u8], msq_prio: u32) -> Result { +pub fn mq_receive(mqdes: mqd_t, message: &mut [u8], msg_prio: &mut u32) -> Result { let len = message.len() as size_t; - let res = unsafe { ffi::mq_receive(mqdes, message.as_mut_ptr() as *mut c_char, len, &msq_prio) }; - + let res = unsafe { + libc::mq_receive(mqdes, + message.as_mut_ptr() as *mut c_char, + len, + msg_prio as *mut u32) + }; Errno::result(res).map(|r| r as usize) } -pub fn mq_send(mqdes: MQd, message: &[u8], msq_prio: u32) -> Result<()> { - let res = unsafe { ffi::mq_send(mqdes, message.as_ptr() as *const c_char, message.len(), msq_prio) }; - +pub fn mq_send(mqdes: mqd_t, message: &[u8], msq_prio: u32) -> Result<()> { + let res = unsafe { + libc::mq_send(mqdes, + message.as_ptr() as *const c_char, + message.len(), + msq_prio) + }; Errno::result(res).map(drop) } -pub fn mq_getattr(mqd: MQd) -> Result { - let mut attr = MqAttr::new(0, 0, 0, 0); - let res = unsafe { ffi::mq_getattr(mqd, &mut attr) }; - try!(Errno::result(res)); - Ok(attr) +pub fn mq_getattr(mqd: mqd_t) -> Result { + let mut attr = unsafe { mem::uninitialized::() }; + let res = unsafe { libc::mq_getattr(mqd, &mut attr) }; + Errno::result(res).map(|_| MqAttr { mq_attr: attr }) } /// Set the attributes of the message queue. Only `O_NONBLOCK` can be set, everything else will be ignored @@ -119,27 +122,32 @@ pub fn mq_getattr(mqd: MQd) -> Result { /// It is recommend to use the `mq_set_nonblock()` and `mq_remove_nonblock()` convenience functions as they are easier to use /// /// [Further reading](http://man7.org/linux/man-pages/man3/mq_setattr.3.html) -pub fn mq_setattr(mqd: MQd, newattr: &MqAttr) -> Result { - let mut attr = MqAttr::new(0, 0, 0, 0); - let res = unsafe { ffi::mq_setattr(mqd, newattr as *const MqAttr, &mut attr) }; - try!(Errno::result(res)); - Ok(attr) +pub fn mq_setattr(mqd: mqd_t, newattr: &MqAttr) -> Result { + let mut attr = unsafe { mem::uninitialized::() }; + let res = unsafe { libc::mq_setattr(mqd, &newattr.mq_attr as *const libc::mq_attr, &mut attr) }; + Errno::result(res).map(|_| MqAttr { mq_attr: attr }) } /// Convenience function. /// Sets the `O_NONBLOCK` attribute for a given message queue descriptor /// Returns the old attributes -pub fn mq_set_nonblock(mqd: MQd) -> Result<(MqAttr)> { +pub fn mq_set_nonblock(mqd: mqd_t) -> Result<(MqAttr)> { let oldattr = try!(mq_getattr(mqd)); - let newattr = MqAttr::new(O_NONBLOCK.bits() as c_long, oldattr.mq_maxmsg, oldattr.mq_msgsize, oldattr.mq_curmsgs); + let newattr = MqAttr::new(O_NONBLOCK.bits() as c_long, + oldattr.mq_attr.mq_maxmsg, + oldattr.mq_attr.mq_msgsize, + oldattr.mq_attr.mq_curmsgs); mq_setattr(mqd, &newattr) } /// Convenience function. /// Removes `O_NONBLOCK` attribute for a given message queue descriptor /// Returns the old attributes -pub fn mq_remove_nonblock(mqd: MQd) -> Result<(MqAttr)> { +pub fn mq_remove_nonblock(mqd: mqd_t) -> Result<(MqAttr)> { let oldattr = try!(mq_getattr(mqd)); - let newattr = MqAttr::new(0, oldattr.mq_maxmsg, oldattr.mq_msgsize, oldattr.mq_curmsgs); + let newattr = MqAttr::new(0, + oldattr.mq_attr.mq_maxmsg, + oldattr.mq_attr.mq_msgsize, + oldattr.mq_attr.mq_curmsgs); mq_setattr(mqd, &newattr) } diff --git a/test/test_mq.rs b/test/test_mq.rs index 94431a04a0..fd050d47b1 100644 --- a/test/test_mq.rs +++ b/test/test_mq.rs @@ -33,7 +33,9 @@ fn test_mq_send_and_receive() { let mq_name_in_child = &CString::new(b"/a_nix_test_queue".as_ref()).unwrap(); let mqd_in_child = mq_open(mq_name_in_child, O_CREAT | O_RDONLY, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH, Some(&attr)).unwrap(); let mut buf = [0u8; 32]; - mq_receive(mqd_in_child, &mut buf, 1).unwrap(); + let mut prio = 0u32; + mq_receive(mqd_in_child, &mut buf, &mut prio).unwrap(); + assert!(prio == 1); write(writer, &buf).unwrap(); // pipe result to parent process. Otherwise cargo does not report test failures correctly mq_close(mqd_in_child).unwrap(); } @@ -99,10 +101,10 @@ fn test_mq_set_nonblocking() { let mqd = mq_open(mq_name, O_CREAT | O_WRONLY, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH, Some(&initial_attr)).unwrap(); mq_set_nonblock(mqd).unwrap(); let new_attr = mq_getattr(mqd); - assert!(new_attr.unwrap().mq_flags == O_NONBLOCK.bits() as c_long); + assert!(new_attr.unwrap().flags() == O_NONBLOCK.bits() as c_long); mq_remove_nonblock(mqd).unwrap(); let new_attr = mq_getattr(mqd); - assert!(new_attr.unwrap().mq_flags == 0); + assert!(new_attr.unwrap().flags() == 0); mq_close(mqd).unwrap(); }