diff options
author | Alan Somers <asomers@gmail.com> | 2017-11-04 11:59:39 -0600 |
---|---|---|
committer | Alan Somers <asomers@gmail.com> | 2018-01-15 21:39:23 -0700 |
commit | 93b85d8b70b14c49a983a6ab94cec6154bb209ef (patch) | |
tree | e2828bfd2f6096bdae6270891e74793a915c8db8 | |
parent | abd72be1cc0dd064bdc2d77bd09488f67ca28203 (diff) | |
download | nix-93b85d8b70b14c49a983a6ab94cec6154bb209ef.zip |
Add AioCb::from_ptr and AioCb::from_mut_ptr
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | src/sys/aio.rs | 67 | ||||
-rw-r--r-- | test/sys/test_aio.rs | 65 |
3 files changed, 133 insertions, 1 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 624f0c7f..573e167c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Added +- Added `AioCb::from_ptr` and `AioCb::from_mut_ptr` + ([#820](https://github.com/nix-rust/nix/pull/820)) - Added specialized wrappers: `sys::ptrace::{traceme, syscall, cont, attach}`. Using the matching routines with `sys::ptrace::ptrace` is now deprecated. - Added `nix::poll` module for all platforms diff --git a/src/sys/aio.rs b/src/sys/aio.rs index d85ecfa1..94837a12 100644 --- a/src/sys/aio.rs +++ b/src/sys/aio.rs @@ -178,6 +178,73 @@ impl<'a> AioCb<'a> { } } + /// Constructs a new `AioCb` from a mutable raw pointer + /// + /// * `fd` File descriptor. Required for all aio functions. + /// * `offs` File offset + /// * `buf` Pointer to the memory buffer + /// * `len` Length of the buffer pointed to by `buf` + /// * `prio` If POSIX Prioritized IO is supported, then the operation will + /// be prioritized at the process's priority level minus `prio` + /// * `sigev_notify` Determines how you will be notified of event + /// completion. + /// * `opcode` This field is only used for `lio_listio`. It determines + /// which operation to use for this individual aiocb + /// + /// # Safety + /// + /// Unsafe because using this `AioCb` will cause `libc::aio_read` or + /// `libc::aio_write` to dereference a raw pointer, without type, bounds, or + /// lifetime checking. + pub unsafe fn from_mut_ptr(fd: RawFd, offs: off_t, + buf: *mut c_void, len: usize, + prio: libc::c_int, sigev_notify: SigevNotify, + opcode: LioOpcode) -> AioCb<'a> { + let mut a = AioCb::common_init(fd, prio, sigev_notify); + a.aio_offset = offs; + a.aio_nbytes = len; + a.aio_buf = buf; + a.aio_lio_opcode = opcode as libc::c_int; + + let aiocb = AioCb { aiocb: a, mutable: true, in_progress: false, + keeper: Keeper::none}; + aiocb + } + + /// Constructs a new `AioCb` from a raw pointer + /// + /// * `fd` File descriptor. Required for all aio functions. + /// * `offs` File offset + /// * `buf` Pointer to the memory buffer + /// * `len` Length of the buffer pointed to by `buf` + /// * `prio` If POSIX Prioritized IO is supported, then the operation will + /// be prioritized at the process's priority level minus `prio` + /// * `sigev_notify` Determines how you will be notified of event + /// completion. + /// * `opcode` This field is only used for `lio_listio`. It determines + /// which operation to use for this individual aiocb + /// + /// # Safety + /// + /// Unsafe because using this `AioCb` will cause `libc::aio_write` to + /// dereference a raw pointer, without type, bounds, or lifetime checking. + pub unsafe fn from_ptr(fd: RawFd, offs: off_t, + buf: *const c_void, len: usize, + prio: libc::c_int, sigev_notify: SigevNotify, + opcode: LioOpcode) -> AioCb<'a> { + let mut a = AioCb::common_init(fd, prio, sigev_notify); + a.aio_offset = offs; + a.aio_nbytes = len; + // casting a const ptr to a mutable ptr here is ok, because we set the + // AioCb's mutable field to false + a.aio_buf = buf as *mut c_void; + a.aio_lio_opcode = opcode as libc::c_int; + + let aiocb = AioCb { aiocb: a, mutable: false, in_progress: false, + keeper: Keeper::none}; + aiocb + } + /// Like `from_mut_slice`, but works on constant slices rather than /// mutable slices. /// diff --git a/test/sys/test_aio.rs b/test/sys/test_aio.rs index 1f807585..42e71fdb 100644 --- a/test/sys/test_aio.rs +++ b/test/sys/test_aio.rs @@ -1,4 +1,4 @@ -use libc::c_int; +use libc::{c_int, c_void}; use nix::{Error, Result}; use nix::errno::*; use nix::sys::aio::*; @@ -244,6 +244,36 @@ fn test_read_into_mut_slice() { assert!(rbuf == EXPECT); } +// Tests from_ptr +#[test] +#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] +fn test_read_into_pointer() { + const INITIAL: &'static [u8] = b"abcdef123456"; + let mut rbuf = vec![0; 4]; + const EXPECT: &'static [u8] = b"cdef"; + let mut f = tempfile().unwrap(); + f.write(INITIAL).unwrap(); + { + // Safety: ok because rbuf lives until after poll_aio + let mut aiocb = unsafe { + AioCb::from_mut_ptr( f.as_raw_fd(), + 2, //offset + rbuf.as_mut_ptr() as *mut c_void, + rbuf.len(), + 0, //priority + SigevNotify::SigevNone, + LioOpcode::LIO_NOP) + }; + aiocb.read().unwrap(); + + let err = poll_aio(&mut aiocb); + assert!(err == Ok(())); + assert!(aiocb.aio_return().unwrap() as usize == EXPECT.len()); + } + + assert!(rbuf == EXPECT); +} + // Test reading into an immutable buffer. It should fail // FIXME: This test fails to panic on Linux/musl #[test] @@ -292,6 +322,39 @@ fn test_write() { assert!(rbuf == EXPECT); } +// Tests `AioCb::from_ptr` +#[test] +#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] +fn test_write_into_pointer() { + const INITIAL: &'static [u8] = b"abcdef123456"; + let wbuf = "CDEF".to_string().into_bytes(); + let mut rbuf = Vec::new(); + const EXPECT: &'static [u8] = b"abCDEF123456"; + + let mut f = tempfile().unwrap(); + f.write(INITIAL).unwrap(); + // Safety: ok because aiocb outlives poll_aio + let mut aiocb = unsafe { + AioCb::from_ptr( f.as_raw_fd(), + 2, //offset + wbuf.as_ptr() as *const c_void, + wbuf.len(), + 0, //priority + SigevNotify::SigevNone, + LioOpcode::LIO_NOP) + }; + aiocb.write().unwrap(); + + let err = poll_aio(&mut aiocb); + assert!(err == Ok(())); + assert!(aiocb.aio_return().unwrap() as usize == wbuf.len()); + + f.seek(SeekFrom::Start(0)).unwrap(); + let len = f.read_to_end(&mut rbuf).unwrap(); + assert!(len == EXPECT.len()); + assert!(rbuf == EXPECT); +} + /// `AioCb::write` should not modify the `AioCb` object if libc::aio_write returns /// an error // Skip on Linux, because Linux's AIO implementation can't detect errors |