Home | History | Annotate | Download | only in ch
      1 /*
      2  * Copyright (c) 2000, 2013, 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 public class IOUtil {
     38 
     39     /**
     40      * Max number of iovec structures that readv/writev supports
     41      */
     42     static final int IOV_MAX;
     43 
     44     private IOUtil() { }                // No instantiation
     45 
     46     static int write(FileDescriptor fd, ByteBuffer src, long position,
     47                      NativeDispatcher nd)
     48         throws IOException
     49     {
     50         if (src instanceof DirectBuffer)
     51             return writeFromNativeBuffer(fd, src, position, nd);
     52 
     53         // Substitute a native buffer
     54         int pos = src.position();
     55         int lim = src.limit();
     56         assert (pos <= lim);
     57         int rem = (pos <= lim ? lim - pos : 0);
     58         ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);
     59         try {
     60             bb.put(src);
     61             bb.flip();
     62             // Do not update src until we see how many bytes were written
     63             src.position(pos);
     64 
     65             int n = writeFromNativeBuffer(fd, bb, position, nd);
     66             if (n > 0) {
     67                 // now update src
     68                 src.position(pos + n);
     69             }
     70             return n;
     71         } finally {
     72             Util.offerFirstTemporaryDirectBuffer(bb);
     73         }
     74     }
     75 
     76     private static int writeFromNativeBuffer(FileDescriptor fd, ByteBuffer bb,
     77                                              long position, NativeDispatcher nd)
     78         throws IOException
     79     {
     80         int pos = bb.position();
     81         int lim = bb.limit();
     82         assert (pos <= lim);
     83         int rem = (pos <= lim ? lim - pos : 0);
     84 
     85         int written = 0;
     86         if (rem == 0)
     87             return 0;
     88         if (position != -1) {
     89             written = nd.pwrite(fd,
     90                                 ((DirectBuffer)bb).address() + pos,
     91                                 rem, position);
     92         } else {
     93             written = nd.write(fd, ((DirectBuffer)bb).address() + pos, rem);
     94         }
     95         if (written > 0)
     96             bb.position(pos + written);
     97         return written;
     98     }
     99 
    100     static long write(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd)
    101         throws IOException
    102     {
    103         return write(fd, bufs, 0, bufs.length, nd);
    104     }
    105 
    106     static long write(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
    107                       NativeDispatcher nd)
    108         throws IOException
    109     {
    110         IOVecWrapper vec = IOVecWrapper.get(length);
    111 
    112         boolean completed = false;
    113         int iov_len = 0;
    114         try {
    115 
    116             // Iterate over buffers to populate native iovec array.
    117             int count = offset + length;
    118             int i = offset;
    119             while (i < count && iov_len < IOV_MAX) {
    120                 ByteBuffer buf = bufs[i];
    121                 int pos = buf.position();
    122                 int lim = buf.limit();
    123                 assert (pos <= lim);
    124                 int rem = (pos <= lim ? lim - pos : 0);
    125                 if (rem > 0) {
    126                     vec.setBuffer(iov_len, buf, pos, rem);
    127 
    128                     // allocate shadow buffer to ensure I/O is done with direct buffer
    129                     if (!(buf instanceof DirectBuffer)) {
    130                         ByteBuffer shadow = Util.getTemporaryDirectBuffer(rem);
    131                         shadow.put(buf);
    132                         shadow.flip();
    133                         vec.setShadow(iov_len, shadow);
    134                         buf.position(pos);  // temporarily restore position in user buffer
    135                         buf = shadow;
    136                         pos = shadow.position();
    137                     }
    138 
    139                     vec.putBase(iov_len, ((DirectBuffer)buf).address() + pos);
    140                     vec.putLen(iov_len, rem);
    141                     iov_len++;
    142                 }
    143                 i++;
    144             }
    145             if (iov_len == 0)
    146                 return 0L;
    147 
    148             long bytesWritten = nd.writev(fd, vec.address, iov_len);
    149 
    150             // Notify the buffers how many bytes were taken
    151             long left = bytesWritten;
    152             for (int j=0; j<iov_len; j++) {
    153                 if (left > 0) {
    154                     ByteBuffer buf = vec.getBuffer(j);
    155                     int pos = vec.getPosition(j);
    156                     int rem = vec.getRemaining(j);
    157                     int n = (left > rem) ? rem : (int)left;
    158                     buf.position(pos + n);
    159                     left -= n;
    160                 }
    161                 // return shadow buffers to buffer pool
    162                 ByteBuffer shadow = vec.getShadow(j);
    163                 if (shadow != null)
    164                     Util.offerLastTemporaryDirectBuffer(shadow);
    165                 vec.clearRefs(j);
    166             }
    167 
    168             completed = true;
    169             return bytesWritten;
    170 
    171         } finally {
    172             // if an error occurred then clear refs to buffers and return any shadow
    173             // buffers to cache
    174             if (!completed) {
    175                 for (int j=0; j<iov_len; j++) {
    176                     ByteBuffer shadow = vec.getShadow(j);
    177                     if (shadow != null)
    178                         Util.offerLastTemporaryDirectBuffer(shadow);
    179                     vec.clearRefs(j);
    180                 }
    181             }
    182         }
    183     }
    184 
    185     static int read(FileDescriptor fd, ByteBuffer dst, long position,
    186                     NativeDispatcher nd)
    187         throws IOException
    188     {
    189         if (dst.isReadOnly())
    190             throw new IllegalArgumentException("Read-only buffer");
    191         if (dst instanceof DirectBuffer)
    192             return readIntoNativeBuffer(fd, dst, position, nd);
    193 
    194         // Substitute a native buffer
    195         ByteBuffer bb = Util.getTemporaryDirectBuffer(dst.remaining());
    196         try {
    197             int n = readIntoNativeBuffer(fd, bb, position, nd);
    198             bb.flip();
    199             if (n > 0)
    200                 dst.put(bb);
    201             return n;
    202         } finally {
    203             Util.offerFirstTemporaryDirectBuffer(bb);
    204         }
    205     }
    206 
    207     private static int readIntoNativeBuffer(FileDescriptor fd, ByteBuffer bb,
    208                                             long position, NativeDispatcher nd)
    209         throws IOException
    210     {
    211         int pos = bb.position();
    212         int lim = bb.limit();
    213         assert (pos <= lim);
    214         int rem = (pos <= lim ? lim - pos : 0);
    215 
    216         if (rem == 0)
    217             return 0;
    218         int n = 0;
    219         if (position != -1) {
    220             n = nd.pread(fd, ((DirectBuffer)bb).address() + pos,
    221                          rem, position);
    222         } else {
    223             n = nd.read(fd, ((DirectBuffer)bb).address() + pos, rem);
    224         }
    225         if (n > 0)
    226             bb.position(pos + n);
    227         return n;
    228     }
    229 
    230     static long read(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd)
    231         throws IOException
    232     {
    233         return read(fd, bufs, 0, bufs.length, nd);
    234     }
    235 
    236     static long read(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
    237                      NativeDispatcher nd)
    238         throws IOException
    239     {
    240         IOVecWrapper vec = IOVecWrapper.get(length);
    241 
    242         boolean completed = false;
    243         int iov_len = 0;
    244         try {
    245 
    246             // Iterate over buffers to populate native iovec array.
    247             int count = offset + length;
    248             int i = offset;
    249             while (i < count && iov_len < IOV_MAX) {
    250                 ByteBuffer buf = bufs[i];
    251                 if (buf.isReadOnly())
    252                     throw new IllegalArgumentException("Read-only buffer");
    253                 int pos = buf.position();
    254                 int lim = buf.limit();
    255                 assert (pos <= lim);
    256                 int rem = (pos <= lim ? lim - pos : 0);
    257 
    258                 if (rem > 0) {
    259                     vec.setBuffer(iov_len, buf, pos, rem);
    260 
    261                     // allocate shadow buffer to ensure I/O is done with direct buffer
    262                     if (!(buf instanceof DirectBuffer)) {
    263                         ByteBuffer shadow = Util.getTemporaryDirectBuffer(rem);
    264                         vec.setShadow(iov_len, shadow);
    265                         buf = shadow;
    266                         pos = shadow.position();
    267                     }
    268 
    269                     vec.putBase(iov_len, ((DirectBuffer)buf).address() + pos);
    270                     vec.putLen(iov_len, rem);
    271                     iov_len++;
    272                 }
    273                 i++;
    274             }
    275             if (iov_len == 0)
    276                 return 0L;
    277 
    278             long bytesRead = nd.readv(fd, vec.address, iov_len);
    279 
    280             // Notify the buffers how many bytes were read
    281             long left = bytesRead;
    282             for (int j=0; j<iov_len; j++) {
    283                 ByteBuffer shadow = vec.getShadow(j);
    284                 if (left > 0) {
    285                     ByteBuffer buf = vec.getBuffer(j);
    286                     int rem = vec.getRemaining(j);
    287                     int n = (left > rem) ? rem : (int)left;
    288                     if (shadow == null) {
    289                         int pos = vec.getPosition(j);
    290                         buf.position(pos + n);
    291                     } else {
    292                         shadow.limit(shadow.position() + n);
    293                         buf.put(shadow);
    294                     }
    295                     left -= n;
    296                 }
    297                 if (shadow != null)
    298                     Util.offerLastTemporaryDirectBuffer(shadow);
    299                 vec.clearRefs(j);
    300             }
    301 
    302             completed = true;
    303             return bytesRead;
    304 
    305         } finally {
    306             // if an error occurred then clear refs to buffers and return any shadow
    307             // buffers to cache
    308             if (!completed) {
    309                 for (int j=0; j<iov_len; j++) {
    310                     ByteBuffer shadow = vec.getShadow(j);
    311                     if (shadow != null)
    312                         Util.offerLastTemporaryDirectBuffer(shadow);
    313                     vec.clearRefs(j);
    314                 }
    315             }
    316         }
    317     }
    318 
    319     public static FileDescriptor newFD(int i) {
    320         FileDescriptor fd = new FileDescriptor();
    321         setfdVal(fd, i);
    322         return fd;
    323     }
    324 
    325     static native boolean randomBytes(byte[] someBytes);
    326 
    327     /**
    328      * Returns two file descriptors for a pipe encoded in a long.
    329      * The read end of the pipe is returned in the high 32 bits,
    330      * while the write end is returned in the low 32 bits.
    331      */
    332     static native long makePipe(boolean blocking);
    333 
    334     static native boolean drain(int fd) throws IOException;
    335 
    336     public static native void configureBlocking(FileDescriptor fd,
    337                                                 boolean blocking)
    338         throws IOException;
    339 
    340     public static native int fdVal(FileDescriptor fd);
    341 
    342     static native void setfdVal(FileDescriptor fd, int value);
    343 
    344     static native int fdLimit();
    345 
    346     static native int iovMax();
    347 
    348     // Android-removed: Code to load native libraries, doesn't make sense on Android.
    349     /*
    350     static native void initIDs();
    351 
    352     /**
    353      * Used to trigger loading of native libraries
    354      *
    355     public static void load() { }
    356     */
    357 
    358     static {
    359         // Android-removed: Code to load native libraries, doesn't make sense on Android.
    360         /*
    361         java.security.AccessController.doPrivileged(
    362                 new java.security.PrivilegedAction<Void>() {
    363                     public Void run() {
    364                         System.loadLibrary("net");
    365                         System.loadLibrary("nio");
    366                         return null;
    367                     }
    368                 });
    369 
    370         initIDs();
    371         */
    372 
    373         IOV_MAX = iovMax();
    374     }
    375 
    376 }
    377