@@ -169,23 +169,30 @@ unsafe fn pipe(name: *const u16, init: bool) -> libc::HANDLE {
169169}
170170
171171pub fn await ( handle : libc:: HANDLE , deadline : u64 ,
172- overlapped : & mut libc:: OVERLAPPED ) -> bool {
173- if deadline == 0 { return true }
172+ events : & [ libc:: HANDLE ] ) -> IoResult < uint > {
173+ use libc :: consts :: os :: extra :: { WAIT_FAILED , WAIT_TIMEOUT , WAIT_OBJECT_0 } ;
174174
175175 // If we've got a timeout, use WaitForSingleObject in tandem with CancelIo
176176 // to figure out if we should indeed get the result.
177- let now = :: io:: timer:: now ( ) ;
178- let timeout = deadline < now || unsafe {
179- let ms = ( deadline - now) as libc:: DWORD ;
180- let r = libc:: WaitForSingleObject ( overlapped. hEvent ,
181- ms) ;
182- r != libc:: WAIT_OBJECT_0
183- } ;
184- if timeout {
185- unsafe { let _ = c:: CancelIo ( handle) ; }
186- false
177+ let ms = if deadline == 0 {
178+ libc:: INFINITE as u64
187179 } else {
188- true
180+ let now = :: io:: timer:: now ( ) ;
181+ if deadline < now { 0 } else { deadline - now}
182+ } ;
183+ let ret = unsafe {
184+ c:: WaitForMultipleObjects ( events. len ( ) as libc:: DWORD ,
185+ events. as_ptr ( ) ,
186+ libc:: FALSE ,
187+ ms as libc:: DWORD )
188+ } ;
189+ match ret {
190+ WAIT_FAILED => Err ( super :: last_error ( ) ) ,
191+ WAIT_TIMEOUT => unsafe {
192+ let _ = c:: CancelIo ( handle) ;
193+ Err ( util:: timeout ( "operation timed out" ) )
194+ } ,
195+ n => Ok ( ( n - WAIT_OBJECT_0 ) as uint )
189196 }
190197}
191198
@@ -390,8 +397,8 @@ impl rtio::RtioPipe for UnixStream {
390397 drop ( guard) ;
391398 loop {
392399 // Process a timeout if one is pending
393- let succeeded = await ( self . handle ( ) , self . read_deadline ,
394- & mut overlapped) ;
400+ let wait_succeeded = await ( self . handle ( ) , self . read_deadline ,
401+ [ overlapped. hEvent ] ) ;
395402
396403 let ret = unsafe {
397404 libc:: GetOverlappedResult ( self . handle ( ) ,
@@ -408,7 +415,7 @@ impl rtio::RtioPipe for UnixStream {
408415
409416 // If the reading half is now closed, then we're done. If we woke up
410417 // because the writing half was closed, keep trying.
411- if !succeeded {
418+ if wait_succeeded . is_err ( ) {
412419 return Err ( util:: timeout ( "read timed out" ) )
413420 }
414421 if self . read_closed ( ) {
@@ -458,8 +465,8 @@ impl rtio::RtioPipe for UnixStream {
458465 } )
459466 }
460467 // Process a timeout if one is pending
461- let succeeded = await ( self . handle ( ) , self . write_deadline ,
462- & mut overlapped) ;
468+ let wait_succeeded = await ( self . handle ( ) , self . write_deadline ,
469+ [ overlapped. hEvent ] ) ;
463470 let ret = unsafe {
464471 libc:: GetOverlappedResult ( self . handle ( ) ,
465472 & mut overlapped,
@@ -473,7 +480,7 @@ impl rtio::RtioPipe for UnixStream {
473480 if os:: errno ( ) != libc:: ERROR_OPERATION_ABORTED as uint {
474481 return Err ( super :: last_error ( ) )
475482 }
476- if !succeeded {
483+ if !wait_succeeded . is_ok ( ) {
477484 let amt = offset + bytes_written as uint ;
478485 return if amt > 0 {
479486 Err ( IoError {
@@ -577,6 +584,10 @@ impl UnixListener {
577584 listener : self ,
578585 event : try!( Event :: new ( true , false ) ) ,
579586 deadline : 0 ,
587+ inner : Arc :: new ( AcceptorState {
588+ abort : try!( Event :: new ( true , false ) ) ,
589+ closed : atomic:: AtomicBool :: new ( false ) ,
590+ } ) ,
580591 } )
581592 }
582593}
@@ -597,11 +608,17 @@ impl rtio::RtioUnixListener for UnixListener {
597608}
598609
599610pub struct UnixAcceptor {
611+ inner : Arc < AcceptorState > ,
600612 listener : UnixListener ,
601613 event : Event ,
602614 deadline : u64 ,
603615}
604616
617+ struct AcceptorState {
618+ abort : Event ,
619+ closed : atomic:: AtomicBool ,
620+ }
621+
605622impl UnixAcceptor {
606623 pub fn native_accept ( & mut self ) -> IoResult < UnixStream > {
607624 // This function has some funky implementation details when working with
@@ -638,6 +655,10 @@ impl UnixAcceptor {
638655 // using the original server pipe.
639656 let handle = self . listener . handle ;
640657
658+ // If we've had an artifical call to close_accept, be sure to never
659+ // proceed in accepting new clients in the future
660+ if self . inner . closed . load ( atomic:: SeqCst ) { return Err ( util:: eof ( ) ) }
661+
641662 let name = try!( to_utf16 ( & self . listener . name ) ) ;
642663
643664 // Once we've got a "server handle", we need to wait for a client to
@@ -652,7 +673,9 @@ impl UnixAcceptor {
652673
653674 if err == libc:: ERROR_IO_PENDING as libc:: DWORD {
654675 // Process a timeout if one is pending
655- let _ = await ( handle, self . deadline , & mut overlapped) ;
676+ let wait_succeeded = await ( handle, self . deadline ,
677+ [ self . inner . abort . handle ( ) ,
678+ overlapped. hEvent ] ) ;
656679
657680 // This will block until the overlapped I/O is completed. The
658681 // timeout was previously handled, so this will either block in
@@ -665,7 +688,11 @@ impl UnixAcceptor {
665688 libc:: TRUE )
666689 } ;
667690 if ret == 0 {
668- err = unsafe { libc:: GetLastError ( ) } ;
691+ if wait_succeeded. is_ok ( ) {
692+ err = unsafe { libc:: GetLastError ( ) } ;
693+ } else {
694+ return Err ( util:: timeout ( "accept timed out" ) )
695+ }
669696 } else {
670697 // we succeeded, bypass the check below
671698 err = libc:: ERROR_PIPE_CONNECTED as libc:: DWORD ;
@@ -711,11 +738,32 @@ impl rtio::RtioUnixAcceptor for UnixAcceptor {
711738 }
712739
713740 fn clone ( & self ) -> Box < rtio:: RtioUnixAcceptor + Send > {
714- fail ! ( )
741+ let name = to_utf16 ( & self . listener . name ) . ok ( ) . unwrap ( ) ;
742+ box UnixAcceptor {
743+ inner : self . inner . clone ( ) ,
744+ event : Event :: new ( true , false ) . ok ( ) . unwrap ( ) ,
745+ deadline : 0 ,
746+ listener : UnixListener {
747+ name : self . listener . name . clone ( ) ,
748+ handle : unsafe {
749+ let p = pipe ( name. as_ptr ( ) , false ) ;
750+ assert ! ( p != libc:: INVALID_HANDLE_VALUE as libc:: HANDLE ) ;
751+ p
752+ } ,
753+ } ,
754+ } as Box < rtio:: RtioUnixAcceptor + Send >
715755 }
716756
717757 fn close_accept ( & mut self ) -> IoResult < ( ) > {
718- fail ! ( )
758+ self . inner . closed . store ( true , atomic:: SeqCst ) ;
759+ let ret = unsafe {
760+ c:: SetEvent ( self . inner . abort . handle ( ) )
761+ } ;
762+ if ret == 0 {
763+ Err ( super :: last_error ( ) )
764+ } else {
765+ Ok ( ( ) )
766+ }
719767 }
720768}
721769
0 commit comments