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