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 |
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(); |
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 |