@@ -526,6 +526,20 @@ impl TcpAcceptor {
526526
527527 #[ cfg( unix) ]
528528 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.
529543 let deadline = if self . deadline == 0 { None } else { Some ( self . deadline ) } ;
530544
531545 while !self . inner . closed . load ( atomics:: SeqCst ) {
@@ -545,6 +559,26 @@ impl TcpAcceptor {
545559
546560 #[ cfg( windows) ]
547561 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.
548582 let events = [ self . inner . abort . handle ( ) , self . inner . accept . handle ( ) ] ;
549583
550584 while !self . inner . closed . load ( atomics:: SeqCst ) {
0 commit comments