| author | alanb |
| Mon May 09 18:45:33 2011 +0100 (12 months ago) | |
| changeset 4216 | dc497a55daa1 |
| parent 3261 | a06412e13bf7 |
| permissions | -rw-r--r-- |
1 /*
2 * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package sun.nio.ch;
27
28 import java.io.FileDescriptor;
29 import java.io.IOException;
30 import java.net.*;
31 import java.nio.ByteBuffer;
32 import java.nio.channels.*;
33 import java.nio.channels.spi.*;
34 import java.util.*;
35 import sun.net.NetHooks;
36
37
38 /**
39 * An implementation of SocketChannels
40 */
41
42 class SocketChannelImpl
43 extends SocketChannel
44 implements SelChImpl
45 {
46
47 // Used to make native read and write calls
48 private static NativeDispatcher nd;
49
50 // Our file descriptor object
51 private final FileDescriptor fd;
52
53 // fd value needed for dev/poll. This value will remain valid
54 // even after the value in the file descriptor object has been set to -1
55 private final int fdVal;
56
57 // IDs of native threads doing reads and writes, for signalling
58 private volatile long readerThread = 0;
59 private volatile long writerThread = 0;
60
61 // Lock held by current reading or connecting thread
62 private final Object readLock = new Object();
63
64 // Lock held by current writing or connecting thread
65 private final Object writeLock = new Object();
66
67 // Lock held by any thread that modifies the state fields declared below
68 // DO NOT invoke a blocking I/O operation while holding this lock!
69 private final Object stateLock = new Object();
70
71 // -- The following fields are protected by stateLock
72
73 // State, increases monotonically
74 private static final int ST_UNINITIALIZED = -1;
75 private static final int ST_UNCONNECTED = 0;
76 private static final int ST_PENDING = 1;
77 private static final int ST_CONNECTED = 2;
78 private static final int ST_KILLPENDING = 3;
79 private static final int ST_KILLED = 4;
80 private int state = ST_UNINITIALIZED;
81
82 // Binding
83 private SocketAddress localAddress;
84 private SocketAddress remoteAddress;
85
86 // Input/Output open
87 private boolean isInputOpen = true;
88 private boolean isOutputOpen = true;
89 private boolean readyToConnect = false;
90
91 // Socket adaptor, created on demand
92 private Socket socket;
93
94 // -- End of fields protected by stateLock
95
96
97 // Constructor for normal connecting sockets
98 //
99 SocketChannelImpl(SelectorProvider sp) throws IOException {
100 super(sp);
101 this.fd = Net.socket(true);
102 this.fdVal = IOUtil.fdVal(fd);
103 this.state = ST_UNCONNECTED;
104 }
105
106 SocketChannelImpl(SelectorProvider sp,
107 FileDescriptor fd,
108 boolean bound)
109 throws IOException
110 {
111 super(sp);
112 this.fd = fd;
113 this.fdVal = IOUtil.fdVal(fd);
114 this.state = ST_UNCONNECTED;
115 if (bound)
116 this.localAddress = Net.localAddress(fd);
117 }
118
119 // Constructor for sockets obtained from server sockets
120 //
121 SocketChannelImpl(SelectorProvider sp,
122 FileDescriptor fd, InetSocketAddress remote)
123 throws IOException
124 {
125 super(sp);
126 this.fd = fd;
127 this.fdVal = IOUtil.fdVal(fd);
128 this.state = ST_CONNECTED;
129 this.localAddress = Net.localAddress(fd);
130 this.remoteAddress = remote;
131 }
132
133 public Socket socket() {
134 synchronized (stateLock) {
135 if (socket == null)
136 socket = SocketAdaptor.create(this);
137 return socket;
138 }
139 }
140
141 @Override
142 public SocketAddress getLocalAddress() throws IOException {
143 synchronized (stateLock) {
144 if (!isOpen())
145 throw new ClosedChannelException();
146 return localAddress;
147 }
148 }
149
150 @Override
151 public SocketAddress getRemoteAddress() throws IOException {
152 synchronized (stateLock) {
153 if (!isOpen())
154 throw new ClosedChannelException();
155 return remoteAddress;
156 }
157 }
158
159 @Override
160 public <T> SocketChannel setOption(SocketOption<T> name, T value)
161 throws IOException
162 {
163 if (name == null)
164 throw new NullPointerException();
165 if (!supportedOptions().contains(name))
166 throw new UnsupportedOperationException("'" + name + "' not supported");
167
168 synchronized (stateLock) {
169 if (!isOpen())
170 throw new ClosedChannelException();
171
172 // special handling for IP_TOS: no-op when IPv6
173 if (name == StandardSocketOptions.IP_TOS) {
174 if (!Net.isIPv6Available())
175 Net.setSocketOption(fd, StandardProtocolFamily.INET, name, value);
176 return this;
177 }
178
179 // no options that require special handling
180 Net.setSocketOption(fd, Net.UNSPEC, name, value);
181 return this;
182 }
183 }
184
185 @Override
186 @SuppressWarnings("unchecked")
187 public <T> T getOption(SocketOption<T> name)
188 throws IOException
189 {
190 if (name == null)
191 throw new NullPointerException();
192 if (!supportedOptions().contains(name))
193 throw new UnsupportedOperationException("'" + name + "' not supported");
194
195 synchronized (stateLock) {
196 if (!isOpen())
197 throw new ClosedChannelException();
198
199 // special handling for IP_TOS: always return 0 when IPv6
200 if (name == StandardSocketOptions.IP_TOS) {
201 return (Net.isIPv6Available()) ? (T) Integer.valueOf(0) :
202 (T) Net.getSocketOption(fd, StandardProtocolFamily.INET, name);
203 }
204
205 // no options that require special handling
206 return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
207 }
208 }
209
210 private static class DefaultOptionsHolder {
211 static final Set<SocketOption<?>> defaultOptions = defaultOptions();
212
213 private static Set<SocketOption<?>> defaultOptions() {
214 HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(8);
215 set.add(StandardSocketOptions.SO_SNDBUF);
216 set.add(StandardSocketOptions.SO_RCVBUF);
217 set.add(StandardSocketOptions.SO_KEEPALIVE);
218 set.add(StandardSocketOptions.SO_REUSEADDR);
219 set.add(StandardSocketOptions.SO_LINGER);
220 set.add(StandardSocketOptions.TCP_NODELAY);
221 // additional options required by socket adaptor
222 set.add(StandardSocketOptions.IP_TOS);
223 set.add(ExtendedSocketOption.SO_OOBINLINE);
224 return Collections.unmodifiableSet(set);
225 }
226 }
227
228 @Override
229 public final Set<SocketOption<?>> supportedOptions() {
230 return DefaultOptionsHolder.defaultOptions;
231 }
232
233 private boolean ensureReadOpen() throws ClosedChannelException {
234 synchronized (stateLock) {
235 if (!isOpen())
236 throw new ClosedChannelException();
237 if (!isConnected())
238 throw new NotYetConnectedException();
239 if (!isInputOpen)
240 return false;
241 else
242 return true;
243 }
244 }
245
246 private void ensureWriteOpen() throws ClosedChannelException {
247 synchronized (stateLock) {
248 if (!isOpen())
249 throw new ClosedChannelException();
250 if (!isOutputOpen)
251 throw new ClosedChannelException();
252 if (!isConnected())
253 throw new NotYetConnectedException();
254 }
255 }
256
257 private void readerCleanup() throws IOException {
258 synchronized (stateLock) {
259 readerThread = 0;
260 if (state == ST_KILLPENDING)
261 kill();
262 }
263 }
264
265 private void writerCleanup() throws IOException {
266 synchronized (stateLock) {
267 writerThread = 0;
268 if (state == ST_KILLPENDING)
269 kill();
270 }
271 }
272
273 public int read(ByteBuffer buf) throws IOException {
274
275 if (buf == null)
276 throw new NullPointerException();
277
278 synchronized (readLock) {
279 if (!ensureReadOpen())
280 return -1;
281 int n = 0;
282 try {
283
284 // Set up the interruption machinery; see
285 // AbstractInterruptibleChannel for details
286 //
287 begin();
288
289 synchronized (stateLock) {
290 if (!isOpen()) {
291 // Either the current thread is already interrupted, so
292 // begin() closed the channel, or another thread closed the
293 // channel since we checked it a few bytecodes ago. In
294 // either case the value returned here is irrelevant since
295 // the invocation of end() in the finally block will throw
296 // an appropriate exception.
297 //
298 return 0;
299
300 }
301
302 // Save this thread so that it can be signalled on those
303 // platforms that require it
304 //
305 readerThread = NativeThread.current();
306 }
307
308 // Between the previous test of isOpen() and the return of the
309 // IOUtil.read invocation below, this channel might be closed
310 // or this thread might be interrupted. We rely upon the
311 // implicit synchronization point in the kernel read() call to
312 // make sure that the right thing happens. In either case the
313 // implCloseSelectableChannel method is ultimately invoked in
314 // some other thread, so there are three possibilities:
315 //
316 // - implCloseSelectableChannel() invokes nd.preClose()
317 // before this thread invokes read(), in which case the
318 // read returns immediately with either EOF or an error,
319 // the latter of which will cause an IOException to be
320 // thrown.
321 //
322 // - implCloseSelectableChannel() invokes nd.preClose() after
323 // this thread is blocked in read(). On some operating
324 // systems (e.g., Solaris and Windows) this causes the read
325 // to return immediately with either EOF or an error
326 // indication.
327 //
328 // - implCloseSelectableChannel() invokes nd.preClose() after
329 // this thread is blocked in read() but the operating
330 // system (e.g., Linux) doesn't support preemptive close,
331 // so implCloseSelectableChannel() proceeds to signal this
332 // thread, thereby causing the read to return immediately
333 // with IOStatus.INTERRUPTED.
334 //
335 // In all three cases the invocation of end() in the finally
336 // clause will notice that the channel has been closed and
337 // throw an appropriate exception (AsynchronousCloseException
338 // or ClosedByInterruptException) if necessary.
339 //
340 // *There is A fourth possibility. implCloseSelectableChannel()
341 // invokes nd.preClose(), signals reader/writer thred and quickly
342 // moves on to nd.close() in kill(), which does a real close.
343 // Then a third thread accepts a new connection, opens file or
344 // whatever that causes the released "fd" to be recycled. All
345 // above happens just between our last isOpen() check and the
346 // next kernel read reached, with the recycled "fd". The solution
347 // is to postpone the real kill() if there is a reader or/and
348 // writer thread(s) over there "waiting", leave the cleanup/kill
349 // to the reader or writer thread. (the preClose() still happens
350 // so the connection gets cut off as usual).
351 //
352 // For socket channels there is the additional wrinkle that
353 // asynchronous shutdown works much like asynchronous close,
354 // except that the channel is shutdown rather than completely
355 // closed. This is analogous to the first two cases above,
356 // except that the shutdown operation plays the role of
357 // nd.preClose().
358 for (;;) {
359 n = IOUtil.read(fd, buf, -1, nd, readLock);
360 if ((n == IOStatus.INTERRUPTED) && isOpen()) {
361 // The system call was interrupted but the channel
362 // is still open, so retry
363 continue;
364 }
365 return IOStatus.normalize(n);
366 }
367
368 } finally {
369 readerCleanup(); // Clear reader thread
370 // The end method, which is defined in our superclass
371 // AbstractInterruptibleChannel, resets the interruption
372 // machinery. If its argument is true then it returns
373 // normally; otherwise it checks the interrupt and open state
374 // of this channel and throws an appropriate exception if
375 // necessary.
376 //
377 // So, if we actually managed to do any I/O in the above try
378 // block then we pass true to the end method. We also pass
379 // true if the channel was in non-blocking mode when the I/O
380 // operation was initiated but no data could be transferred;
381 // this prevents spurious exceptions from being thrown in the
382 // rare event that a channel is closed or a thread is
383 // interrupted at the exact moment that a non-blocking I/O
384 // request is made.
385 //
386 end(n > 0 || (n == IOStatus.UNAVAILABLE));
387
388 // Extra case for socket channels: Asynchronous shutdown
389 //
390 synchronized (stateLock) {
391 if ((n <= 0) && (!isInputOpen))
392 return IOStatus.EOF;
393 }
394
395 assert IOStatus.check(n);
396
397 }
398 }
399 }
400
401 public long read(ByteBuffer[] dsts, int offset, int length)
402 throws IOException
403 {
404 if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
405 throw new IndexOutOfBoundsException();
406 synchronized (readLock) {
407 if (!ensureReadOpen())
408 return -1;
409 long n = 0;
410 try {
411 begin();
412 synchronized (stateLock) {
413 if (!isOpen())
414 return 0;
415 readerThread = NativeThread.current();
416 }
417
418 for (;;) {
419 n = IOUtil.read(fd, dsts, offset, length, nd);
420 if ((n == IOStatus.INTERRUPTED) && isOpen())
421 continue;
422 return IOStatus.normalize(n);
423 }
424 } finally {
425 readerCleanup();
426 end(n > 0 || (n == IOStatus.UNAVAILABLE));
427 synchronized (stateLock) {
428 if ((n <= 0) && (!isInputOpen))
429 return IOStatus.EOF;
430 }
431 assert IOStatus.check(n);
432 }
433 }
434 }
435
436 public int write(ByteBuffer buf) throws IOException {
437 if (buf == null)
438 throw new NullPointerException();
439 synchronized (writeLock) {
440 ensureWriteOpen();
441 int n = 0;
442 try {
443 begin();
444 synchronized (stateLock) {
445 if (!isOpen())
446 return 0;
447 writerThread = NativeThread.current();
448 }
449 for (;;) {
450 n = IOUtil.write(fd, buf, -1, nd, writeLock);
451 if ((n == IOStatus.INTERRUPTED) && isOpen())
452 continue;
453 return IOStatus.normalize(n);
454 }
455 } finally {
456 writerCleanup();
457 end(n > 0 || (n == IOStatus.UNAVAILABLE));
458 synchronized (stateLock) {
459 if ((n <= 0) && (!isOutputOpen))
460 throw new AsynchronousCloseException();
461 }
462 assert IOStatus.check(n);
463 }
464 }
465 }
466
467 public long write(ByteBuffer[] srcs, int offset, int length)
468 throws IOException
469 {
470 if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
471 throw new IndexOutOfBoundsException();
472 synchronized (writeLock) {
473 ensureWriteOpen();
474 long n = 0;
475 try {
476 begin();
477 synchronized (stateLock) {
478 if (!isOpen())
479 return 0;
480 writerThread = NativeThread.current();
481 }
482 for (;;) {
483 n = IOUtil.write(fd, srcs, offset, length, nd);
484 if ((n == IOStatus.INTERRUPTED) && isOpen())
485 continue;
486 return IOStatus.normalize(n);
487 }
488 } finally {
489 writerCleanup();
490 end((n > 0) || (n == IOStatus.UNAVAILABLE));
491 synchronized (stateLock) {
492 if ((n <= 0) && (!isOutputOpen))
493 throw new AsynchronousCloseException();
494 }
495 assert IOStatus.check(n);
496 }
497 }
498 }
499
500 // package-private
501 int sendOutOfBandData(byte b) throws IOException {
502 synchronized (writeLock) {
503 ensureWriteOpen();
504 int n = 0;
505 try {
506 begin();
507 synchronized (stateLock) {
508 if (!isOpen())
509 return 0;
510 writerThread = NativeThread.current();
511 }
512 for (;;) {
513 n = sendOutOfBandData(fd, b);
514 if ((n == IOStatus.INTERRUPTED) && isOpen())
515 continue;
516 return IOStatus.normalize(n);
517 }
518 } finally {
519 writerCleanup();
520 end((n > 0) || (n == IOStatus.UNAVAILABLE));
521 synchronized (stateLock) {
522 if ((n <= 0) && (!isOutputOpen))
523 throw new AsynchronousCloseException();
524 }
525 assert IOStatus.check(n);
526 }
527 }
528 }
529
530 protected void implConfigureBlocking(boolean block) throws IOException {
531 IOUtil.configureBlocking(fd, block);
532 }
533
534 public SocketAddress localAddress() {
535 synchronized (stateLock) {
536 return localAddress;
537 }
538 }
539
540 public SocketAddress remoteAddress() {
541 synchronized (stateLock) {
542 return remoteAddress;
543 }
544 }
545
546 @Override
547 public SocketChannel bind(SocketAddress local) throws IOException {
548 synchronized (readLock) {
549 synchronized (writeLock) {
550 synchronized (stateLock) {
551 if (!isOpen())
552 throw new ClosedChannelException();
553 if (state == ST_PENDING)
554 throw new ConnectionPendingException();
555 if (localAddress != null)
556 throw new AlreadyBoundException();
557 InetSocketAddress isa = (local == null) ?
558 new InetSocketAddress(0) : Net.checkAddress(local);
559 NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
560 Net.bind(fd, isa.getAddress(), isa.getPort());
561 localAddress = Net.localAddress(fd);
562 }
563 }
564 }
565 return this;
566 }
567
568 public boolean isConnected() {
569 synchronized (stateLock) {
570 return (state == ST_CONNECTED);
571 }
572 }
573
574 public boolean isConnectionPending() {
575 synchronized (stateLock) {
576 return (state == ST_PENDING);
577 }
578 }
579
580 void ensureOpenAndUnconnected() throws IOException { // package-private
581 synchronized (stateLock) {
582 if (!isOpen())
583 throw new ClosedChannelException();
584 if (state == ST_CONNECTED)
585 throw new AlreadyConnectedException();
586 if (state == ST_PENDING)
587 throw new ConnectionPendingException();
588 }
589 }
590
591 public boolean connect(SocketAddress sa) throws IOException {
592 int localPort = 0;
593
594 synchronized (readLock) {
595 synchronized (writeLock) {
596 ensureOpenAndUnconnected();
597 InetSocketAddress isa = Net.checkAddress(sa);
598 SecurityManager sm = System.getSecurityManager();
599 if (sm != null)
600 sm.checkConnect(isa.getAddress().getHostAddress(),
601 isa.getPort());
602 synchronized (blockingLock()) {
603 int n = 0;
604 try {
605 try {
606 begin();
607 synchronized (stateLock) {
608 if (!isOpen()) {
609 return false;
610 }
611 // notify hook only if unbound
612 if (localAddress == null) {
613 NetHooks.beforeTcpConnect(fd,
614 isa.getAddress(),
615 isa.getPort());
616 }
617 readerThread = NativeThread.current();
618 }
619 for (;;) {
620 InetAddress ia = isa.getAddress();
621 if (ia.isAnyLocalAddress())
622 ia = InetAddress.getLocalHost();
623 n = Net.connect(fd,
624 ia,
625 isa.getPort());
626 if ( (n == IOStatus.INTERRUPTED)
627 && isOpen())
628 continue;
629 break;
630 }
631
632 synchronized (stateLock) {
633 if (isOpen() && (localAddress == null) ||
634 ((InetSocketAddress)localAddress)
635 .getAddress().isAnyLocalAddress())
636 {
637 // Socket was not bound before connecting or
638 // Socket was bound with an "anyLocalAddress"
639 localAddress = Net.localAddress(fd);
640 }
641 }
642
643 } finally {
644 readerCleanup();
645 end((n > 0) || (n == IOStatus.UNAVAILABLE));
646 assert IOStatus.check(n);
647 }
648 } catch (IOException x) {
649 // If an exception was thrown, close the channel after
650 // invoking end() so as to avoid bogus
651 // AsynchronousCloseExceptions
652 close();
653 throw x;
654 }
655 synchronized (stateLock) {
656 remoteAddress = isa;
657 if (n > 0) {
658
659 // Connection succeeded; disallow further
660 // invocation
661 state = ST_CONNECTED;
662 return true;
663 }
664 // If nonblocking and no exception then connection
665 // pending; disallow another invocation
666 if (!isBlocking())
667 state = ST_PENDING;
668 else
669 assert false;
670 }
671 }
672 return false;
673 }
674 }
675 }
676
677 public boolean finishConnect() throws IOException {
678 synchronized (readLock) {
679 synchronized (writeLock) {
680 synchronized (stateLock) {
681 if (!isOpen())
682 throw new ClosedChannelException();
683 if (state == ST_CONNECTED)
684 return true;
685 if (state != ST_PENDING)
686 throw new NoConnectionPendingException();
687 }
688 int n = 0;
689 try {
690 try {
691 begin();
692 synchronized (blockingLock()) {
693 synchronized (stateLock) {
694 if (!isOpen()) {
695 return false;
696 }
697 readerThread = NativeThread.current();
698 }
699 if (!isBlocking()) {
700 for (;;) {
701 n = checkConnect(fd, false,
702 readyToConnect);
703 if ( (n == IOStatus.INTERRUPTED)
704 && isOpen())
705 continue;
706 break;
707 }
708 } else {
709 for (;;) {
710 n = checkConnect(fd, true,
711 readyToConnect);
712 if (n == 0) {
713 // Loop in case of
714 // spurious notifications
715 continue;
716 }
717 if ( (n == IOStatus.INTERRUPTED)
718 && isOpen())
719 continue;
720 break;
721 }
722 }
723 }
724 } finally {
725 synchronized (stateLock) {
726 readerThread = 0;
727 if (state == ST_KILLPENDING) {
728 kill();
729 // poll()/getsockopt() does not report
730 // error (throws exception, with n = 0)
731 // on Linux platform after dup2 and
732 // signal-wakeup. Force n to 0 so the
733 // end() can throw appropriate exception
734 n = 0;
735 }
736 }
737 end((n > 0) || (n == IOStatus.UNAVAILABLE));
738 assert IOStatus.check(n);
739 }
740 } catch (IOException x) {
741 // If an exception was thrown, close the channel after
742 // invoking end() so as to avoid bogus
743 // AsynchronousCloseExceptions
744 close();
745 throw x;
746 }
747 if (n > 0) {
748 synchronized (stateLock) {
749 state = ST_CONNECTED;
750 }
751 return true;
752 }
753 return false;
754 }
755 }
756 }
757
758 @Override
759 public SocketChannel shutdownInput() throws IOException {
760 synchronized (stateLock) {
761 if (!isOpen())
762 throw new ClosedChannelException();
763 if (!isConnected())
764 throw new NotYetConnectedException();
765 if (isInputOpen) {
766 Net.shutdown(fd, Net.SHUT_RD);
767 if (readerThread != 0)
768 NativeThread.signal(readerThread);
769 isInputOpen = false;
770 }
771 return this;
772 }
773 }
774
775 @Override
776 public SocketChannel shutdownOutput() throws IOException {
777 synchronized (stateLock) {
778 if (!isOpen())
779 throw new ClosedChannelException();
780 if (!isConnected())
781 throw new NotYetConnectedException();
782 if (isOutputOpen) {
783 Net.shutdown(fd, Net.SHUT_WR);
784 if (writerThread != 0)
785 NativeThread.signal(writerThread);
786 isOutputOpen = false;
787 }
788 return this;
789 }
790 }
791
792 public boolean isInputOpen() {
793 synchronized (stateLock) {
794 return isInputOpen;
795 }
796 }
797
798 public boolean isOutputOpen() {
799 synchronized (stateLock) {
800 return isOutputOpen;
801 }
802 }
803
804 // AbstractInterruptibleChannel synchronizes invocations of this method
805 // using AbstractInterruptibleChannel.closeLock, and also ensures that this
806 // method is only ever invoked once. Before we get to this method, isOpen
807 // (which is volatile) will have been set to false.
808 //
809 protected void implCloseSelectableChannel() throws IOException {
810 synchronized (stateLock) {
811 isInputOpen = false;
812 isOutputOpen = false;
813
814 // Close the underlying file descriptor and dup it to a known fd
815 // that's already closed. This prevents other operations on this
816 // channel from using the old fd, which might be recycled in the
817 // meantime and allocated to an entirely different channel.
818 //
819 nd.preClose(fd);
820
821 // Signal native threads, if needed. If a target thread is not
822 // currently blocked in an I/O operation then no harm is done since
823 // the signal handler doesn't actually do anything.
824 //
825 if (readerThread != 0)
826 NativeThread.signal(readerThread);
827
828 if (writerThread != 0)
829 NativeThread.signal(writerThread);
830
831 // If this channel is not registered then it's safe to close the fd
832 // immediately since we know at this point that no thread is
833 // blocked in an I/O operation upon the channel and, since the
834 // channel is marked closed, no thread will start another such
835 // operation. If this channel is registered then we don't close
836 // the fd since it might be in use by a selector. In that case
837 // closing this channel caused its keys to be cancelled, so the
838 // last selector to deregister a key for this channel will invoke
839 // kill() to close the fd.
840 //
841 if (!isRegistered())
842 kill();
843 }
844 }
845
846 public void kill() throws IOException {
847 synchronized (stateLock) {
848 if (state == ST_KILLED)
849 return;
850 if (state == ST_UNINITIALIZED) {
851 state = ST_KILLED;
852 return;
853 }
854 assert !isOpen() && !isRegistered();
855
856 // Postpone the kill if there is a waiting reader
857 // or writer thread. See the comments in read() for
858 // more detailed explanation.
859 if (readerThread == 0 && writerThread == 0) {
860 nd.close(fd);
861 state = ST_KILLED;
862 } else {
863 state = ST_KILLPENDING;
864 }
865 }
866 }
867
868 /**
869 * Translates native poll revent ops into a ready operation ops
870 */
871 public boolean translateReadyOps(int ops, int initialOps,
872 SelectionKeyImpl sk) {
873 int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
874 int oldOps = sk.nioReadyOps();
875 int newOps = initialOps;
876
877 if ((ops & PollArrayWrapper.POLLNVAL) != 0) {
878 // This should only happen if this channel is pre-closed while a
879 // selection operation is in progress
880 // ## Throw an error if this channel has not been pre-closed
881 return false;
882 }
883
884 if ((ops & (PollArrayWrapper.POLLERR
885 | PollArrayWrapper.POLLHUP)) != 0) {
886 newOps = intOps;
887 sk.nioReadyOps(newOps);
888 // No need to poll again in checkConnect,
889 // the error will be detected there
890 readyToConnect = true;
891 return (newOps & ~oldOps) != 0;
892 }
893
894 if (((ops & PollArrayWrapper.POLLIN) != 0) &&
895 ((intOps & SelectionKey.OP_READ) != 0) &&
896 (state == ST_CONNECTED))
897 newOps |= SelectionKey.OP_READ;
898
899 if (((ops & PollArrayWrapper.POLLCONN) != 0) &&
900 ((intOps & SelectionKey.OP_CONNECT) != 0) &&
901 ((state == ST_UNCONNECTED) || (state == ST_PENDING))) {
902 newOps |= SelectionKey.OP_CONNECT;
903 readyToConnect = true;
904 }
905
906 if (((ops & PollArrayWrapper.POLLOUT) != 0) &&
907 ((intOps & SelectionKey.OP_WRITE) != 0) &&
908 (state == ST_CONNECTED))
909 newOps |= SelectionKey.OP_WRITE;
910
911 sk.nioReadyOps(newOps);
912 return (newOps & ~oldOps) != 0;
913 }
914
915 public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
916 return translateReadyOps(ops, sk.nioReadyOps(), sk);
917 }
918
919 public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
920 return translateReadyOps(ops, 0, sk);
921 }
922
923 /**
924 * Translates an interest operation set into a native poll event set
925 */
926 public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
927 int newOps = 0;
928 if ((ops & SelectionKey.OP_READ) != 0)
929 newOps |= PollArrayWrapper.POLLIN;
930 if ((ops & SelectionKey.OP_WRITE) != 0)
931 newOps |= PollArrayWrapper.POLLOUT;
932 if ((ops & SelectionKey.OP_CONNECT) != 0)
933 newOps |= PollArrayWrapper.POLLCONN;
934 sk.selector.putEventOps(sk, newOps);
935 }
936
937 public FileDescriptor getFD() {
938 return fd;
939 }
940
941 public int getFDVal() {
942 return fdVal;
943 }
944
945 public String toString() {
946 StringBuffer sb = new StringBuffer();
947 sb.append(this.getClass().getSuperclass().getName());
948 sb.append('[');
949 if (!isOpen())
950 sb.append("closed");
951 else {
952 synchronized (stateLock) {
953 switch (state) {
954 case ST_UNCONNECTED:
955 sb.append("unconnected");
956 break;
957 case ST_PENDING:
958 sb.append("connection-pending");
959 break;
960 case ST_CONNECTED:
961 sb.append("connected");
962 if (!isInputOpen)
963 sb.append(" ishut");
964 if (!isOutputOpen)
965 sb.append(" oshut");
966 break;
967 }
968 if (localAddress() != null) {
969 sb.append(" local=");
970 sb.append(localAddress().toString());
971 }
972 if (remoteAddress() != null) {
973 sb.append(" remote=");
974 sb.append(remoteAddress().toString());
975 }
976 }
977 }
978 sb.append(']');
979 return sb.toString();
980 }
981
982
983 // -- Native methods --
984
985 private static native int checkConnect(FileDescriptor fd,
986 boolean block, boolean ready)
987 throws IOException;
988
989 private static native int sendOutOfBandData(FileDescriptor fd, byte data)
990 throws IOException;
991
992 static {
993 Util.load();
994 nd = new SocketDispatcher();
995 }
996
997 }