// AbstractInterruptibleChannel synchronizes invocations of this method // using AbstractInterruptibleChannel.closeLock, and also ensures that this // method is only ever invoked once. Before we get to this method, isOpen // (which is volatile) will have been set to false. // protected void implCloseSelectableChannel() throws IOException { synchronized (stateLock) { isInputOpen = false; isOutputOpen = false; closeImpl(); // Signal native threads, if needed. If a target thread is not // currently blocked in an I/O operation then no harm is done since // the signal handler doesn't actually do anything. // if (readerThread != 0) NativeThread.signal(readerThread); if (writerThread != 0) NativeThread.signal(writerThread); // If this channel is not registered then it's safe to close the fd // immediately since we know at this point that no thread is // blocked in an I/O operation upon the channel and, since the // channel is marked closed, no thread will start another such // operation. If this channel is registered then we don't close // the fd since it might be in use by a selector. In that case // closing this channel caused its keys to be cancelled, so the // last selector to deregister a key for this channel will invoke // kill() to close the fd. // if (!isRegistered()) kill(); } }
protected void implCloseSelectableChannel() throws IOException { synchronized (stateLock) { if (state != ST_KILLED) nd.preClose(fd); ResourceManager.afterUdpClose(); // if member of mulitcast group then invalidate all keys if (registry != null) registry.invalidateAll(); long th; if ((th = readerThread) != 0) NativeThread.signal(th); if ((th = writerThread) != 0) NativeThread.signal(th); if (!isRegistered()) kill(); } }
public long write0(ByteBuffer[] bufs) throws IOException { if (bufs == null) throw new NullPointerException(); synchronized (writeLock) { ensureWriteOpen(); long n = 0; try { begin(); synchronized (stateLock) { if (!isOpen()) return 0; writerThread = NativeThread.current(); } for (; ; ) { n = Net.write(fd, bufs); if ((n == IOStatus.INTERRUPTED) && isOpen()) continue; return IOStatus.normalize(n); } } finally { writerCleanup(); end((n > 0) || (n == IOStatus.UNAVAILABLE)); synchronized (stateLock) { if ((n <= 0) && (!isOutputOpen)) throw new AsynchronousCloseException(); } assert IOStatus.check(n); } } }
private long read0(ByteBuffer[] bufs) throws IOException { if (bufs == null) throw new NullPointerException(); synchronized (readLock) { if (!ensureReadOpen()) return -1; long n = 0; try { begin(); synchronized (stateLock) { if (!isOpen()) return 0; readerThread = NativeThread.current(); } for (; ; ) { n = Net.read(fd, bufs); if ((n == IOStatus.INTERRUPTED) && isOpen()) continue; return IOStatus.normalize(n); } } finally { readerCleanup(); end(n > 0 || (n == IOStatus.UNAVAILABLE)); synchronized (stateLock) { if ((n <= 0) && (!isInputOpen)) return IOStatus.EOF; } assert IOStatus.check(n); } } }
public boolean connect(SocketAddress sa) throws IOException { int trafficClass = 0; // ## Pick up from options int localPort = 0; synchronized (readLock) { synchronized (writeLock) { ensureOpenAndUnconnected(); InetSocketAddress isa = Net.checkAddress(sa); SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort()); synchronized (blockingLock()) { int n = 0; try { try { begin(); synchronized (stateLock) { if (!isOpen()) { return false; } readerThread = NativeThread.current(); } for (; ; ) { InetAddress ia = isa.getAddress(); if (ia.isAnyLocalAddress()) ia = InetAddress.getLocalHost(); n = connectImpl(ia, isa.getPort(), trafficClass); if ((n == IOStatus.INTERRUPTED) && isOpen()) continue; break; } } finally { readerCleanup(); end((n > 0) || (n == IOStatus.UNAVAILABLE)); assert IOStatus.check(n); } } catch (IOException x) { // If an exception was thrown, close the channel after // invoking end() so as to avoid bogus // AsynchronousCloseExceptions close(); throw x; } synchronized (stateLock) { remoteAddress = isa; if (n > 0) { // Connection succeeded; disallow further // invocation state = ST_CONNECTED; return true; } // If nonblocking and no exception then connection // pending; disallow another invocation if (!isBlocking()) state = ST_PENDING; else assert false; } } return false; } } }
public void shutdownOutput() throws IOException { synchronized (stateLock) { if (!isOpen()) throw new ClosedChannelException(); isOutputOpen = false; shutdown(fd, SHUT_WR); if (writerThread != 0) NativeThread.signal(writerThread); } }
public int send(ByteBuffer src, SocketAddress target) throws IOException { if (src == null) throw new NullPointerException(); synchronized (writeLock) { ensureOpen(); InetSocketAddress isa = Net.checkAddress(target); InetAddress ia = isa.getAddress(); if (ia == null) throw new IOException("Target address not resolved"); synchronized (stateLock) { if (!isConnected()) { if (target == null) throw new NullPointerException(); SecurityManager sm = System.getSecurityManager(); if (sm != null) { if (ia.isMulticastAddress()) { sm.checkMulticast(ia); } else { sm.checkConnect(ia.getHostAddress(), isa.getPort()); } } } else { // Connected case; Check address then write if (!target.equals(remoteAddress)) { throw new IllegalArgumentException("Connected address not equal to target address"); } return write(src); } } int n = 0; try { begin(); if (!isOpen()) return 0; writerThread = NativeThread.current(); do { n = send(fd, src, isa); } while ((n == IOStatus.INTERRUPTED) && isOpen()); synchronized (stateLock) { if (isOpen() && (localAddress == null)) { localAddress = Net.localAddress(fd); } } return IOStatus.normalize(n); } finally { writerThread = 0; end((n > 0) || (n == IOStatus.UNAVAILABLE)); assert IOStatus.check(n); } } }
public SocketAddress receive(ByteBuffer dst) throws IOException { if (dst.isReadOnly()) throw new IllegalArgumentException("Read-only buffer"); if (dst == null) throw new NullPointerException(); synchronized (readLock) { ensureOpen(); // Socket was not bound before attempting receive if (localAddress() == null) bind(null); int n = 0; ByteBuffer bb = null; try { begin(); if (!isOpen()) return null; SecurityManager security = System.getSecurityManager(); readerThread = NativeThread.current(); if (isConnected() || (security == null)) { do { n = receive(fd, dst); } while ((n == IOStatus.INTERRUPTED) && isOpen()); if (n == IOStatus.UNAVAILABLE) return null; } else { bb = Util.getTemporaryDirectBuffer(dst.remaining()); for (; ; ) { do { n = receive(fd, bb); } while ((n == IOStatus.INTERRUPTED) && isOpen()); if (n == IOStatus.UNAVAILABLE) return null; InetSocketAddress isa = (InetSocketAddress) sender; try { security.checkAccept(isa.getAddress().getHostAddress(), isa.getPort()); } catch (SecurityException se) { // Ignore packet bb.clear(); n = 0; continue; } bb.flip(); dst.put(bb); break; } } return sender; } finally { if (bb != null) Util.releaseTemporaryDirectBuffer(bb); readerThread = 0; end((n > 0) || (n == IOStatus.UNAVAILABLE)); assert IOStatus.check(n); } } }
// package-private int poll(int events, long timeout) throws IOException { assert Thread.holdsLock(blockingLock()) && !isBlocking(); synchronized (readLock) { int n = 0; try { begin(); synchronized (stateLock) { if (!isOpen()) return 0; readerThread = NativeThread.current(); } n = Net.poll(fd, events, timeout); } finally { readerThread = 0; end(n > 0); } return n; } }
public int write(ByteBuffer buf) throws IOException { if (buf == null) throw new NullPointerException(); synchronized (writeLock) { synchronized (stateLock) { ensureOpen(); if (!isConnected()) throw new NotYetConnectedException(); } int n = 0; try { begin(); if (!isOpen()) return 0; writerThread = NativeThread.current(); do { n = IOUtil.write(fd, buf, -1, nd); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { writerThread = 0; end((n > 0) || (n == IOStatus.UNAVAILABLE)); assert IOStatus.check(n); } } }
public long write(ByteBuffer[] srcs, int offset, int length) throws IOException { if ((offset < 0) || (length < 0) || (offset > srcs.length - length)) throw new IndexOutOfBoundsException(); synchronized (writeLock) { synchronized (stateLock) { ensureOpen(); if (!isConnected()) throw new NotYetConnectedException(); } long n = 0; try { begin(); if (!isOpen()) return 0; writerThread = NativeThread.current(); do { n = IOUtil.write(fd, srcs, offset, length, nd); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { writerThread = 0; end((n > 0) || (n == IOStatus.UNAVAILABLE)); assert IOStatus.check(n); } } }
public boolean finishConnect() throws IOException { synchronized (readLock) { synchronized (writeLock) { synchronized (stateLock) { if (!isOpen()) throw new ClosedChannelException(); if (state == ST_CONNECTED) return true; if (state != ST_PENDING) throw new NoConnectionPendingException(); } int n = 0; try { try { begin(); synchronized (blockingLock()) { synchronized (stateLock) { if (!isOpen()) { return false; } readerThread = NativeThread.current(); } if (!isBlocking()) { for (; ; ) { n = checkConnect(fd, false, readyToConnect); if ((n == IOStatus.INTERRUPTED) && isOpen()) continue; break; } } else { for (; ; ) { n = checkConnect(fd, true, readyToConnect); if (n == 0) { // Loop in case of // spurious notifications continue; } if ((n == IOStatus.INTERRUPTED) && isOpen()) continue; break; } } } } finally { synchronized (stateLock) { readerThread = 0; if (state == ST_KILLPENDING) { kill(); // poll()/getsockopt() does not report // error (throws exception, with n = 0) // on Linux platform after dup2 and // signal-wakeup. Force n to 0 so the // end() can throw appropriate exception n = 0; } } end((n > 0) || (n == IOStatus.UNAVAILABLE)); assert IOStatus.check(n); } } catch (IOException x) { // If an exception was thrown, close the channel after // invoking end() so as to avoid bogus // AsynchronousCloseExceptions close(); throw x; } if (n > 0) { synchronized (stateLock) { state = ST_CONNECTED; } return true; } return false; } } }
public int read(ByteBuffer buf) throws IOException { if (buf == null) throw new NullPointerException(); synchronized (readLock) { if (!ensureReadOpen()) return -1; int n = 0; try { // Set up the interruption machinery; see // AbstractInterruptibleChannel for details // begin(); synchronized (stateLock) { if (!isOpen()) { // Either the current thread is already interrupted, so // begin() closed the channel, or another thread closed the // channel since we checked it a few bytecodes ago. In // either case the value returned here is irrelevant since // the invocation of end() in the finally block will throw // an appropriate exception. // return 0; } // Save this thread so that it can be signalled on those // platforms that require it // readerThread = NativeThread.current(); } // Between the previous test of isOpen() and the return of the // IOUtil.read invocation below, this channel might be closed // or this thread might be interrupted. We rely upon the // implicit synchronization point in the kernel read() call to // make sure that the right thing happens. In either case the // implCloseSelectableChannel method is ultimately invoked in // some other thread, so there are three possibilities: // // - implCloseSelectableChannel() invokes nd.preClose() // before this thread invokes read(), in which case the // read returns immediately with either EOF or an error, // the latter of which will cause an IOException to be // thrown. // // - implCloseSelectableChannel() invokes nd.preClose() after // this thread is blocked in read(). On some operating // systems (e.g., Solaris and Windows) this causes the read // to return immediately with either EOF or an error // indication. // // - implCloseSelectableChannel() invokes nd.preClose() after // this thread is blocked in read() but the operating // system (e.g., Linux) doesn't support preemptive close, // so implCloseSelectableChannel() proceeds to signal this // thread, thereby causing the read to return immediately // with IOStatus.INTERRUPTED. // // In all three cases the invocation of end() in the finally // clause will notice that the channel has been closed and // throw an appropriate exception (AsynchronousCloseException // or ClosedByInterruptException) if necessary. // // *There is A fourth possibility. implCloseSelectableChannel() // invokes nd.preClose(), signals reader/writer thred and quickly // moves on to nd.close() in kill(), which does a real close. // Then a third thread accepts a new connection, opens file or // whatever that causes the released "fd" to be recycled. All // above happens just between our last isOpen() check and the // next kernel read reached, with the recycled "fd". The solution // is to postpone the real kill() if there is a reader or/and // writer thread(s) over there "waiting", leave the cleanup/kill // to the reader or writer thread. (the preClose() still happens // so the connection gets cut off as usual). // // For socket channels there is the additional wrinkle that // asynchronous shutdown works much like asynchronous close, // except that the channel is shutdown rather than completely // closed. This is analogous to the first two cases above, // except that the shutdown operation plays the role of // nd.preClose(). for (; ; ) { n = Net.read(fd, buf); if ((n == IOStatus.INTERRUPTED) && isOpen()) { // The system call was interrupted but the channel // is still open, so retry continue; } return IOStatus.normalize(n); } } finally { readerCleanup(); // Clear reader thread // The end method, which is defined in our superclass // AbstractInterruptibleChannel, resets the interruption // machinery. If its argument is true then it returns // normally; otherwise it checks the interrupt and open state // of this channel and throws an appropriate exception if // necessary. // // So, if we actually managed to do any I/O in the above try // block then we pass true to the end method. We also pass // true if the channel was in non-blocking mode when the I/O // operation was initiated but no data could be transferred; // this prevents spurious exceptions from being thrown in the // rare event that a channel is closed or a thread is // interrupted at the exact moment that a non-blocking I/O // request is made. // end(n > 0 || (n == IOStatus.UNAVAILABLE)); // Extra case for socket channels: Asynchronous shutdown // synchronized (stateLock) { if ((n <= 0) && (!isInputOpen)) return IOStatus.EOF; } assert IOStatus.check(n); } } }