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