summaryrefslogtreecommitdiff
path: root/src/sys/aio.rs
diff options
context:
space:
mode:
authorAlan Somers <asomers@gmail.com>2017-04-07 23:30:47 -0600
committerAlan Somers <asomers@gmail.com>2017-04-15 20:13:18 -0600
commitd3ad3c775ce55612aa0a754e010899990673661b (patch)
treed82245435de3c965e1df5eeffe48c5658eeac6e9 /src/sys/aio.rs
parent8c47de417e71d59b0248bc3df5886bc7c4410040 (diff)
downloadnix-d3ad3c775ce55612aa0a754e010899990673661b.zip
Add AioCb::from_boxed_slice
The existing AioCb constructors work for simple programs where everything is stored on the stack. But in more complicated programs the borrow checker can't prove that a buffer will outlive the AioCb that references it. Fix this problem by introducting AioCb::from_boxed_slice, which takes a reference-counted buffer. Fixes #575
Diffstat (limited to 'src/sys/aio.rs')
-rw-r--r--src/sys/aio.rs57
1 files changed, 49 insertions, 8 deletions
diff --git a/src/sys/aio.rs b/src/sys/aio.rs
index 13a03b5d..64aee7ca 100644
--- a/src/sys/aio.rs
+++ b/src/sys/aio.rs
@@ -8,6 +8,7 @@ use std::io::Write;
use std::io::stderr;
use std::marker::PhantomData;
use std::mem;
+use std::rc::Rc;
use std::ptr::{null, null_mut};
use sys::signal::*;
use sys::time::TimeSpec;
@@ -61,6 +62,17 @@ pub enum AioCancelStat {
AioAllDone = libc::AIO_ALLDONE,
}
+/// Private type used by nix to keep buffers from Drop'ing while the kernel has
+/// a pointer to them.
+#[derive(Clone, Debug)]
+enum Keeper<'a> {
+ none,
+ /// Keeps a reference to a Boxed slice
+ boxed(Rc<Box<[u8]>>),
+ /// Keeps a reference to a slice
+ phantom(PhantomData<&'a mut [u8]>)
+}
+
/// The basic structure used by all aio functions. Each `aiocb` represents one
/// I/O request.
pub struct AioCb<'a> {
@@ -69,7 +81,8 @@ pub struct AioCb<'a> {
mutable: bool,
/// Could this `AioCb` potentially have any in-kernel state?
in_progress: bool,
- phantom: PhantomData<&'a mut [u8]>
+ /// Used to keep buffers from Drop'ing
+ keeper: Keeper<'a>
}
impl<'a> AioCb<'a> {
@@ -89,7 +102,7 @@ impl<'a> AioCb<'a> {
a.aio_buf = null_mut();
let aiocb = AioCb { aiocb: a, mutable: false, in_progress: false,
- phantom: PhantomData};
+ keeper: Keeper::none};
aiocb
}
@@ -106,17 +119,43 @@ impl<'a> AioCb<'a> {
/// which operation to use for this individual aiocb
pub fn from_mut_slice(fd: RawFd, offs: off_t, buf: &'a mut [u8],
prio: ::c_int, sigev_notify: SigevNotify,
- opcode: LioOpcode) -> AioCb {
+ opcode: LioOpcode) -> AioCb<'a> {
let mut a = AioCb::common_init(fd, prio, sigev_notify);
a.aio_offset = offs;
a.aio_nbytes = buf.len() as size_t;
- // casting an immutable buffer to a mutable pointer looks unsafe, but
- // technically its only unsafe to dereference it, not to create it.
a.aio_buf = buf.as_ptr() as *mut c_void;
a.aio_lio_opcode = opcode as ::c_int;
let aiocb = AioCb { aiocb: a, mutable: true, in_progress: false,
- phantom: PhantomData};
+ keeper: Keeper::phantom(PhantomData)};
+ aiocb
+ }
+
+ /// Constructs a new `AioCb`.
+ ///
+ /// Unlike `from_mut_slice`, this method returns a structure suitable for
+ /// placement on the heap.
+ ///
+ /// * `fd` File descriptor. Required for all aio functions.
+ /// * `offs` File offset
+ /// * `buf` A shared memory buffer on the heap
+ /// * `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
+ pub fn from_boxed_slice(fd: RawFd, offs: off_t, buf: Rc<Box<[u8]>>,
+ prio: ::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 = buf.len() as size_t;
+ a.aio_buf = buf.as_ptr() as *mut c_void;
+ a.aio_lio_opcode = opcode as ::c_int;
+
+ let aiocb = AioCb{ aiocb: a, mutable: true, in_progress: false,
+ keeper: Keeper::boxed(buf)};
aiocb
}
@@ -139,12 +178,15 @@ impl<'a> AioCb<'a> {
let mut a = AioCb::common_init(fd, prio, sigev_notify);
a.aio_offset = offs;
a.aio_nbytes = buf.len() as size_t;
+ // casting an immutable buffer to a mutable pointer looks unsafe,
+ // but technically its only unsafe to dereference it, not to create
+ // it.
a.aio_buf = buf.as_ptr() as *mut c_void;
assert!(opcode != LioOpcode::LIO_READ, "Can't read into an immutable buffer");
a.aio_lio_opcode = opcode as ::c_int;
let aiocb = AioCb { aiocb: a, mutable: false, in_progress: false,
- phantom: PhantomData};
+ keeper: Keeper::none};
aiocb
}
@@ -284,7 +326,6 @@ impl<'a> Debug for AioCb<'a> {
.field("aio_sigevent", &SigEvent::from(&self.aiocb.aio_sigevent))
.field("mutable", &self.mutable)
.field("in_progress", &self.in_progress)
- .field("phantom", &self.phantom)
.finish()
}
}