@@ -526,6 +526,20 @@ impl TcpAcceptor {
526
526
527
527
#[ cfg( unix) ]
528
528
pub fn native_accept ( & mut self ) -> IoResult < TcpStream > {
529
+ // In implementing accept, the two main concerns are dealing with
530
+ // close_accept() and timeouts. The unix implementation is based on a
531
+ // nonblocking accept plus a call to select(). Windows ends up having
532
+ // an entirely separate implementation than unix, which is explained
533
+ // below.
534
+ //
535
+ // To implement timeouts, all blocking is done via select() instead of
536
+ // accept() by putting the socket in non-blocking mode. Because
537
+ // select() takes a timeout argument, we just pass through the timeout
538
+ // to select().
539
+ //
540
+ // To implement close_accept(), we have a self-pipe to ourselves which
541
+ // is passed to select() along with the socket being accepted on. The
542
+ // self-pipe is never written to unless close_accept() is called.
529
543
let deadline = if self . deadline == 0 { None } else { Some ( self . deadline ) } ;
530
544
531
545
while !self . inner . closed . load ( atomics:: SeqCst ) {
@@ -545,6 +559,26 @@ impl TcpAcceptor {
545
559
546
560
#[ cfg( windows) ]
547
561
pub fn native_accept ( & mut self ) -> IoResult < TcpStream > {
562
+ // Unlink unix, windows cannot invoke `select` on arbitrary file
563
+ // descriptors like pipes, only sockets. Consequently, windows cannot
564
+ // use the same implementation as unix for accept() when close_accept()
565
+ // is considered.
566
+ //
567
+ // In order to implement close_accept() and timeouts, windows uses
568
+ // event handles. An acceptor-specific abort event is created which
569
+ // will only get set in close_accept(), and it will never be un-set.
570
+ // Additionally, another acceptor-specific event is associated with the
571
+ // FD_ACCEPT network event.
572
+ //
573
+ // These two events are then passed to WaitForMultipleEvents to see
574
+ // which one triggers first, and the timeout passed to this function is
575
+ // the local timeout for the acceptor.
576
+ //
577
+ // If the wait times out, then the accept timed out. If the wait
578
+ // succeeds with the abort event, then we were closed, and if the wait
579
+ // succeeds otherwise, then we do a nonblocking poll via `accept` to
580
+ // see if we can accept a connection. The connection is candidate to be
581
+ // stolen, so we do all of this in a loop as well.
548
582
let events = [ self . inner . abort . handle ( ) , self . inner . accept . handle ( ) ] ;
549
583
550
584
while !self . inner . closed . load ( atomics:: SeqCst ) {
0 commit comments