@@ -169,6 +169,27 @@ unsafe fn pipe(name: *u16, init: bool) -> libc::HANDLE {
169169 )
170170}
171171
172+ pub fn await ( handle : libc:: HANDLE , deadline : u64 ,
173+ overlapped : & mut libc:: OVERLAPPED ) -> bool {
174+ if deadline == 0 { return true }
175+
176+ // If we've got a timeout, use WaitForSingleObject in tandem with CancelIo
177+ // to figure out if we should indeed get the result.
178+ let now = :: io:: timer:: now ( ) ;
179+ let timeout = deadline < now || unsafe {
180+ let ms = ( deadline - now) as libc:: DWORD ;
181+ let r = libc:: WaitForSingleObject ( overlapped. hEvent ,
182+ ms) ;
183+ r != libc:: WAIT_OBJECT_0
184+ } ;
185+ if timeout {
186+ unsafe { let _ = c:: CancelIo ( handle) ; }
187+ false
188+ } else {
189+ true
190+ }
191+ }
192+
172193////////////////////////////////////////////////////////////////////////////////
173194// Unix Streams
174195////////////////////////////////////////////////////////////////////////////////
@@ -177,6 +198,8 @@ pub struct UnixStream {
177198 inner : UnsafeArc < Inner > ,
178199 write : Option < Event > ,
179200 read : Option < Event > ,
201+ read_deadline : u64 ,
202+ write_deadline : u64 ,
180203}
181204
182205impl UnixStream {
@@ -253,6 +276,8 @@ impl UnixStream {
253276 inner : UnsafeArc :: new ( inner) ,
254277 read : None ,
255278 write : None ,
279+ read_deadline : 0 ,
280+ write_deadline : 0 ,
256281 } )
257282 }
258283 }
@@ -358,6 +383,10 @@ impl rtio::RtioPipe for UnixStream {
358383 // sleep.
359384 drop ( guard) ;
360385 loop {
386+ // Process a timeout if one is pending
387+ let succeeded = await ( self . handle ( ) , self . read_deadline ,
388+ & mut overlapped) ;
389+
361390 let ret = unsafe {
362391 libc:: GetOverlappedResult ( self . handle ( ) ,
363392 & mut overlapped,
@@ -373,6 +402,9 @@ impl rtio::RtioPipe for UnixStream {
373402
374403 // If the reading half is now closed, then we're done. If we woke up
375404 // because the writing half was closed, keep trying.
405+ if !succeeded {
406+ return Err ( io:: standard_error ( io:: TimedOut ) )
407+ }
376408 if self . read_closed ( ) {
377409 return Err ( io:: standard_error ( io:: EndOfFile ) )
378410 }
@@ -408,12 +440,16 @@ impl rtio::RtioPipe for UnixStream {
408440 & mut bytes_written,
409441 & mut overlapped)
410442 } ;
443+ let err = os:: errno ( ) ;
411444 drop ( guard) ;
412445
413446 if ret == 0 {
414- if os :: errno ( ) != libc:: ERROR_IO_PENDING as uint {
415- return Err ( super :: last_error ( ) )
447+ if err != libc:: ERROR_IO_PENDING as uint {
448+ return Err ( io :: IoError :: from_errno ( err , true ) ) ;
416449 }
450+ // Process a timeout if one is pending
451+ let succeeded = await ( self . handle ( ) , self . write_deadline ,
452+ & mut overlapped) ;
417453 let ret = unsafe {
418454 libc:: GetOverlappedResult ( self . handle ( ) ,
419455 & mut overlapped,
@@ -427,10 +463,22 @@ impl rtio::RtioPipe for UnixStream {
427463 if os:: errno ( ) != libc:: ERROR_OPERATION_ABORTED as uint {
428464 return Err ( super :: last_error ( ) )
429465 }
466+ if !succeeded {
467+ let amt = offset + bytes_written as uint ;
468+ return if amt > 0 {
469+ Err ( io:: IoError {
470+ kind : io:: ShortWrite ( amt) ,
471+ desc : "short write during write" ,
472+ detail : None ,
473+ } )
474+ } else {
475+ Err ( util:: timeout ( "write timed out" ) )
476+ }
477+ }
430478 if self . write_closed ( ) {
431479 return Err ( io:: standard_error ( io:: BrokenPipe ) )
432480 }
433- continue ; // retry
481+ continue // retry
434482 }
435483 }
436484 offset += bytes_written as uint ;
@@ -443,6 +491,8 @@ impl rtio::RtioPipe for UnixStream {
443491 inner : self . inner . clone ( ) ,
444492 read : None ,
445493 write : None ,
494+ read_deadline : 0 ,
495+ write_deadline : 0 ,
446496 } as Box < rtio:: RtioPipe : Send >
447497 }
448498
@@ -475,6 +525,18 @@ impl rtio::RtioPipe for UnixStream {
475525 unsafe { ( * self . inner . get ( ) ) . write_closed . store ( true , atomics:: SeqCst ) }
476526 self . cancel_io ( )
477527 }
528+
529+ fn set_timeout ( & mut self , timeout : Option < u64 > ) {
530+ let deadline = timeout. map ( |a| :: io:: timer:: now ( ) + a) . unwrap_or ( 0 ) ;
531+ self . read_deadline = deadline;
532+ self . write_deadline = deadline;
533+ }
534+ fn set_read_timeout ( & mut self , timeout : Option < u64 > ) {
535+ self . read_deadline = timeout. map ( |a| :: io:: timer:: now ( ) + a) . unwrap_or ( 0 ) ;
536+ }
537+ fn set_write_timeout ( & mut self , timeout : Option < u64 > ) {
538+ self . write_deadline = timeout. map ( |a| :: io:: timer:: now ( ) + a) . unwrap_or ( 0 ) ;
539+ }
478540}
479541
480542////////////////////////////////////////////////////////////////////////////////
@@ -577,22 +639,8 @@ impl UnixAcceptor {
577639 let mut err = unsafe { libc:: GetLastError ( ) } ;
578640
579641 if err == libc:: ERROR_IO_PENDING as libc:: DWORD {
580- // If we've got a timeout, use WaitForSingleObject in tandem
581- // with CancelIo to figure out if we should indeed get the
582- // result.
583- if self . deadline != 0 {
584- let now = :: io:: timer:: now ( ) ;
585- let timeout = self . deadline < now || unsafe {
586- let ms = ( self . deadline - now) as libc:: DWORD ;
587- let r = libc:: WaitForSingleObject ( overlapped. hEvent ,
588- ms) ;
589- r != libc:: WAIT_OBJECT_0
590- } ;
591- if timeout {
592- unsafe { let _ = c:: CancelIo ( handle) ; }
593- return Err ( util:: timeout ( "accept timed out" ) )
594- }
595- }
642+ // Process a timeout if one is pending
643+ let _ = await ( handle, self . deadline , & mut overlapped) ;
596644
597645 // This will block until the overlapped I/O is completed. The
598646 // timeout was previously handled, so this will either block in
@@ -638,6 +686,8 @@ impl UnixAcceptor {
638686 inner : UnsafeArc :: new ( Inner :: new ( handle) ) ,
639687 read : None ,
640688 write : None ,
689+ read_deadline : 0 ,
690+ write_deadline : 0 ,
641691 } )
642692 }
643693}
0 commit comments