@@ -169,6 +169,27 @@ unsafe fn pipe(name: *u16, init: bool) -> libc::HANDLE {
169
169
)
170
170
}
171
171
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
+
172
193
////////////////////////////////////////////////////////////////////////////////
173
194
// Unix Streams
174
195
////////////////////////////////////////////////////////////////////////////////
@@ -177,6 +198,8 @@ pub struct UnixStream {
177
198
inner : UnsafeArc < Inner > ,
178
199
write : Option < Event > ,
179
200
read : Option < Event > ,
201
+ read_deadline : u64 ,
202
+ write_deadline : u64 ,
180
203
}
181
204
182
205
impl UnixStream {
@@ -253,6 +276,8 @@ impl UnixStream {
253
276
inner : UnsafeArc :: new ( inner) ,
254
277
read : None ,
255
278
write : None ,
279
+ read_deadline : 0 ,
280
+ write_deadline : 0 ,
256
281
} )
257
282
}
258
283
}
@@ -358,6 +383,10 @@ impl rtio::RtioPipe for UnixStream {
358
383
// sleep.
359
384
drop ( guard) ;
360
385
loop {
386
+ // Process a timeout if one is pending
387
+ let succeeded = await ( self . handle ( ) , self . read_deadline ,
388
+ & mut overlapped) ;
389
+
361
390
let ret = unsafe {
362
391
libc:: GetOverlappedResult ( self . handle ( ) ,
363
392
& mut overlapped,
@@ -373,6 +402,9 @@ impl rtio::RtioPipe for UnixStream {
373
402
374
403
// If the reading half is now closed, then we're done. If we woke up
375
404
// because the writing half was closed, keep trying.
405
+ if !succeeded {
406
+ return Err ( io:: standard_error ( io:: TimedOut ) )
407
+ }
376
408
if self . read_closed ( ) {
377
409
return Err ( io:: standard_error ( io:: EndOfFile ) )
378
410
}
@@ -408,12 +440,16 @@ impl rtio::RtioPipe for UnixStream {
408
440
& mut bytes_written,
409
441
& mut overlapped)
410
442
} ;
443
+ let err = os:: errno ( ) ;
411
444
drop ( guard) ;
412
445
413
446
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 ) ) ;
416
449
}
450
+ // Process a timeout if one is pending
451
+ let succeeded = await ( self . handle ( ) , self . write_deadline ,
452
+ & mut overlapped) ;
417
453
let ret = unsafe {
418
454
libc:: GetOverlappedResult ( self . handle ( ) ,
419
455
& mut overlapped,
@@ -427,10 +463,22 @@ impl rtio::RtioPipe for UnixStream {
427
463
if os:: errno ( ) != libc:: ERROR_OPERATION_ABORTED as uint {
428
464
return Err ( super :: last_error ( ) )
429
465
}
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
+ }
430
478
if self . write_closed ( ) {
431
479
return Err ( io:: standard_error ( io:: BrokenPipe ) )
432
480
}
433
- continue ; // retry
481
+ continue // retry
434
482
}
435
483
}
436
484
offset += bytes_written as uint ;
@@ -443,6 +491,8 @@ impl rtio::RtioPipe for UnixStream {
443
491
inner : self . inner . clone ( ) ,
444
492
read : None ,
445
493
write : None ,
494
+ read_deadline : 0 ,
495
+ write_deadline : 0 ,
446
496
} as Box < rtio:: RtioPipe : Send >
447
497
}
448
498
@@ -475,6 +525,18 @@ impl rtio::RtioPipe for UnixStream {
475
525
unsafe { ( * self . inner . get ( ) ) . write_closed . store ( true , atomics:: SeqCst ) }
476
526
self . cancel_io ( )
477
527
}
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
+ }
478
540
}
479
541
480
542
////////////////////////////////////////////////////////////////////////////////
@@ -577,22 +639,8 @@ impl UnixAcceptor {
577
639
let mut err = unsafe { libc:: GetLastError ( ) } ;
578
640
579
641
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) ;
596
644
597
645
// This will block until the overlapped I/O is completed. The
598
646
// timeout was previously handled, so this will either block in
@@ -638,6 +686,8 @@ impl UnixAcceptor {
638
686
inner : UnsafeArc :: new ( Inner :: new ( handle) ) ,
639
687
read : None ,
640
688
write : None ,
689
+ read_deadline : 0 ,
690
+ write_deadline : 0 ,
641
691
} )
642
692
}
643
693
}
0 commit comments