src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java
changeset 54754 193a8f1a4f3b
parent 54620 13b67c1420b8
child 55081 dd321e3596c0
child 57358 f0a1d9760c5e
equal deleted inserted replaced
54753:a8535f04b465 54754:193a8f1a4f3b
    44 import java.nio.channels.spi.SelectorProvider;
    44 import java.nio.channels.spi.SelectorProvider;
    45 import java.util.Collections;
    45 import java.util.Collections;
    46 import java.util.HashSet;
    46 import java.util.HashSet;
    47 import java.util.Objects;
    47 import java.util.Objects;
    48 import java.util.Set;
    48 import java.util.Set;
    49 import java.util.concurrent.locks.Condition;
       
    50 import java.util.concurrent.locks.ReentrantLock;
    49 import java.util.concurrent.locks.ReentrantLock;
    51 
    50 
    52 import sun.net.NetHooks;
    51 import sun.net.NetHooks;
    53 import sun.net.ext.ExtendedSocketOptions;
    52 import sun.net.ext.ExtendedSocketOptions;
    54 
    53 
    70     // Lock held by thread currently blocked on this channel
    69     // Lock held by thread currently blocked on this channel
    71     private final ReentrantLock acceptLock = new ReentrantLock();
    70     private final ReentrantLock acceptLock = new ReentrantLock();
    72 
    71 
    73     // Lock held by any thread that modifies the state fields declared below
    72     // Lock held by any thread that modifies the state fields declared below
    74     // DO NOT invoke a blocking I/O operation while holding this lock!
    73     // DO NOT invoke a blocking I/O operation while holding this lock!
    75     private final ReentrantLock stateLock = new ReentrantLock();
    74     private final Object stateLock = new Object();
    76     private final Condition stateCondition = stateLock.newCondition();
       
    77 
    75 
    78     // -- The following fields are protected by stateLock
    76     // -- The following fields are protected by stateLock
    79 
    77 
    80     // Channel state, increases monotonically
    78     // Channel state, increases monotonically
    81     private static final int ST_INUSE = 0;
    79     private static final int ST_INUSE = 0;
    82     private static final int ST_CLOSING = 1;
    80     private static final int ST_CLOSING = 1;
    83     private static final int ST_KILLPENDING = 2;
    81     private static final int ST_CLOSED = 2;
    84     private static final int ST_KILLED = 3;
       
    85     private int state;
    82     private int state;
    86 
    83 
    87     // ID of native thread currently blocked in this channel, for signalling
    84     // ID of native thread currently blocked in this channel, for signalling
    88     private long thread;
    85     private long thread;
    89 
    86 
   110     {
   107     {
   111         super(sp);
   108         super(sp);
   112         this.fd =  fd;
   109         this.fd =  fd;
   113         this.fdVal = IOUtil.fdVal(fd);
   110         this.fdVal = IOUtil.fdVal(fd);
   114         if (bound) {
   111         if (bound) {
   115             stateLock.lock();
   112             synchronized (stateLock) {
   116             try {
       
   117                 localAddress = Net.localAddress(fd);
   113                 localAddress = Net.localAddress(fd);
   118             } finally {
       
   119                 stateLock.unlock();
       
   120             }
   114             }
   121         }
   115         }
   122     }
   116     }
   123 
   117 
   124     // @throws ClosedChannelException if channel is closed
   118     // @throws ClosedChannelException if channel is closed
   127             throw new ClosedChannelException();
   121             throw new ClosedChannelException();
   128     }
   122     }
   129 
   123 
   130     @Override
   124     @Override
   131     public ServerSocket socket() {
   125     public ServerSocket socket() {
   132         stateLock.lock();
   126         synchronized (stateLock) {
   133         try {
       
   134             if (socket == null)
   127             if (socket == null)
   135                 socket = ServerSocketAdaptor.create(this);
   128                 socket = ServerSocketAdaptor.create(this);
   136             return socket;
   129             return socket;
   137         } finally {
       
   138             stateLock.unlock();
       
   139         }
   130         }
   140     }
   131     }
   141 
   132 
   142     @Override
   133     @Override
   143     public SocketAddress getLocalAddress() throws IOException {
   134     public SocketAddress getLocalAddress() throws IOException {
   144         stateLock.lock();
   135         synchronized (stateLock) {
   145         try {
       
   146             ensureOpen();
   136             ensureOpen();
   147             return (localAddress == null)
   137             return (localAddress == null)
   148                     ? null
   138                     ? null
   149                     : Net.getRevealedLocalAddress(localAddress);
   139                     : Net.getRevealedLocalAddress(localAddress);
   150         } finally {
       
   151             stateLock.unlock();
       
   152         }
   140         }
   153     }
   141     }
   154 
   142 
   155     @Override
   143     @Override
   156     public <T> ServerSocketChannel setOption(SocketOption<T> name, T value)
   144     public <T> ServerSocketChannel setOption(SocketOption<T> name, T value)
   157         throws IOException
   145         throws IOException
   158     {
   146     {
   159         Objects.requireNonNull(name);
   147         Objects.requireNonNull(name);
   160         if (!supportedOptions().contains(name))
   148         if (!supportedOptions().contains(name))
   161             throw new UnsupportedOperationException("'" + name + "' not supported");
   149             throw new UnsupportedOperationException("'" + name + "' not supported");
   162         stateLock.lock();
   150         synchronized (stateLock) {
   163         try {
       
   164             ensureOpen();
   151             ensureOpen();
   165 
   152 
   166             if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
   153             if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
   167                 // SO_REUSEADDR emulated when using exclusive bind
   154                 // SO_REUSEADDR emulated when using exclusive bind
   168                 isReuseAddress = (Boolean)value;
   155                 isReuseAddress = (Boolean)value;
   169             } else {
   156             } else {
   170                 // no options that require special handling
   157                 // no options that require special handling
   171                 Net.setSocketOption(fd, Net.UNSPEC, name, value);
   158                 Net.setSocketOption(fd, Net.UNSPEC, name, value);
   172             }
   159             }
   173             return this;
   160             return this;
   174         } finally {
       
   175             stateLock.unlock();
       
   176         }
   161         }
   177     }
   162     }
   178 
   163 
   179     @Override
   164     @Override
   180     @SuppressWarnings("unchecked")
   165     @SuppressWarnings("unchecked")
   183     {
   168     {
   184         Objects.requireNonNull(name);
   169         Objects.requireNonNull(name);
   185         if (!supportedOptions().contains(name))
   170         if (!supportedOptions().contains(name))
   186             throw new UnsupportedOperationException("'" + name + "' not supported");
   171             throw new UnsupportedOperationException("'" + name + "' not supported");
   187 
   172 
   188         stateLock.lock();
   173         synchronized (stateLock) {
   189         try {
       
   190             ensureOpen();
   174             ensureOpen();
   191             if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
   175             if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
   192                 // SO_REUSEADDR emulated when using exclusive bind
   176                 // SO_REUSEADDR emulated when using exclusive bind
   193                 return (T)Boolean.valueOf(isReuseAddress);
   177                 return (T)Boolean.valueOf(isReuseAddress);
   194             }
   178             }
   195             // no options that require special handling
   179             // no options that require special handling
   196             return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
   180             return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
   197         } finally {
       
   198             stateLock.unlock();
       
   199         }
   181         }
   200     }
   182     }
   201 
   183 
   202     private static class DefaultOptionsHolder {
   184     private static class DefaultOptionsHolder {
   203         static final Set<SocketOption<?>> defaultOptions = defaultOptions();
   185         static final Set<SocketOption<?>> defaultOptions = defaultOptions();
   219         return DefaultOptionsHolder.defaultOptions;
   201         return DefaultOptionsHolder.defaultOptions;
   220     }
   202     }
   221 
   203 
   222     @Override
   204     @Override
   223     public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException {
   205     public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException {
   224         stateLock.lock();
   206         synchronized (stateLock) {
   225         try {
       
   226             ensureOpen();
   207             ensureOpen();
   227             if (localAddress != null)
   208             if (localAddress != null)
   228                 throw new AlreadyBoundException();
   209                 throw new AlreadyBoundException();
   229             InetSocketAddress isa = (local == null)
   210             InetSocketAddress isa = (local == null)
   230                                     ? new InetSocketAddress(0)
   211                                     ? new InetSocketAddress(0)
   234                 sm.checkListen(isa.getPort());
   215                 sm.checkListen(isa.getPort());
   235             NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
   216             NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
   236             Net.bind(fd, isa.getAddress(), isa.getPort());
   217             Net.bind(fd, isa.getAddress(), isa.getPort());
   237             Net.listen(fd, backlog < 1 ? 50 : backlog);
   218             Net.listen(fd, backlog < 1 ? 50 : backlog);
   238             localAddress = Net.localAddress(fd);
   219             localAddress = Net.localAddress(fd);
   239         } finally {
       
   240             stateLock.unlock();
       
   241         }
   220         }
   242         return this;
   221         return this;
   243     }
   222     }
   244 
   223 
   245     /**
   224     /**
   249      * @throws NotYetBoundException if the channel's socket has not been bound yet
   228      * @throws NotYetBoundException if the channel's socket has not been bound yet
   250      */
   229      */
   251     private void begin(boolean blocking) throws ClosedChannelException {
   230     private void begin(boolean blocking) throws ClosedChannelException {
   252         if (blocking)
   231         if (blocking)
   253             begin();  // set blocker to close channel if interrupted
   232             begin();  // set blocker to close channel if interrupted
   254         stateLock.lock();
   233         synchronized (stateLock) {
   255         try {
       
   256             ensureOpen();
   234             ensureOpen();
   257             if (localAddress == null)
   235             if (localAddress == null)
   258                 throw new NotYetBoundException();
   236                 throw new NotYetBoundException();
   259             if (blocking)
   237             if (blocking)
   260                 thread = NativeThread.current();
   238                 thread = NativeThread.current();
   261         } finally {
       
   262             stateLock.unlock();
       
   263         }
   239         }
   264     }
   240     }
   265 
   241 
   266     /**
   242     /**
   267      * Marks the end of an I/O operation that may have blocked.
   243      * Marks the end of an I/O operation that may have blocked.
   271      */
   247      */
   272     private void end(boolean blocking, boolean completed)
   248     private void end(boolean blocking, boolean completed)
   273         throws AsynchronousCloseException
   249         throws AsynchronousCloseException
   274     {
   250     {
   275         if (blocking) {
   251         if (blocking) {
   276             stateLock.lock();
   252             synchronized (stateLock) {
   277             try {
       
   278                 thread = 0;
   253                 thread = 0;
   279                 // notify any thread waiting in implCloseSelectableChannel
       
   280                 if (state == ST_CLOSING) {
   254                 if (state == ST_CLOSING) {
   281                     stateCondition.signalAll();
   255                     tryFinishClose();
   282                 }
   256                 }
   283             } finally {
       
   284                 stateLock.unlock();
       
   285             }
   257             }
   286             end(completed);
   258             end(completed);
   287         }
   259         }
   288     }
   260     }
   289 
   261 
   403     /**
   375     /**
   404      * Adjust the blocking mode while holding acceptLock.
   376      * Adjust the blocking mode while holding acceptLock.
   405      */
   377      */
   406     private void lockedConfigureBlocking(boolean block) throws IOException {
   378     private void lockedConfigureBlocking(boolean block) throws IOException {
   407         assert acceptLock.isHeldByCurrentThread();
   379         assert acceptLock.isHeldByCurrentThread();
   408         stateLock.lock();
   380         synchronized (stateLock) {
   409         try {
       
   410             ensureOpen();
   381             ensureOpen();
   411             IOUtil.configureBlocking(fd, block);
   382             IOUtil.configureBlocking(fd, block);
   412         } finally {
   383         }
   413             stateLock.unlock();
   384     }
   414         }
   385 
   415     }
   386     /**
   416 
   387      * Closes the socket if there are no accept in progress and the channel is
   417     /**
   388      * not registered with a Selector.
   418      * Invoked by implCloseChannel to close the channel.
   389      */
   419      *
   390     private boolean tryClose() throws IOException {
   420      * This method waits for outstanding I/O operations to complete. When in
   391         assert Thread.holdsLock(stateLock) && state == ST_CLOSING;
   421      * blocking mode, the socket is pre-closed and the threads in blocking I/O
   392         if ((thread == 0) && !isRegistered()) {
   422      * operations are signalled to ensure that the outstanding I/O operations
   393             state = ST_CLOSED;
   423      * complete quickly.
   394             nd.close(fd);
   424      *
   395             return true;
   425      * The socket is closed by this method when it is not registered with a
   396         } else {
   426      * Selector. Note that a channel configured blocking may be registered with
   397             return false;
   427      * a Selector. This arises when a key is canceled and the channel configured
   398         }
   428      * to blocking mode before the key is flushed from the Selector.
   399     }
   429      */
   400 
   430     @Override
   401     /**
   431     protected void implCloseSelectableChannel() throws IOException {
   402      * Invokes tryClose to attempt to close the socket.
   432         assert !isOpen();
   403      *
   433 
   404      * This method is used for deferred closing by I/O and Selector operations.
   434         boolean interrupted = false;
   405      */
   435         boolean blocking;
   406     private void tryFinishClose() {
   436 
       
   437         // set state to ST_CLOSING
       
   438         stateLock.lock();
       
   439         try {
   407         try {
       
   408             tryClose();
       
   409         } catch (IOException ignore) { }
       
   410     }
       
   411 
       
   412     /**
       
   413      * Closes this channel when configured in blocking mode.
       
   414      *
       
   415      * If there is an accept in progress then the socket is pre-closed and the
       
   416      * accept thread is signalled, in which case the final close is deferred
       
   417      * until the accept aborts.
       
   418      */
       
   419     private void implCloseBlockingMode() throws IOException {
       
   420         synchronized (stateLock) {
   440             assert state < ST_CLOSING;
   421             assert state < ST_CLOSING;
   441             state = ST_CLOSING;
   422             state = ST_CLOSING;
   442             blocking = isBlocking();
   423             if (!tryClose()) {
   443         } finally {
       
   444             stateLock.unlock();
       
   445         }
       
   446 
       
   447         // wait for any outstanding accept to complete
       
   448         if (blocking) {
       
   449             stateLock.lock();
       
   450             try {
       
   451                 assert state == ST_CLOSING;
       
   452                 long th = thread;
   424                 long th = thread;
   453                 if (th != 0) {
   425                 if (th != 0) {
   454                     nd.preClose(fd);
   426                     nd.preClose(fd);
   455                     NativeThread.signal(th);
   427                     NativeThread.signal(th);
   456 
       
   457                     // wait for accept operation to end
       
   458                     while (thread != 0) {
       
   459                         try {
       
   460                             stateCondition.await();
       
   461                         } catch (InterruptedException e) {
       
   462                             interrupted = true;
       
   463                         }
       
   464                     }
       
   465                 }
   428                 }
   466             } finally {
   429             }
   467                 stateLock.unlock();
   430         }
   468             }
   431     }
       
   432 
       
   433     /**
       
   434      * Closes this channel when configured in non-blocking mode.
       
   435      *
       
   436      * If the channel is registered with a Selector then the close is deferred
       
   437      * until the channel is flushed from all Selectors.
       
   438      */
       
   439     private void implCloseNonBlockingMode() throws IOException {
       
   440         synchronized (stateLock) {
       
   441             assert state < ST_CLOSING;
       
   442             state = ST_CLOSING;
       
   443         }
       
   444         // wait for any accept to complete before trying to close
       
   445         acceptLock.lock();
       
   446         acceptLock.unlock();
       
   447         synchronized (stateLock) {
       
   448             if (state == ST_CLOSING) {
       
   449                 tryClose();
       
   450             }
       
   451         }
       
   452     }
       
   453 
       
   454     /**
       
   455      * Invoked by implCloseChannel to close the channel.
       
   456      */
       
   457     @Override
       
   458     protected void implCloseSelectableChannel() throws IOException {
       
   459         assert !isOpen();
       
   460         if (isBlocking()) {
       
   461             implCloseBlockingMode();
   469         } else {
   462         } else {
   470             // non-blocking mode: wait for accept to complete
   463             implCloseNonBlockingMode();
   471             acceptLock.lock();
   464         }
   472             acceptLock.unlock();
   465     }
   473         }
   466 
   474 
   467     @Override
   475         // set state to ST_KILLPENDING
   468     public void kill() {
   476         stateLock.lock();
   469         synchronized (stateLock) {
   477         try {
   470             if (state == ST_CLOSING) {
   478             assert state == ST_CLOSING;
   471                 tryFinishClose();
   479             state = ST_KILLPENDING;
   472             }
   480         } finally {
       
   481             stateLock.unlock();
       
   482         }
       
   483 
       
   484         // close socket if not registered with Selector
       
   485         if (!isRegistered())
       
   486             kill();
       
   487 
       
   488         // restore interrupt status
       
   489         if (interrupted)
       
   490             Thread.currentThread().interrupt();
       
   491     }
       
   492 
       
   493     @Override
       
   494     public void kill() throws IOException {
       
   495         stateLock.lock();
       
   496         try {
       
   497             if (state == ST_KILLPENDING) {
       
   498                 state = ST_KILLED;
       
   499                 nd.close(fd);
       
   500             }
       
   501         } finally {
       
   502             stateLock.unlock();
       
   503         }
   473         }
   504     }
   474     }
   505 
   475 
   506     /**
   476     /**
   507      * Returns true if channel's socket is bound
   477      * Returns true if channel's socket is bound
   508      */
   478      */
   509     boolean isBound() {
   479     boolean isBound() {
   510         stateLock.lock();
   480         synchronized (stateLock) {
   511         try {
       
   512             return localAddress != null;
   481             return localAddress != null;
   513         } finally {
       
   514             stateLock.unlock();
       
   515         }
   482         }
   516     }
   483     }
   517 
   484 
   518     /**
   485     /**
   519      * Returns the local address, or null if not bound
   486      * Returns the local address, or null if not bound
   520      */
   487      */
   521     InetSocketAddress localAddress() {
   488     InetSocketAddress localAddress() {
   522         stateLock.lock();
   489         synchronized (stateLock) {
   523         try {
       
   524             return localAddress;
   490             return localAddress;
   525         } finally {
       
   526             stateLock.unlock();
       
   527         }
   491         }
   528     }
   492     }
   529 
   493 
   530     /**
   494     /**
   531      * Translates native poll revent set into a ready operation set
   495      * Translates native poll revent set into a ready operation set
   587         sb.append(this.getClass().getName());
   551         sb.append(this.getClass().getName());
   588         sb.append('[');
   552         sb.append('[');
   589         if (!isOpen()) {
   553         if (!isOpen()) {
   590             sb.append("closed");
   554             sb.append("closed");
   591         } else {
   555         } else {
   592             stateLock.lock();
   556             synchronized (stateLock) {
   593             try {
       
   594                 InetSocketAddress addr = localAddress;
   557                 InetSocketAddress addr = localAddress;
   595                 if (addr == null) {
   558                 if (addr == null) {
   596                     sb.append("unbound");
   559                     sb.append("unbound");
   597                 } else {
   560                 } else {
   598                     sb.append(Net.getRevealedLocalAddressAsString(addr));
   561                     sb.append(Net.getRevealedLocalAddressAsString(addr));
   599                 }
   562                 }
   600             } finally {
       
   601                 stateLock.unlock();
       
   602             }
   563             }
   603         }
   564         }
   604         sb.append(']');
   565         sb.append(']');
   605         return sb.toString();
   566         return sb.toString();
   606     }
   567     }