about summary refs log tree commit diff
path: root/src/libnative
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-07-15 11:06:31 -0700
committerAlex Crichton <alex@alexcrichton.com>2014-08-24 17:08:14 -0700
commitc301db20a40d63ee330956a97102c3e566475f75 (patch)
treedd45dcb51a7f073c2b5831d90838449002220056 /src/libnative
parent7441d4f3f33b4cc21912ff9a3b495f62abc3362e (diff)
downloadrust-c301db20a40d63ee330956a97102c3e566475f75.tar.gz
rust-c301db20a40d63ee330956a97102c3e566475f75.zip
native: Add some documentation for accept
Document the new code for how close_accept and timeouts are implemented.
Diffstat (limited to 'src/libnative')
-rw-r--r--src/libnative/io/net.rs34
1 files changed, 34 insertions, 0 deletions
diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs
index daa1b25e407..bbfc8aff1b7 100644
--- a/src/libnative/io/net.rs
+++ b/src/libnative/io/net.rs
@@ -526,6 +526,20 @@ impl TcpAcceptor {
 
     #[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 @@ impl TcpAcceptor {
 
     #[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) {