diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2014-07-11 14:29:15 -0700 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2014-08-24 17:08:14 -0700 |
| commit | 110168de2a7b529a7c4839ca1e19c4c42f68be12 (patch) | |
| tree | b590f2a6976d0c44b174c1eb3205a120a8072db0 /src/libstd/io/net/unix.rs | |
| parent | 6d9b219e6f84325ee32c70a29bf782e7ad54ebc8 (diff) | |
| download | rust-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.rs | 95 |
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); + }) } |
