@@ -2,6 +2,8 @@ use {Error, Errno, Result};
22use std:: os:: unix:: io:: RawFd ;
33use libc:: { c_void, off_t, size_t} ;
44use libc;
5+ use std:: io:: Write ;
6+ use std:: io:: stderr;
57use std:: marker:: PhantomData ;
68use std:: mem;
79use std:: ptr:: { null, null_mut} ;
@@ -59,11 +61,12 @@ pub enum AioCancelStat {
5961
6062/// The basic structure used by all aio functions. Each `aiocb` represents one
6163/// I/O request.
62- #[ repr( C ) ]
6364pub struct AioCb < ' a > {
6465 aiocb : libc:: aiocb ,
6566 /// Tracks whether the buffer pointed to by aiocb.aio_buf is mutable
6667 mutable : bool ,
68+ /// Could this `AioCb` potentially have any in-kernel state?
69+ in_progress : bool ,
6770 phantom : PhantomData < & ' a mut [ u8 ] >
6871}
6972
@@ -83,7 +86,8 @@ impl<'a> AioCb<'a> {
8386 a. aio_nbytes = 0 ;
8487 a. aio_buf = null_mut ( ) ;
8588
86- let aiocb = AioCb { aiocb : a, mutable : false , phantom : PhantomData } ;
89+ let aiocb = AioCb { aiocb : a, mutable : false , in_progress : false ,
90+ phantom : PhantomData } ;
8791 aiocb
8892 }
8993
@@ -109,7 +113,8 @@ impl<'a> AioCb<'a> {
109113 a. aio_buf = buf. as_ptr ( ) as * mut c_void ;
110114 a. aio_lio_opcode = opcode as :: c_int ;
111115
112- let aiocb = AioCb { aiocb : a, mutable : true , phantom : PhantomData } ;
116+ let aiocb = AioCb { aiocb : a, mutable : true , in_progress : false ,
117+ phantom : PhantomData } ;
113118 aiocb
114119 }
115120
@@ -136,7 +141,8 @@ impl<'a> AioCb<'a> {
136141 assert ! ( opcode != LioOpcode :: LIO_READ , "Can't read into an immutable buffer" ) ;
137142 a. aio_lio_opcode = opcode as :: c_int ;
138143
139- let aiocb = AioCb { aiocb : a, mutable : false , phantom : PhantomData } ;
144+ let aiocb = AioCb { aiocb : a, mutable : false , in_progress : false ,
145+ phantom : PhantomData } ;
140146 aiocb
141147 }
142148
@@ -184,13 +190,15 @@ impl<'a> AioCb<'a> {
184190 /// An asynchronous version of `fsync`.
185191 pub fn fsync ( & mut self , mode : AioFsyncMode ) -> Result < ( ) > {
186192 let p: * mut libc:: aiocb = & mut self . aiocb ;
193+ self . in_progress = true ;
187194 Errno :: result ( unsafe { libc:: aio_fsync ( mode as :: c_int , p) } ) . map ( drop)
188195 }
189196
190197 /// Asynchronously reads from a file descriptor into a buffer
191198 pub fn read ( & mut self ) -> Result < ( ) > {
192199 assert ! ( self . mutable, "Can't read into an immutable buffer" ) ;
193200 let p: * mut libc:: aiocb = & mut self . aiocb ;
201+ self . in_progress = true ;
194202 Errno :: result ( unsafe { libc:: aio_read ( p) } ) . map ( drop)
195203 }
196204
@@ -200,12 +208,14 @@ impl<'a> AioCb<'a> {
200208 // Note: this should be just `return`, but that's a reserved word
201209 pub fn aio_return ( & mut self ) -> Result < isize > {
202210 let p: * mut libc:: aiocb = & mut self . aiocb ;
211+ self . in_progress = false ;
203212 Errno :: result ( unsafe { libc:: aio_return ( p) } )
204213 }
205214
206215 /// Asynchronously writes from a buffer to a file descriptor
207216 pub fn write ( & mut self ) -> Result < ( ) > {
208217 let p: * mut libc:: aiocb = & mut self . aiocb ;
218+ self . in_progress = true ;
209219 Errno :: result ( unsafe { libc:: aio_write ( p) } ) . map ( drop)
210220 }
211221
@@ -259,3 +269,27 @@ pub fn lio_listio(mode: LioMode, list: &[&mut AioCb],
259269 libc:: lio_listio ( mode as i32 , p, list. len ( ) as i32 , sigevp)
260270 } ) . map ( drop)
261271}
272+
273+ impl < ' a > Drop for AioCb < ' a > {
274+ /// If the `AioCb` has no remaining state in the kernel, just drop it.
275+ /// Otherwise, collect its error and return values, so as not to leak
276+ /// resources.
277+ fn drop ( & mut self ) {
278+ if self . in_progress {
279+ // Well-written programs should never get here. They should always
280+ // wait for an AioCb to complete before dropping it
281+ let _ = write ! ( stderr( ) , "WARNING: dropped an in-progress AioCb" ) ;
282+ loop {
283+ let ret = aio_suspend ( & [ & self ] , None ) ;
284+ match ret {
285+ Ok ( ( ) ) => break ,
286+ Err ( Error :: Sys ( Errno :: EINVAL ) ) => panic ! (
287+ "Inconsistent AioCb.in_progress value" ) ,
288+ Err ( Error :: Sys ( Errno :: EINTR ) ) => ( ) , // Retry interrupted syscall
289+ _ => panic ! ( "Unexpected aio_suspend return value {:?}" , ret)
290+ } ;
291+ }
292+ let _ = self . aio_return ( ) ;
293+ }
294+ }
295+ }
0 commit comments