001 /* VMChannel.java -- Native interface suppling channel operations. 002 Copyright (C) 2006 Free Software Foundation, Inc. 003 004 The original of this file is part of GNU Classpath. 005 006 GNU Classpath is free software; you can redistribute it and/or modify 007 it under the terms of the GNU General Public License as published by 008 the Free Software Foundation; either version 2, or (at your option) 009 any later version. 010 011 GNU Classpath is distributed in the hope that it will be useful, but 012 WITHOUT ANY WARRANTY; without even the implied warranty of 013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 General Public License for more details. 015 016 You should have received a copy of the GNU General Public License 017 along with GNU Classpath; see the file COPYING. If not, write to the 018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 019 02110-1301 USA. 020 021 Linking this library statically or dynamically with other modules is 022 making a combined work based on this library. Thus, the terms and 023 conditions of the GNU General Public License cover the whole 024 combination. 025 026 As a special exception, the copyright holders of this library give you 027 permission to link this library with independent modules to produce an 028 executable, regardless of the license terms of these independent 029 modules, and to copy and distribute the resulting executable under 030 terms of your choice, provided that you also meet, for each linked 031 independent module, the terms and conditions of the license of that 032 module. An independent module is a module which is not derived from 033 or based on this library. If you modify this library, you may extend 034 this exception to your version of the library, but you are not 035 obligated to do so. If you do not wish to do so, delete this 036 exception statement from your version. */ 037 package gnu.java.nio; 038 039 import gnu.classpath.Configuration; 040 041 import java.io.IOException; 042 import java.net.Inet4Address; 043 import java.net.Inet6Address; 044 import java.net.InetAddress; 045 import java.net.InetSocketAddress; 046 import java.net.SocketAddress; 047 import java.net.SocketException; 048 import java.nio.ByteBuffer; 049 import java.nio.MappedByteBuffer; 050 051 import org.jikesrvm.VM; 052 import org.jikesrvm.mm.mminterface.MemoryManager; 053 import org.jikesrvm.runtime.FileSystem; 054 import org.vmmagic.pragma.NonMovingAllocation; 055 056 057 /** 058 * Native interface to support configuring of channel to run in a non-blocking 059 * manner and support scatter/gather io operations. 060 * 061 * JikesRVM-specific implementation by Robin Garner and Filip Pizlo. 062 */ 063 public final class VMChannel 064 { 065 /** 066 * Our reference implementation uses an integer to store the native 067 * file descriptor. 068 */ 069 private final State nfd; 070 071 private Kind kind; 072 073 public VMChannel() 074 { 075 // XXX consider adding security check here, so only Classpath 076 // code may create instances. 077 this.nfd = new State(); 078 kind = Kind.OTHER; 079 } 080 081 /** 082 * This constructor is used by the POSIX reference implementation; 083 * other virtual machines need not support it. 084 * 085 * <strong>Important:</strong> do not call this in library code that is 086 * not specific to Classpath's reference implementation. 087 * 088 * @param native_fd The native file descriptor integer. 089 * @throws IOException 090 */ 091 VMChannel(final int native_fd) throws IOException 092 { 093 this(); 094 this.nfd.setNativeFD(native_fd); 095 } 096 097 public State getState() 098 { 099 return nfd; 100 } 101 102 /** 103 * Don't do fast I/O for the standard file descriptors - these are used 104 * for throwing exceptions, so may not be able to allocate. 105 * 106 * Cache the max of the IDs to avoid gratuitous native calls. 107 */ 108 private static int MAX_STANDARD_FD; 109 110 private static int max(int[] values) { 111 int result = values[0]; 112 for (int i : values) 113 if (i > result) result = i; 114 return result; 115 } 116 117 static 118 { 119 // load the shared library needed for native methods. 120 if (Configuration.INIT_LOAD_LIBRARY) 121 { 122 System.loadLibrary ("javanio"); 123 } 124 initIDs(); 125 MAX_STANDARD_FD = max(new int[] {stdin_fd(),stdin_fd(),stderr_fd()}); 126 } 127 128 public static VMChannel getStdin() throws IOException 129 { 130 return new VMChannel(stdin_fd()); 131 } 132 133 public static VMChannel getStdout() throws IOException 134 { 135 return new VMChannel(stdout_fd()); 136 } 137 138 public static VMChannel getStderr() throws IOException 139 { 140 return new VMChannel(stderr_fd()); 141 } 142 143 private static native int stdin_fd(); 144 private static native int stdout_fd(); 145 private static native int stderr_fd(); 146 147 148 /** 149 * Set the file descriptor to have the required blocking 150 * setting. 151 * 152 * @param blocking The blocking flag to set. 153 */ 154 public void setBlocking(boolean blocking) throws IOException 155 { 156 setBlocking(nfd.getNativeFD(), blocking); 157 } 158 159 private static native void setBlocking(int fd, boolean blocking) 160 throws IOException; 161 162 public int available() throws IOException 163 { 164 return available(nfd.getNativeFD()); 165 } 166 167 private static native int available(int native_fd) throws IOException; 168 169 /** 170 * A thread-local store of non-moving buffers. Used to perform IO to 171 * in cases where the actual user buffer is in a moving space. 172 */ 173 private static class LocalByteArray extends ThreadLocal<byte[]> { 174 private static final int INITIAL_BUFFER_SIZE = 8192; 175 @Override 176 @NonMovingAllocation 177 protected byte[] initialValue() { 178 return new byte[INITIAL_BUFFER_SIZE]; 179 } 180 181 /** 182 * Get a buffer, ensuring it is at least 'len' in size 183 * @param len Minimum length of the buffer 184 * @return a new or recycled buffer 185 */ 186 @NonMovingAllocation 187 public byte[] get(int len) { 188 byte[] buf = get(); 189 if (buf.length < len) { 190 /* Allocate a new buffer by successive doubling of capacity */ 191 int newCapacity = buf.length << 1; 192 while (newCapacity < len) 193 newCapacity <<= 1; 194 buf = new byte[newCapacity]; 195 set(buf); 196 } 197 return buf; 198 } 199 } 200 201 /** 202 * Thread-local buffer for VM-side buffering of write calls 203 */ 204 private static final LocalByteArray localByteArray = new LocalByteArray() ; 205 206 /** 207 * Read the specified byte buffer. 208 * 209 * @param dst 210 * @return the number of bytes actually read 211 * @throws IOException 212 */ 213 public int read(ByteBuffer dst) throws IOException { 214 return read(dst,dst.position(),dst.limit()-dst.position()); 215 } 216 217 /** 218 * Read a byte buffer, given a starting position and length. 219 * Looks at the type of buffer and decides which is the fastest way 220 * to perform the write. If the buffer is backed by a byte array, use 221 * the internal method, otherwise push it out to classpath's native function 222 * (the slow way). 223 * 224 * @param dst 225 * @param pos 226 * @param len 227 * @return the number of bytes actually read 228 * @throws IOException 229 */ 230 private int read(ByteBuffer dst, int pos, int len) throws IOException { 231 int bytes; 232 if (len == 1) { 233 int b = FileSystem.readByte(nfd.getNativeFD()); 234 if (b >= 0) { 235 dst.put((byte)(b & 0xFF)); 236 dst.position(pos+1); 237 return 1; 238 } else 239 bytes = b; 240 } else if (dst.hasArray()) { 241 bytes = read(dst.array(),pos,len); 242 } else { 243 return read(nfd.getNativeFD(), dst); 244 } 245 if (bytes > 0) 246 dst.position(pos+bytes); 247 return bytes; 248 } 249 250 /** 251 * Reads a byte array directly. Performs optimal buffering. 252 * 253 * If the target buffer is pinned, use it directly. Otherwise 254 * allocate one of the thread-local buffers, perform the IO to 255 * that, and copy the result to the target array. 256 * 257 * @param dst Byte array to read to 258 * @return Number of bytes read. 259 * @throws IOException If an error occurs or dst is not a direct buffers. 260 */ 261 private int read(byte[] dst, int pos, int len) throws IOException { 262 if (MemoryManager.willNeverMove(dst)) { 263 return read(nfd.getNativeFD(),dst,pos,len); 264 } else { 265 byte[] buffer; 266 // Rebuffer the IO in a thread-local byte array 267 buffer = localByteArray.get(len); 268 269 /* perform the read */ 270 int bytes = read(nfd.getNativeFD(),buffer,0,len); 271 if (bytes > 0) 272 System.arraycopy(buffer,0,dst,pos,bytes); 273 return bytes; 274 } 275 } 276 277 /** 278 * Use JikesRVM's internal read function - the fast way. 279 * 280 * @param fd File descriptor 281 * @param dst Destination buffer 282 * @param position Starting offset in the buffer 283 * @param len Number of bytes to read 284 * @return Number of bytes read, or -1 for end of file. 285 * @throws IOException 286 */ 287 private static int read(int fd, byte[] dst, int position, int len) throws IOException { 288 if (VM.VerifyAssertions) VM._assert(MemoryManager.willNeverMove(dst)); 289 int bytes = FileSystem.readBytes(fd,dst,position,len); 290 if (bytes < 0) { 291 throw new IOException("Error code "+Integer.toString(bytes)); 292 } 293 if (bytes == 0) { 294 bytes = -1; 295 } 296 return bytes; 297 } 298 299 /** 300 * Classpath's native read method. Slow, due to the amount of JNI processing. 301 * 302 * @param fd 303 * @param dst 304 * @return the number of bytes actually read 305 * @throws IOException 306 */ 307 private static native int read(int fd, ByteBuffer dst) throws IOException; 308 309 /** 310 * Read a single byte. 311 * 312 * @return The byte read, or -1 on end of file. 313 * @throws IOException 314 */ 315 public int read() throws IOException 316 { 317 //return read(nfd.getNativeFD()); 318 int result = FileSystem.readByte(nfd.getNativeFD()); 319 if (result < -1) { 320 throw new IOException("Error code "+Integer.toString(result)); 321 } 322 return result; 323 } 324 325 private static native int read(int fd) throws IOException; 326 327 /** 328 * Reads into byte buffers directly using the supplied file descriptor. 329 * Assumes that the buffer list contains DirectBuffers. Will perform a 330 * scattering read. 331 * 332 * @param dsts An array direct byte buffers. 333 * @param offset Index of the first buffer to read to. 334 * @param length The number of buffers to read to. 335 * @return Number of bytes read. 336 * @throws IOException If an error occurs or the dsts are not direct buffers. 337 */ 338 public long readScattering(ByteBuffer[] dsts, int offset, int length) 339 throws IOException 340 { 341 if (offset + length > dsts.length) 342 throw new IndexOutOfBoundsException("offset + length > dsts.length"); 343 344 return readScattering(nfd.getNativeFD(), dsts, offset, length); 345 } 346 347 private static native long readScattering(int fd, ByteBuffer[] dsts, 348 int offset, int length) 349 throws IOException; 350 351 /** 352 * Receive a datagram on this channel, returning the host address 353 * that sent the datagram. 354 * 355 * @param dst Where to store the datagram. 356 * @return The host address that sent the datagram. 357 * @throws IOException 358 */ 359 public SocketAddress receive(ByteBuffer dst) throws IOException 360 { 361 if (kind != Kind.SOCK_DGRAM) 362 throw new SocketException("not a datagram socket"); 363 ByteBuffer hostPort = ByteBuffer.allocateDirect(18); 364 int hostlen = receive(nfd.getNativeFD(), dst, hostPort); 365 if (hostlen == 0) 366 return null; 367 if (hostlen == 4) // IPv4 368 { 369 byte[] addr = new byte[4]; 370 hostPort.get(addr); 371 int port = hostPort.getShort() & 0xFFFF; 372 return new InetSocketAddress(Inet4Address.getByAddress(addr), port); 373 } 374 if (hostlen == 16) // IPv6 375 { 376 byte[] addr = new byte[16]; 377 hostPort.get(addr); 378 int port = hostPort.getShort() & 0xFFFF; 379 return new InetSocketAddress(Inet6Address.getByAddress(addr), port); 380 } 381 382 throw new SocketException("host address received with invalid length: " 383 + hostlen); 384 } 385 386 private static native int receive (int fd, ByteBuffer dst, ByteBuffer address) 387 throws IOException; 388 389 /** 390 * Writes from a byte array using the supplied file descriptor. 391 * 392 * @param src The source buffer. 393 * @return Number of bytes written. 394 * @throws IOException 395 */ 396 public int write(byte[] src, int pos, int len) throws IOException { 397 if (MemoryManager.willNeverMove(src)) { 398 return write(nfd.getNativeFD(), src, pos, len); 399 } else { 400 byte[] buffer; 401 // Rebuffer the IO in a thread-local DirectBuffer 402 buffer = localByteArray.get(len); 403 if (VM.VerifyAssertions) VM._assert(MemoryManager.willNeverMove(buffer)); 404 System.arraycopy(src, pos, buffer,0,len); 405 return write(nfd.getNativeFD(),buffer,0,len); 406 } 407 } 408 409 public int write(ByteBuffer src, int pos, int len) throws IOException { 410 int bytes; 411 if (len == 1) { 412 int ok = FileSystem.writeByte(nfd.getNativeFD(),src.get(pos)); 413 if(ok == 0){ 414 bytes = 1; 415 }else{ 416 throw new IOException("Error code " + Integer.toString(ok)); 417 } 418 } else if (src.hasArray()) { 419 bytes = write(src.array(),pos,len); 420 } else { 421 // Use classpath version, which does buffer housekeeping 422 return write(nfd.getNativeFD(), src); 423 } 424 if (bytes > 0) 425 src.position(src.position()+bytes); 426 return bytes; 427 } 428 429 public int write(ByteBuffer src) throws IOException { 430 if (nfd.getNativeFD() > MAX_STANDARD_FD) 431 return write(src,src.position(),src.limit()-src.position()); 432 else 433 return write(nfd.getNativeFD(),src); 434 } 435 436 /** 437 * Use JikesRVM's internal read function - the fast way. 438 * 439 * @param fd File descriptor 440 * @param src SOurce buffer 441 * @param pos Starting offset in the buffer 442 * @param len Number of bytes to write 443 * @return Number of bytes written. 444 * @throws IOException 445 */ 446 private static int write(int fd, byte[] src, int pos, int len) throws IOException { 447 int bytes = FileSystem.writeBytes(fd,src,pos,len); 448 if (bytes < 0) 449 throw new IOException("Error code "+Integer.toString(bytes)); 450 return bytes; 451 } 452 453 /** 454 * Classpath's native write method. Slow, due to the amount of JNI processing. 455 * 456 * @param fd 457 * @param src 458 * @return Number of bytes written 459 * @throws IOException 460 */ 461 private static native int write(int fd, ByteBuffer src) throws IOException; 462 463 /** 464 * Writes from byte buffers directly using the supplied file descriptor. 465 * Assumes the that buffer list contains DirectBuffers. Will perform 466 * as gathering write. 467 * 468 * @param srcs 469 * @param offset 470 * @param length 471 * @return Number of bytes written. 472 * @throws IOException 473 */ 474 public long writeGathering(ByteBuffer[] srcs, int offset, int length) 475 throws IOException 476 { 477 if (offset + length > srcs.length) 478 throw new IndexOutOfBoundsException("offset + length > srcs.length"); 479 480 // A gathering write is limited to 16 buffers; when writing, ensure 481 // that we have at least one buffer with something in it in the 16 482 // buffer window starting at offset. 483 while (!srcs[offset].hasRemaining() && offset < srcs.length) 484 offset++; 485 486 // There are no buffers with anything to write. 487 if (offset == srcs.length) 488 return 0; 489 490 // If we advanced `offset' so far that we don't have `length' 491 // buffers left, reset length to only the remaining buffers. 492 if (length > srcs.length - offset) 493 length = srcs.length - offset; 494 495 return writeGathering(nfd.getNativeFD(), srcs, offset, length); 496 } 497 498 private native long writeGathering(int fd, ByteBuffer[] srcs, 499 int offset, int length) 500 throws IOException; 501 502 /** 503 * Send a datagram to the given address. 504 * 505 * @param src The source buffer. 506 * @param dst The destination address. 507 * @return The number of bytes written. 508 * @throws IOException 509 */ 510 public int send(ByteBuffer src, InetSocketAddress dst) 511 throws IOException 512 { 513 InetAddress addr = dst.getAddress(); 514 if (addr == null) 515 throw new NullPointerException(); 516 if (addr instanceof Inet4Address) 517 return send(nfd.getNativeFD(), src, addr.getAddress(), dst.getPort()); 518 else if (addr instanceof Inet6Address) 519 return send6(nfd.getNativeFD(), src, addr.getAddress(), dst.getPort()); 520 else 521 throw new SocketException("unrecognized inet address type"); 522 } 523 524 // Send to an IPv4 address. 525 private static native int send(int fd, ByteBuffer src, byte[] addr, int port) 526 throws IOException; 527 528 // Send to an IPv6 address. 529 private static native int send6(int fd, ByteBuffer src, byte[] addr, int port) 530 throws IOException; 531 532 /** 533 * Write a single byte. 534 * 535 * @param b The byte to write. 536 * @throws IOException 537 */ 538 public void write(int b) throws IOException 539 { 540 //write(nfd.getNativeFD(), b); 541 int result = FileSystem.writeByte(nfd.getNativeFD(), b); 542 if (result < 0) { 543 throw new IOException("Error code "+Integer.toString(result)); 544 } 545 } 546 547 private static native void write(int fd, int b) throws IOException; 548 549 private native static void initIDs(); 550 551 // Network (socket) specific methods. 552 553 /** 554 * Create a new socket. This method will initialize the native file 555 * descriptor state of this instance. 556 * 557 * @param stream Whether or not to create a streaming socket, or a datagram 558 * socket. 559 * @throws IOException If creating a new socket fails, or if this 560 * channel already has its native descriptor initialized. 561 */ 562 public void initSocket(boolean stream) throws IOException 563 { 564 if (nfd.isValid()) 565 throw new IOException("native FD already initialized"); 566 if (stream) 567 kind = Kind.SOCK_STREAM; 568 else 569 kind = Kind.SOCK_DGRAM; 570 nfd.setNativeFD(socket(stream)); 571 } 572 573 /** 574 * Create a new socket, returning the native file descriptor. 575 * 576 * @param stream Set to true for streaming sockets; false for datagrams. 577 * @return The native file descriptor. 578 * @throws IOException If creating the socket fails. 579 */ 580 private static native int socket(boolean stream) throws IOException; 581 582 /** 583 * Connect the underlying socket file descriptor to the remote host. 584 * 585 * @param saddr The address to connect to. 586 * @param timeout The connect timeout to use for blocking connects. 587 * @return True if the connection succeeded; false if the file descriptor 588 * is in non-blocking mode and the connection did not immediately 589 * succeed. 590 * @throws IOException If an error occurs while connecting. 591 */ 592 public boolean connect(InetSocketAddress saddr, int timeout) 593 throws SocketException 594 { 595 int fd; 596 597 InetAddress addr = saddr.getAddress(); 598 599 // Translates an IOException into a SocketException to conform 600 // to the throws clause. 601 try 602 { 603 fd = nfd.getNativeFD(); 604 } 605 catch (IOException ioe) 606 { 607 throw new SocketException(ioe.getMessage()); 608 } 609 610 if (addr instanceof Inet4Address) 611 return connect(fd, addr.getAddress(), saddr.getPort(), 612 timeout); 613 if (addr instanceof Inet6Address) 614 return connect6(fd, addr.getAddress(), saddr.getPort(), 615 timeout); 616 throw new SocketException("unsupported internet address"); 617 } 618 619 private static native boolean connect(int fd, byte[] addr, int port, int timeout) 620 throws SocketException; 621 622 private static native boolean connect6(int fd, byte[] addr, int port, int timeout) 623 throws SocketException; 624 625 /** 626 * Disconnect this channel, if it is a datagram socket. Disconnecting 627 * a datagram channel will disassociate it from any address, so the 628 * socket will remain open, but can send and receive datagrams from 629 * any address. 630 * 631 * @throws IOException If disconnecting this channel fails, or if this 632 * channel is not a datagram channel. 633 */ 634 public void disconnect() throws IOException 635 { 636 if (kind != Kind.SOCK_DGRAM) 637 throw new IOException("can only disconnect datagram channels"); 638 disconnect(nfd.getNativeFD()); 639 } 640 641 private static native void disconnect(int fd) throws IOException; 642 643 public InetSocketAddress getLocalAddress() throws IOException 644 { 645 if (!nfd.isValid()) 646 return null; 647 ByteBuffer name = ByteBuffer.allocateDirect(18); 648 int namelen = getsockname(nfd.getNativeFD(), name); 649 if (namelen == 0) // not bound 650 return null; // XXX return some wildcard? 651 if (namelen == 4) 652 { 653 byte[] addr = new byte[4]; 654 name.get(addr); 655 int port = name.getShort() & 0xFFFF; 656 return new InetSocketAddress(Inet4Address.getByAddress(addr), port); 657 } 658 if (namelen == 16) 659 { 660 byte[] addr = new byte[16]; 661 name.get(addr); 662 int port = name.getShort() & 0xFFFF; 663 return new InetSocketAddress(Inet6Address.getByAddress(addr), port); 664 } 665 throw new SocketException("invalid address length"); 666 } 667 668 private static native int getsockname(int fd, ByteBuffer name) 669 throws IOException; 670 671 /** 672 * Returns the socket address of the remote peer this channel is connected 673 * to, or null if this channel is not yet connected. 674 * 675 * @return The peer address. 676 * @throws IOException 677 */ 678 public InetSocketAddress getPeerAddress() throws IOException 679 { 680 if (!nfd.isValid()) 681 return null; 682 ByteBuffer name = ByteBuffer.allocateDirect(18); 683 int namelen = getpeername (nfd.getNativeFD(), name); 684 if (namelen == 0) // not connected yet 685 return null; 686 if (namelen == 4) // IPv4 687 { 688 byte[] addr = new byte[4]; 689 name.get(addr); 690 int port = name.getShort() & 0xFFFF; 691 return new InetSocketAddress(Inet4Address.getByAddress(addr), port); 692 } 693 else if (namelen == 16) // IPv6 694 { 695 byte[] addr = new byte[16]; 696 name.get(addr); 697 int port = name.getShort() & 0xFFFF; 698 return new InetSocketAddress(Inet6Address.getByAddress(addr), port); 699 } 700 throw new SocketException("invalid address length"); 701 } 702 703 /* 704 * The format here is the peer address, followed by the port number. 705 * The returned value is the length of the peer address; thus, there 706 * will be LEN + 2 valid bytes put into NAME. 707 */ 708 private static native int getpeername(int fd, ByteBuffer name) 709 throws IOException; 710 711 /** 712 * Accept an incoming connection, returning a new VMChannel, or null 713 * if the channel is nonblocking and no connection is pending. 714 * 715 * @return The accepted connection, or null. 716 * @throws IOException If an IO error occurs. 717 */ 718 public VMChannel accept() throws IOException 719 { 720 int new_fd = accept(nfd.getNativeFD()); 721 if (new_fd == -1) // non-blocking accept had no pending connection 722 return null; 723 return new VMChannel(new_fd); 724 } 725 726 private static native int accept(int native_fd) throws IOException; 727 728 // File-specific methods. 729 730 /** 731 * Open a file at PATH, initializing the native state to operate on 732 * that open file. 733 * 734 * @param path The absolute file path. 735 * @throws IOException If the file cannot be opened, or if this 736 * channel was previously initialized. 737 */ 738 public void openFile(String path, int mode) throws IOException 739 { 740 if (nfd.isValid() || nfd.isClosed()) 741 throw new IOException("can't reinitialize this channel"); 742 int fd = open(path, mode); 743 nfd.setNativeFD(fd); 744 kind = Kind.FILE; 745 } 746 747 private static native int open(String path, int mode) throws IOException; 748 749 public long position() throws IOException 750 { 751 if (kind != Kind.FILE) 752 throw new IOException("not a file"); 753 return position(nfd.getNativeFD()); 754 } 755 756 private static native long position(int fd) throws IOException; 757 758 public void seek(long pos) throws IOException 759 { 760 if (kind != Kind.FILE) 761 throw new IOException("not a file"); 762 seek(nfd.getNativeFD(), pos); 763 } 764 765 private static native void seek(int fd, long pos) throws IOException; 766 767 public void truncate(long length) throws IOException 768 { 769 if (kind != Kind.FILE) 770 throw new IOException("not a file"); 771 truncate(nfd.getNativeFD(), length); 772 } 773 774 private static native void truncate(int fd, long len) throws IOException; 775 776 public boolean lock(long pos, long len, boolean shared, boolean wait) 777 throws IOException 778 { 779 if (kind != Kind.FILE) 780 throw new IOException("not a file"); 781 return lock(nfd.getNativeFD(), pos, len, shared, wait); 782 } 783 784 private static native boolean lock(int fd, long pos, long len, 785 boolean shared, boolean wait) 786 throws IOException; 787 788 public void unlock(long pos, long len) throws IOException 789 { 790 if (kind != Kind.FILE) 791 throw new IOException("not a file"); 792 unlock(nfd.getNativeFD(), pos, len); 793 } 794 795 private static native void unlock(int fd, long pos, long len) throws IOException; 796 797 public long size() throws IOException 798 { 799 if (kind != Kind.FILE) 800 throw new IOException("not a file"); 801 return size(nfd.getNativeFD()); 802 } 803 804 private static native long size(int fd) throws IOException; 805 806 public MappedByteBuffer map(char mode, long position, int size) 807 throws IOException 808 { 809 if (kind != Kind.FILE) 810 throw new IOException("not a file"); 811 return map(nfd.getNativeFD(), mode, position, size); 812 } 813 814 private static native MappedByteBuffer map(int fd, char mode, 815 long position, int size) 816 throws IOException; 817 818 public boolean flush(boolean metadata) throws IOException 819 { 820 if (kind != Kind.FILE) 821 throw new IOException("not a file"); 822 return flush(nfd.getNativeFD(), metadata); 823 } 824 825 private static native boolean flush(int fd, boolean metadata) throws IOException; 826 827 // Close. 828 829 /** 830 * Close this socket. The socket is also automatically closed when this 831 * object is finalized. 832 * 833 * @throws IOException If closing the socket fails, or if this object has 834 * no open socket. 835 */ 836 public void close() throws IOException 837 { 838 nfd.close(); 839 } 840 841 static native void close(int native_fd) throws IOException; 842 843 /** 844 * <p>Provides a simple mean for the JNI code to find out whether the 845 * current thread was interrupted by a call to Thread.interrupt().</p> 846 * 847 * @return true if the current thread was interrupted, false otherwise 848 */ 849 static boolean isThreadInterrupted() 850 { 851 return Thread.currentThread().isInterrupted(); 852 } 853 854 // Inner classes. 855 856 /** 857 * A wrapper for a native file descriptor integer. This tracks the state 858 * of an open file descriptor, and ensures that 859 * 860 * This class need not be fully supported by virtual machines; if a 861 * virtual machine does not use integer file descriptors, or does and 862 * wishes to hide that, then the methods of this class may be stubbed out. 863 * 864 * System-specific classes that depend on access to native file descriptor 865 * integers SHOULD declare this fact. 866 */ 867 public final class State 868 { 869 private int native_fd; 870 private boolean valid; 871 private boolean closed; 872 873 State() 874 { 875 native_fd = -1; 876 valid = false; 877 closed = false; 878 } 879 880 public boolean isValid() 881 { 882 return valid; 883 } 884 885 public boolean isClosed() 886 { 887 return closed; 888 } 889 890 public int getNativeFD() throws IOException 891 { 892 if (!valid) 893 throw new IOException("invalid file descriptor"); 894 return native_fd; 895 } 896 897 void setNativeFD(final int native_fd) throws IOException 898 { 899 if (valid) 900 throw new IOException("file descriptor already initialized"); 901 this.native_fd = native_fd; 902 valid = true; 903 } 904 905 public void close() throws IOException 906 { 907 if (!valid) 908 throw new IOException("invalid file descriptor"); 909 try 910 { 911 VMChannel.close(native_fd); 912 } 913 finally 914 { 915 valid = false; 916 closed = true; 917 } 918 } 919 920 @Override 921 public String toString() 922 { 923 if (closed) 924 return "<<closed>>"; 925 if (!valid) 926 return "<<invalid>>"; 927 return String.valueOf(native_fd); 928 } 929 930 @Override 931 protected void finalize() throws Throwable 932 { 933 try 934 { 935 if (valid) 936 close(); 937 } 938 finally 939 { 940 super.finalize(); 941 } 942 } 943 } 944 945 /** 946 * An enumeration of possible kinds of channel. 947 */ 948 static class Kind // XXX enum 949 { 950 /** A streaming (TCP) socket. */ 951 static final Kind SOCK_STREAM = new Kind(); 952 953 /** A datagram (UDP) socket. */ 954 static final Kind SOCK_DGRAM = new Kind(); 955 956 /** A file. */ 957 static final Kind FILE = new Kind(); 958 959 /** Something else; not a socket or file. */ 960 static final Kind OTHER = new Kind(); 961 962 private Kind() { } 963 } 964 }