about summary refs log tree commit diff
path: root/src/libstd/io/net/unix.rs
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-07-11 14:29:15 -0700
committerAlex Crichton <alex@alexcrichton.com>2014-08-24 17:08:14 -0700
commit110168de2a7b529a7c4839ca1e19c4c42f68be12 (patch)
treeb590f2a6976d0c44b174c1eb3205a120a8072db0 /src/libstd/io/net/unix.rs
parent6d9b219e6f84325ee32c70a29bf782e7ad54ebc8 (diff)
downloadrust-110168de2a7b529a7c4839ca1e19c4c42f68be12.tar.gz
rust-110168de2a7b529a7c4839ca1e19c4c42f68be12.zip
native: Implement clone/close_accept for unix
This commits implements {Tcp,Unix}Acceptor::{clone,close_accept} methods for
unix. A windows implementation is coming in a later commit.

The clone implementation is based on atomic reference counting (as with all
other clones), and the close_accept implementation is based on selecting on a
self-pipe which signals that a close has been seen.
Diffstat (limited to 'src/libstd/io/net/unix.rs')
-rw-r--r--src/libstd/io/net/unix.rs95
1 files changed, 95 insertions, 0 deletions
diff --git a/src/libstd/io/net/unix.rs b/src/libstd/io/net/unix.rs
index eb251075418..74f024a844e 100644
--- a/src/libstd/io/net/unix.rs
+++ b/src/libstd/io/net/unix.rs
@@ -212,6 +212,15 @@ impl UnixAcceptor {
     pub fn set_timeout(&mut self, timeout_ms: Option<u64>) {
         self.obj.set_timeout(timeout_ms)
     }
+
+    /// Closes the accepting capabilities of this acceptor.
+    ///
+    /// This function has the same semantics as `TcpAcceptor::close_accept`, and
+    /// more information can be found in that documentation.
+    #[experimental]
+    pub fn close_accept(&mut self) -> IoResult<()> {
+        self.obj.close_accept().map_err(IoError::from_rtio_error)
+    }
 }
 
 impl Acceptor<UnixStream> for UnixAcceptor {
@@ -222,6 +231,25 @@ impl Acceptor<UnixStream> for UnixAcceptor {
     }
 }
 
+impl Clone for UnixAcceptor {
+    /// Creates a new handle to this unix acceptor, allowing for simultaneous
+    /// accepts.
+    ///
+    /// The underlying unix acceptor will not be closed until all handles to the
+    /// acceptor have been deallocated. Incoming connections will be received on
+    /// at most once acceptor, the same connection will not be accepted twice.
+    ///
+    /// The `close_accept` method will shut down *all* acceptors cloned from the
+    /// same original acceptor, whereas the `set_timeout` method only affects
+    /// the selector that it is called on.
+    ///
+    /// This function is useful for creating a handle to invoke `close_accept`
+    /// on to wake up any other task blocked in `accept`.
+    fn clone(&self) -> UnixAcceptor {
+        UnixAcceptor { obj: self.obj.clone() }
+    }
+}
+
 #[cfg(test)]
 #[allow(experimental)]
 mod tests {
@@ -702,4 +730,71 @@ mod tests {
 
         rx2.recv();
     })
+
+    iotest!(fn clone_accept_smoke() {
+        let addr = next_test_unix();
+        let l = UnixListener::bind(&addr);
+        let mut a = l.listen().unwrap();
+        let mut a2 = a.clone();
+
+        let addr2 = addr.clone();
+        spawn(proc() {
+            let _ = UnixStream::connect(&addr2);
+        });
+        spawn(proc() {
+            let _ = UnixStream::connect(&addr);
+        });
+
+        assert!(a.accept().is_ok());
+        assert!(a2.accept().is_ok());
+    })
+
+    iotest!(fn clone_accept_concurrent() {
+        let addr = next_test_unix();
+        let l = UnixListener::bind(&addr);
+        let a = l.listen().unwrap();
+        let a2 = a.clone();
+
+        let (tx, rx) = channel();
+        let tx2 = tx.clone();
+
+        spawn(proc() { let mut a = a; tx.send(a.accept()) });
+        spawn(proc() { let mut a = a2; tx2.send(a.accept()) });
+
+        let addr2 = addr.clone();
+        spawn(proc() {
+            let _ = UnixStream::connect(&addr2);
+        });
+        spawn(proc() {
+            let _ = UnixStream::connect(&addr);
+        });
+
+        assert!(rx.recv().is_ok());
+        assert!(rx.recv().is_ok());
+    })
+
+    iotest!(fn close_accept_smoke() {
+        let addr = next_test_unix();
+        let l = UnixListener::bind(&addr);
+        let mut a = l.listen().unwrap();
+
+        a.close_accept().unwrap();
+        assert_eq!(a.accept().err().unwrap().kind, EndOfFile);
+    })
+
+    iotest!(fn close_accept_concurrent() {
+        let addr = next_test_unix();
+        let l = UnixListener::bind(&addr);
+        let a = l.listen().unwrap();
+        let mut a2 = a.clone();
+
+        let (tx, rx) = channel();
+        spawn(proc() {
+            let mut a = a;
+            tx.send(a.accept());
+        });
+        a2.close_accept().unwrap();
+
+        assert_eq!(rx.recv().err().unwrap().kind, EndOfFile);
+    })
 }