From: Alex Crichton Date: Tue, 15 Jul 2014 18:06:31 +0000 (-0700) Subject: native: Add some documentation for accept X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=c301db20a40d63ee330956a97102c3e566475f75;p=rust.git native: Add some documentation for accept Document the new code for how close_accept and timeouts are implemented. --- 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 @@ pub fn fd(&self) -> sock_t { self.inner.listener.fd() } #[cfg(unix)] pub fn native_accept(&mut self) -> IoResult { + // 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 { #[cfg(windows)] pub fn native_accept(&mut self) -> IoResult { + // 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) {