343 lines · 11.7 KB · Java
RawDownload
/* * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.nio.ch; import java.io.FileDescriptor;import java.io.IOException;import java.nio.ByteBuffer;  /** * File-descriptor based I/O utilities that are shared by NIO classes. */ class IOUtil {     private IOUtil() { }                // No instantiation     static int write(FileDescriptor fd, ByteBuffer src, long position,                     NativeDispatcher nd, Object lock)        throws IOException    {        if (src instanceof DirectBuffer)            return writeFromNativeBuffer(fd, src, position, nd, lock);         // Substitute a native buffer        int pos = src.position();        int lim = src.limit();        assert (pos <= lim);        int rem = (pos <= lim ? lim - pos : 0);        ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);        try {            bb.put(src);            bb.flip();            // Do not update src until we see how many bytes were written            src.position(pos);             int n = writeFromNativeBuffer(fd, bb, position, nd, lock);            if (n > 0) {                // now update src                src.position(pos + n);            }            return n;        } finally {            Util.offerFirstTemporaryDirectBuffer(bb);        }    }     private static int writeFromNativeBuffer(FileDescriptor fd, ByteBuffer bb,                                           long position, NativeDispatcher nd,                                             Object lock)        throws IOException    {        int pos = bb.position();        int lim = bb.limit();        assert (pos <= lim);        int rem = (pos <= lim ? lim - pos : 0);         int written = 0;        if (rem == 0)            return 0;        if (position != -1) {            written = nd.pwrite(fd,                                ((DirectBuffer)bb).address() + pos,                                rem, position, lock);        } else {            written = nd.write(fd, ((DirectBuffer)bb).address() + pos, rem);        }        if (written > 0)            bb.position(pos + written);        return written;    }     static long write(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd)        throws IOException    {        return write(fd, bufs, 0, bufs.length, nd);    }     static long write(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,                      NativeDispatcher nd)        throws IOException    {        IOVecWrapper vec = IOVecWrapper.get(length);         boolean completed = false;        int iov_len = 0;        try {             // Iterate over buffers to populate native iovec array.            int count = offset + length;            for (int i=offset; i<count; i++) {                ByteBuffer buf = bufs[i];                int pos = buf.position();                int lim = buf.limit();                assert (pos <= lim);                int rem = (pos <= lim ? lim - pos : 0);                if (rem > 0) {                    vec.setBuffer(iov_len, buf, pos, rem);                     // allocate shadow buffer to ensure I/O is done with direct buffer                    if (!(buf instanceof DirectBuffer)) {                        ByteBuffer shadow = Util.getTemporaryDirectBuffer(rem);                        shadow.put(buf);                        shadow.flip();                        vec.setShadow(iov_len, shadow);                        buf.position(pos);  // temporarily restore position in user buffer                        buf = shadow;                        pos = shadow.position();                    }                     vec.putBase(iov_len, ((DirectBuffer)buf).address() + pos);                    vec.putLen(iov_len, rem);                    iov_len++;                }            }            if (iov_len == 0)                return 0L;             long bytesWritten = nd.writev(fd, vec.address, iov_len);             // Notify the buffers how many bytes were taken            long left = bytesWritten;            for (int j=0; j<iov_len; j++) {                if (left > 0) {                    ByteBuffer buf = vec.getBuffer(j);                    int pos = vec.getPosition(j);                    int rem = vec.getRemaining(j);                    int n = (left > rem) ? rem : (int)left;                    buf.position(pos + n);                    left -= n;                }                // return shadow buffers to buffer pool                ByteBuffer shadow = vec.getShadow(j);                if (shadow != null)                    Util.offerLastTemporaryDirectBuffer(shadow);                vec.clearRefs(j);            }             completed = true;            return bytesWritten;         } finally {            // if an error occurred then clear refs to buffers and return any shadow            // buffers to cache            if (!completed) {                for (int j=0; j<iov_len; j++) {                    ByteBuffer shadow = vec.getShadow(j);                    if (shadow != null)                        Util.offerLastTemporaryDirectBuffer(shadow);                    vec.clearRefs(j);                }            }        }    }     static int read(FileDescriptor fd, ByteBuffer dst, long position,                    NativeDispatcher nd, Object lock)        throws IOException    {        if (dst.isReadOnly())            throw new IllegalArgumentException("Read-only buffer");        if (dst instanceof DirectBuffer)            return readIntoNativeBuffer(fd, dst, position, nd, lock);         // Substitute a native buffer        ByteBuffer bb = Util.getTemporaryDirectBuffer(dst.remaining());        try {            int n = readIntoNativeBuffer(fd, bb, position, nd, lock);            bb.flip();            if (n > 0)                dst.put(bb);            return n;        } finally {            Util.offerFirstTemporaryDirectBuffer(bb);        }    }     private static int readIntoNativeBuffer(FileDescriptor fd, ByteBuffer bb,                                            long position, NativeDispatcher nd,                                            Object lock)        throws IOException    {        int pos = bb.position();        int lim = bb.limit();        assert (pos <= lim);        int rem = (pos <= lim ? lim - pos : 0);         if (rem == 0)            return 0;        int n = 0;        if (position != -1) {            n = nd.pread(fd, ((DirectBuffer)bb).address() + pos,                         rem, position, lock);        } else {            n = nd.read(fd, ((DirectBuffer)bb).address() + pos, rem);        }        if (n > 0)            bb.position(pos + n);        return n;    }     static long read(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd)        throws IOException    {        return read(fd, bufs, 0, bufs.length, nd);    }     static long read(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,                     NativeDispatcher nd)        throws IOException    {        IOVecWrapper vec = IOVecWrapper.get(length);         boolean completed = false;        int iov_len = 0;        try {             // Iterate over buffers to populate native iovec array.            int count = offset + length;            for (int i=offset; i<count; i++) {                ByteBuffer buf = bufs[i];                if (buf.isReadOnly())                    throw new IllegalArgumentException("Read-only buffer");                int pos = buf.position();                int lim = buf.limit();                assert (pos <= lim);                int rem = (pos <= lim ? lim - pos : 0);                 if (rem > 0) {                    vec.setBuffer(iov_len, buf, pos, rem);                     // allocate shadow buffer to ensure I/O is done with direct buffer                    if (!(buf instanceof DirectBuffer)) {                        ByteBuffer shadow = Util.getTemporaryDirectBuffer(rem);                        vec.setShadow(iov_len, shadow);                        buf = shadow;                        pos = shadow.position();                    }                     vec.putBase(iov_len, ((DirectBuffer)buf).address() + pos);                    vec.putLen(iov_len, rem);                    iov_len++;                }            }            if (iov_len == 0)                return 0L;             long bytesRead = nd.readv(fd, vec.address, iov_len);             // Notify the buffers how many bytes were read            long left = bytesRead;            for (int j=0; j<iov_len; j++) {                ByteBuffer shadow = vec.getShadow(j);                if (left > 0) {                    ByteBuffer buf = vec.getBuffer(j);                    int rem = vec.getRemaining(j);                    int n = (left > rem) ? rem : (int)left;                    if (shadow == null) {                        int pos = vec.getPosition(j);                        buf.position(pos + n);                    } else {                        shadow.limit(shadow.position() + n);                        buf.put(shadow);                    }                    left -= n;                }                if (shadow != null)                    Util.offerLastTemporaryDirectBuffer(shadow);                vec.clearRefs(j);            }             completed = true;            return bytesRead;         } finally {            // if an error occurred then clear refs to buffers and return any shadow            // buffers to cache            if (!completed) {                for (int j=0; j<iov_len; j++) {                    ByteBuffer shadow = vec.getShadow(j);                    if (shadow != null)                        Util.offerLastTemporaryDirectBuffer(shadow);                    vec.clearRefs(j);                }            }        }    }     static FileDescriptor newFD(int i) {        FileDescriptor fd = new FileDescriptor();        setfdVal(fd, i);        return fd;    }     static native boolean randomBytes(byte[] someBytes);     /**     * Returns two file descriptors for a pipe encoded in a long.     * The read end of the pipe is returned in the high 32 bits,     * while the write end is returned in the low 32 bits.     */    static native long makePipe(boolean blocking);     static native boolean drain(int fd) throws IOException;     static native void configureBlocking(FileDescriptor fd, boolean blocking)        throws IOException;     static native int fdVal(FileDescriptor fd);     static native void setfdVal(FileDescriptor fd, int value);     static native void initIDs();     static {        // Note that IOUtil.initIDs is called from within Util.load.        Util.load();    } }