src/share/classes/sun/nio/ch/IOUtil.java
author alanb
Wed Apr 06 20:51:55 2011 +0100 (13 months ago)
changeset 3990 cd86fbf11e33
parent 3261a06412e13bf7
permissions -rw-r--r--
7034155: (ch) NullPointerException in sun.io.ch.IOUtil when OOM is thrown
Reviewed-by: forax
        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.nio.ByteBuffer;
       31 
       32 
       33 /**
       34  * File-descriptor based I/O utilities that are shared by NIO classes.
       35  */
       36 
       37 class IOUtil {
       38 
       39     private IOUtil() { }                // No instantiation
       40 
       41     static int write(FileDescriptor fd, ByteBuffer src, long position,
       42                      NativeDispatcher nd, Object lock)
       43         throws IOException
       44     {
       45         if (src instanceof DirectBuffer)
       46             return writeFromNativeBuffer(fd, src, position, nd, lock);
       47 
       48         // Substitute a native buffer
       49         int pos = src.position();
       50         int lim = src.limit();
       51         assert (pos <= lim);
       52         int rem = (pos <= lim ? lim - pos : 0);
       53         ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);
       54         try {
       55             bb.put(src);
       56             bb.flip();
       57             // Do not update src until we see how many bytes were written
       58             src.position(pos);
       59 
       60             int n = writeFromNativeBuffer(fd, bb, position, nd, lock);
       61             if (n > 0) {
       62                 // now update src
       63                 src.position(pos + n);
       64             }
       65             return n;
       66         } finally {
       67             Util.offerFirstTemporaryDirectBuffer(bb);
       68         }
       69     }
       70 
       71     private static int writeFromNativeBuffer(FileDescriptor fd, ByteBuffer bb,
       72                                            long position, NativeDispatcher nd,
       73                                              Object lock)
       74         throws IOException
       75     {
       76         int pos = bb.position();
       77         int lim = bb.limit();
       78         assert (pos <= lim);
       79         int rem = (pos <= lim ? lim - pos : 0);
       80 
       81         int written = 0;
       82         if (rem == 0)
       83             return 0;
       84         if (position != -1) {
       85             written = nd.pwrite(fd,
       86                                 ((DirectBuffer)bb).address() + pos,
       87                                 rem, position, lock);
       88         } else {
       89             written = nd.write(fd, ((DirectBuffer)bb).address() + pos, rem);
       90         }
       91         if (written > 0)
       92             bb.position(pos + written);
       93         return written;
       94     }
       95 
       96     static long write(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd)
       97         throws IOException
       98     {
       99         return write(fd, bufs, 0, bufs.length, nd);
      100     }
      101 
      102     static long write(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
      103                       NativeDispatcher nd)
      104         throws IOException
      105     {
      106         IOVecWrapper vec = IOVecWrapper.get(length);
      107 
      108         boolean completed = false;
      109         int iov_len = 0;
      110         try {
      111 
      112             // Iterate over buffers to populate native iovec array.
      113             int count = offset + length;
      114             for (int i=offset; i<count; i++) {
      115                 ByteBuffer buf = bufs[i];
      116                 int pos = buf.position();
      117                 int lim = buf.limit();
      118                 assert (pos <= lim);
      119                 int rem = (pos <= lim ? lim - pos : 0);
      120                 if (rem > 0) {
      121                     vec.setBuffer(iov_len, buf, pos, rem);
      122 
      123                     // allocate shadow buffer to ensure I/O is done with direct buffer
      124                     if (!(buf instanceof DirectBuffer)) {
      125                         ByteBuffer shadow = Util.getTemporaryDirectBuffer(rem);
      126                         shadow.put(buf);
      127                         shadow.flip();
      128                         vec.setShadow(iov_len, shadow);
      129                         buf.position(pos);  // temporarily restore position in user buffer
      130                         buf = shadow;
      131                         pos = shadow.position();
      132                     }
      133 
      134                     vec.putBase(iov_len, ((DirectBuffer)buf).address() + pos);
      135                     vec.putLen(iov_len, rem);
      136                     iov_len++;
      137                 }
      138             }
      139             if (iov_len == 0)
      140                 return 0L;
      141 
      142             long bytesWritten = nd.writev(fd, vec.address, iov_len);
      143 
      144             // Notify the buffers how many bytes were taken
      145             long left = bytesWritten;
      146             for (int j=0; j<iov_len; j++) {
      147                 if (left > 0) {
      148                     ByteBuffer buf = vec.getBuffer(j);
      149                     int pos = vec.getPosition(j);
      150                     int rem = vec.getRemaining(j);
      151                     int n = (left > rem) ? rem : (int)left;
      152                     buf.position(pos + n);
      153                     left -= n;
      154                 }
      155                 // return shadow buffers to buffer pool
      156                 ByteBuffer shadow = vec.getShadow(j);
      157                 if (shadow != null)
      158                     Util.offerLastTemporaryDirectBuffer(shadow);
      159                 vec.clearRefs(j);
      160             }
      161 
      162             completed = true;
      163             return bytesWritten;
      164 
      165         } finally {
      166             // if an error occurred then clear refs to buffers and return any shadow
      167             // buffers to cache
      168             if (!completed) {
      169                 for (int j=0; j<iov_len; j++) {
      170                     ByteBuffer shadow = vec.getShadow(j);
      171                     if (shadow != null)
      172                         Util.offerLastTemporaryDirectBuffer(shadow);
      173                     vec.clearRefs(j);
      174                 }
      175             }
      176         }
      177     }
      178 
      179     static int read(FileDescriptor fd, ByteBuffer dst, long position,
      180                     NativeDispatcher nd, Object lock)
      181         throws IOException
      182     {
      183         if (dst.isReadOnly())
      184             throw new IllegalArgumentException("Read-only buffer");
      185         if (dst instanceof DirectBuffer)
      186             return readIntoNativeBuffer(fd, dst, position, nd, lock);
      187 
      188         // Substitute a native buffer
      189         ByteBuffer bb = Util.getTemporaryDirectBuffer(dst.remaining());
      190         try {
      191             int n = readIntoNativeBuffer(fd, bb, position, nd, lock);
      192             bb.flip();
      193             if (n > 0)
      194                 dst.put(bb);
      195             return n;
      196         } finally {
      197             Util.offerFirstTemporaryDirectBuffer(bb);
      198         }
      199     }
      200 
      201     private static int readIntoNativeBuffer(FileDescriptor fd, ByteBuffer bb,
      202                                             long position, NativeDispatcher nd,
      203                                             Object lock)
      204         throws IOException
      205     {
      206         int pos = bb.position();
      207         int lim = bb.limit();
      208         assert (pos <= lim);
      209         int rem = (pos <= lim ? lim - pos : 0);
      210 
      211         if (rem == 0)
      212             return 0;
      213         int n = 0;
      214         if (position != -1) {
      215             n = nd.pread(fd, ((DirectBuffer)bb).address() + pos,
      216                          rem, position, lock);
      217         } else {
      218             n = nd.read(fd, ((DirectBuffer)bb).address() + pos, rem);
      219         }
      220         if (n > 0)
      221             bb.position(pos + n);
      222         return n;
      223     }
      224 
      225     static long read(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd)
      226         throws IOException
      227     {
      228         return read(fd, bufs, 0, bufs.length, nd);
      229     }
      230 
      231     static long read(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
      232                      NativeDispatcher nd)
      233         throws IOException
      234     {
      235         IOVecWrapper vec = IOVecWrapper.get(length);
      236 
      237         boolean completed = false;
      238         int iov_len = 0;
      239         try {
      240 
      241             // Iterate over buffers to populate native iovec array.
      242             int count = offset + length;
      243             for (int i=offset; i<count; i++) {
      244                 ByteBuffer buf = bufs[i];
      245                 if (buf.isReadOnly())
      246                     throw new IllegalArgumentException("Read-only buffer");
      247                 int pos = buf.position();
      248                 int lim = buf.limit();
      249                 assert (pos <= lim);
      250                 int rem = (pos <= lim ? lim - pos : 0);
      251 
      252                 if (rem > 0) {
      253                     vec.setBuffer(iov_len, buf, pos, rem);
      254 
      255                     // allocate shadow buffer to ensure I/O is done with direct buffer
      256                     if (!(buf instanceof DirectBuffer)) {
      257                         ByteBuffer shadow = Util.getTemporaryDirectBuffer(rem);
      258                         vec.setShadow(iov_len, shadow);
      259                         buf = shadow;
      260                         pos = shadow.position();
      261                     }
      262 
      263                     vec.putBase(iov_len, ((DirectBuffer)buf).address() + pos);
      264                     vec.putLen(iov_len, rem);
      265                     iov_len++;
      266                 }
      267             }
      268             if (iov_len == 0)
      269                 return 0L;
      270 
      271             long bytesRead = nd.readv(fd, vec.address, iov_len);
      272 
      273             // Notify the buffers how many bytes were read
      274             long left = bytesRead;
      275             for (int j=0; j<iov_len; j++) {
      276                 ByteBuffer shadow = vec.getShadow(j);
      277                 if (left > 0) {
      278                     ByteBuffer buf = vec.getBuffer(j);
      279                     int rem = vec.getRemaining(j);
      280                     int n = (left > rem) ? rem : (int)left;
      281                     if (shadow == null) {
      282                         int pos = vec.getPosition(j);
      283                         buf.position(pos + n);
      284                     } else {
      285                         shadow.limit(shadow.position() + n);
      286                         buf.put(shadow);
      287                     }
      288                     left -= n;
      289                 }
      290                 if (shadow != null)
      291                     Util.offerLastTemporaryDirectBuffer(shadow);
      292                 vec.clearRefs(j);
      293             }
      294 
      295             completed = true;
      296             return bytesRead;
      297 
      298         } finally {
      299             // if an error occurred then clear refs to buffers and return any shadow
      300             // buffers to cache
      301             if (!completed) {
      302                 for (int j=0; j<iov_len; j++) {
      303                     ByteBuffer shadow = vec.getShadow(j);
      304                     if (shadow != null)
      305                         Util.offerLastTemporaryDirectBuffer(shadow);
      306                     vec.clearRefs(j);
      307                 }
      308             }
      309         }
      310     }
      311 
      312     static FileDescriptor newFD(int i) {
      313         FileDescriptor fd = new FileDescriptor();
      314         setfdVal(fd, i);
      315         return fd;
      316     }
      317 
      318     static native boolean randomBytes(byte[] someBytes);
      319 
      320     /**
      321      * Returns two file descriptors for a pipe encoded in a long.
      322      * The read end of the pipe is returned in the high 32 bits,
      323      * while the write end is returned in the low 32 bits.
      324      */
      325     static native long makePipe(boolean blocking);
      326 
      327     static native boolean drain(int fd) throws IOException;
      328 
      329     static native void configureBlocking(FileDescriptor fd, boolean blocking)
      330         throws IOException;
      331 
      332     static native int fdVal(FileDescriptor fd);
      333 
      334     static native void setfdVal(FileDescriptor fd, int value);
      335 
      336     static native void initIDs();
      337 
      338     static {
      339         // Note that IOUtil.initIDs is called from within Util.load.
      340         Util.load();
      341     }
      342 
      343 }