]> git.lizzy.rs Git - rust.git/commitdiff
native: Add some documentation for accept
authorAlex Crichton <alex@alexcrichton.com>
Tue, 15 Jul 2014 18:06:31 +0000 (11:06 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Mon, 25 Aug 2014 00:08:14 +0000 (17:08 -0700)
Document the new code for how close_accept and timeouts are implemented.

src/libnative/io/net.rs

index daa1b25e40775d6b85c835b245a2a0ae9a331fe0..bbfc8aff1b74175721c729cb43e2ce1e859a93e9 100644 (file)
@@ -526,6 +526,20 @@ pub fn fd(&self) -> sock_t { self.inner.listener.fd() }
 
     #[cfg(unix)]
     pub fn native_accept(&mut self) -> IoResult<TcpStream> {
+        // In implementing accept, the two main concerns are dealing with
+        // close_accept() and timeouts. The unix implementation is based on a
+        // nonblocking accept plus a call to select(). Windows ends up having
+        // an entirely separate implementation than unix, which is explained
+        // below.
+        //
+        // To implement timeouts, all blocking is done via select() instead of
+        // accept() by putting the socket in non-blocking mode. Because
+        // select() takes a timeout argument, we just pass through the timeout
+        // to select().
+        //
+        // To implement close_accept(), we have a self-pipe to ourselves which
+        // is passed to select() along with the socket being accepted on. The
+        // self-pipe is never written to unless close_accept() is called.
         let deadline = if self.deadline == 0 {None} else {Some(self.deadline)};
 
         while !self.inner.closed.load(atomics::SeqCst) {
@@ -545,6 +559,26 @@ pub fn native_accept(&mut self) -> IoResult<TcpStream> {
 
     #[cfg(windows)]
     pub fn native_accept(&mut self) -> IoResult<TcpStream> {
+        // Unlink unix, windows cannot invoke `select` on arbitrary file
+        // descriptors like pipes, only sockets. Consequently, windows cannot
+        // use the same implementation as unix for accept() when close_accept()
+        // is considered.
+        //
+        // In order to implement close_accept() and timeouts, windows uses
+        // event handles. An acceptor-specific abort event is created which
+        // will only get set in close_accept(), and it will never be un-set.
+        // Additionally, another acceptor-specific event is associated with the
+        // FD_ACCEPT network event.
+        //
+        // These two events are then passed to WaitForMultipleEvents to see
+        // which one triggers first, and the timeout passed to this function is
+        // the local timeout for the acceptor.
+        //
+        // If the wait times out, then the accept timed out. If the wait
+        // succeeds with the abort event, then we were closed, and if the wait
+        // succeeds otherwise, then we do a nonblocking poll via `accept` to
+        // see if we can accept a connection. The connection is candidate to be
+        // stolen, so we do all of this in a loop as well.
         let events = [self.inner.abort.handle(), self.inner.accept.handle()];
 
         while !self.inner.closed.load(atomics::SeqCst) {