Skip to content

Commit

Permalink
Auto merge of #392 - fiveop:less_ffi, r=@fiveop
Browse files Browse the repository at this point in the history
Replace ffi module by libc functions in mqueue.rs

This is almost finished. I still need to check if I introduced any breaking changes by changing signatures. I would want to record this in the change log, however, for that we still need to merge #391.

- [x] update change log
- [x] run rustfmt on `src/mqueue.rs`
  • Loading branch information
homu committed Sep 1, 2016
2 parents 9140e62 + 8ed5521 commit 45e3170
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 89 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ This project adheres to [Semantic Versioning](http://semver.org/).
`::nix::sched` to `Result<bool>` 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`.
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"))]
Expand Down
178 changes: 93 additions & 85 deletions src/mqueue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,142 +4,150 @@

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<MqAttr> 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::<libc::mq_attr>() };
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<MQd> {
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<mqd_t> {
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<usize> {
pub fn mq_receive(mqdes: mqd_t, message: &mut [u8], msg_prio: &mut u32) -> Result<usize> {
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<MqAttr> {
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<MqAttr> {
let mut attr = unsafe { mem::uninitialized::<libc::mq_attr>() };
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
/// Returns the old attributes
/// 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<MqAttr> {
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<MqAttr> {
let mut attr = unsafe { mem::uninitialized::<libc::mq_attr>() };
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)
}
8 changes: 5 additions & 3 deletions test/test_mq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down Expand Up @@ -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();
}

Expand Down

0 comments on commit 45e3170

Please sign in to comment.