/*
* Copyright ( c ) 2000 , 2022 , 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;
import java.util.Objects;
import jdk.internal.access.JavaNioAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.foreign.MemorySessionImpl;
/**
* File - descriptor based I / O utilities that are shared by NIO classes .
*/
public final class IOUtil {
/**
* Max number of iovec structures that readv / writev supports
*/
static final int IOV_MAX;
/**
* Max total number of bytes that writev supports
*/
static final long WRITEV_MAX;
private IOUtil() { } // No instantiation
static int write(FileDescriptor fd, ByteBuffer src, long position,
NativeDispatcher nd)
throws IOException
{
return write(fd, src, position, false , false , -1 , nd);
}
static int write(FileDescriptor fd, ByteBuffer src, long position,
boolean async, NativeDispatcher nd)
throws IOException
{
return write(fd, src, position, false , async, -1 , nd);
}
static int write(FileDescriptor fd, ByteBuffer src, long position,
boolean directIO, int alignment, NativeDispatcher nd)
throws IOException
{
return write(fd, src, position, directIO, false , alignment, nd);
}
static int write(FileDescriptor fd, ByteBuffer src, long position,
boolean directIO, boolean async, int alignment,
NativeDispatcher nd)
throws IOException
{
if (src instanceof DirectBuffer) {
return writeFromNativeBuffer(fd, src, position, directIO, async, alignment, nd);
}
// Substitute a native buffer
int pos = src.position();
int lim = src.limit();
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0 );
ByteBuffer bb;
if (directIO) {
Util.checkRemainingBufferSizeAligned(rem, alignment);
bb = Util.getTemporaryAlignedDirectBuffer(rem, alignment);
} else {
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, directIO, async, alignment, nd);
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, boolean directIO,
boolean async, int alignment,
NativeDispatcher nd)
throws IOException
{
int pos = bb.position();
int lim = bb.limit();
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0 );
if (directIO) {
Util.checkBufferPositionAligned(bb, pos, alignment);
Util.checkRemainingBufferSizeAligned(rem, alignment);
}
int written = 0 ;
if (rem == 0 )
return 0 ;
acquireScope(bb, async);
try {
if (position != -1 ) {
written = nd.pwrite(fd, bufferAddress(bb) + pos, rem, position);
} else {
written = nd.write(fd, bufferAddress(bb) + pos, rem);
}
} finally {
releaseScope(bb);
}
if (written > 0 )
bb.position(pos + written);
return written;
}
static long write(FileDescriptor fd, ByteBuffer[] bufs, boolean async,
NativeDispatcher nd)
throws IOException
{
return write(fd, bufs, 0 , bufs.length, false , async, -1 , nd);
}
static long write(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
NativeDispatcher nd)
throws IOException
{
return write(fd, bufs, offset, length, false , false , -1 , nd);
}
static long write(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
boolean direct, int alignment, NativeDispatcher nd)
throws IOException
{
return write(fd, bufs, offset, length, direct, false , alignment, nd);
}
static long write(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
boolean directIO, boolean async,
int alignment, NativeDispatcher nd)
throws IOException
{
IOVecWrapper vec = IOVecWrapper.get(length);
boolean completed = false ;
int iov_len = 0 ;
Runnable handleReleasers = null ;
try {
// Iterate over buffers to populate native iovec array.
long writevLen = 0 L;
int count = offset + length;
int i = offset;
while (i < count && iov_len < IOV_MAX && writevLen < WRITEV_MAX) {
ByteBuffer buf = bufs[i];
acquireScope(buf, async);
if (NIO_ACCESS.hasSession(buf)) {
handleReleasers = LinkedRunnable.of(Releaser.of(buf), handleReleasers);
}
int pos = buf.position();
int lim = buf.limit();
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0 );
if (directIO)
Util.checkRemainingBufferSizeAligned(rem, alignment);
if (rem > 0 ) {
long headroom = WRITEV_MAX - writevLen;
if (headroom < rem)
rem = (int )headroom;
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;
if (directIO)
shadow = Util.getTemporaryAlignedDirectBuffer(rem, alignment);
else
shadow = Util.getTemporaryDirectBuffer(rem);
shadow.put(shadow.position(), buf, pos, rem);
shadow.flip();
vec.setShadow(iov_len, shadow);
buf = shadow;
pos = shadow.position();
}
vec.putBase(iov_len, bufferAddress(buf) + pos);
vec.putLen(iov_len, rem);
iov_len++;
writevLen += rem;
}
i++;
}
if (iov_len == 0 )
return 0 L;
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 {
releaseScopes(handleReleasers);
// 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)
throws IOException
{
return read(fd, dst, position, false , false , -1 , nd);
}
static int read(FileDescriptor fd, ByteBuffer dst, long position,
boolean async, NativeDispatcher nd)
throws IOException
{
return read(fd, dst, position, false , async, -1 , nd);
}
static int read(FileDescriptor fd, ByteBuffer dst, long position,
boolean directIO, int alignment, NativeDispatcher nd)
throws IOException
{
return read(fd, dst, position, directIO, false , alignment, nd);
}
static int read(FileDescriptor fd, ByteBuffer dst, long position,
boolean directIO, boolean async,
int alignment, NativeDispatcher nd)
throws IOException
{
if (dst.isReadOnly())
throw new IllegalArgumentException("Read-only buffer" );
if (dst instanceof DirectBuffer)
return readIntoNativeBuffer(fd, dst, position, directIO, async, alignment, nd);
// Substitute a native buffer
ByteBuffer bb;
int rem = dst.remaining();
if (directIO) {
Util.checkRemainingBufferSizeAligned(rem, alignment);
bb = Util.getTemporaryAlignedDirectBuffer(rem, alignment);
} else {
bb = Util.getTemporaryDirectBuffer(rem);
}
try {
int n = readIntoNativeBuffer(fd, bb, position, directIO, async, alignment, nd);
bb.flip();
if (n > 0 )
dst.put(bb);
return n;
} finally {
Util.offerFirstTemporaryDirectBuffer(bb);
}
}
private static int readIntoNativeBuffer(FileDescriptor fd, ByteBuffer bb,
long position, boolean directIO,
boolean async, int alignment,
NativeDispatcher nd)
throws IOException
{
int pos = bb.position();
int lim = bb.limit();
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0 );
if (directIO) {
Util.checkBufferPositionAligned(bb, pos, alignment);
Util.checkRemainingBufferSizeAligned(rem, alignment);
}
if (rem == 0 )
return 0 ;
int n = 0 ;
acquireScope(bb, async);
try {
if (position != -1 ) {
n = nd.pread(fd, bufferAddress(bb) + pos, rem, position);
} else {
n = nd.read(fd, bufferAddress(bb) + pos, rem);
}
} finally {
releaseScope(bb);
}
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, false , false , -1 , nd);
}
static long read(FileDescriptor fd, ByteBuffer[] bufs, boolean async,
NativeDispatcher nd)
throws IOException
{
return read(fd, bufs, 0 , bufs.length, false , async, -1 , nd);
}
static long read(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
NativeDispatcher nd)
throws IOException
{
return read(fd, bufs, offset, length, false , false , -1 , nd);
}
static long read(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
boolean directIO, int alignment, NativeDispatcher nd)
throws IOException
{
return read(fd, bufs, offset, length, directIO, false , alignment, nd);
}
static long read(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
boolean directIO, boolean async,
int alignment, NativeDispatcher nd)
throws IOException
{
IOVecWrapper vec = IOVecWrapper.get(length);
boolean completed = false ;
int iov_len = 0 ;
Runnable handleReleasers = null ;
try {
// Iterate over buffers to populate native iovec array.
int count = offset + length;
int i = offset;
while (i < count && iov_len < IOV_MAX) {
ByteBuffer buf = bufs[i];
if (buf.isReadOnly())
throw new IllegalArgumentException("Read-only buffer" );
acquireScope(buf, async);
if (NIO_ACCESS.hasSession(buf)) {
handleReleasers = LinkedRunnable.of(Releaser.of(buf), handleReleasers);
}
int pos = buf.position();
int lim = buf.limit();
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0 );
if (directIO)
Util.checkRemainingBufferSizeAligned(rem, alignment);
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;
if (directIO) {
shadow = Util.getTemporaryAlignedDirectBuffer(rem, alignment);
} else {
shadow = Util.getTemporaryDirectBuffer(rem);
}
vec.setShadow(iov_len, shadow);
buf = shadow;
pos = shadow.position();
}
vec.putBase(iov_len, bufferAddress(buf) + pos);
vec.putLen(iov_len, rem);
iov_len++;
}
i++;
}
if (iov_len == 0 )
return 0 L;
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 {
releaseScopes(handleReleasers);
// 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);
}
}
}
}
private static final JavaNioAccess NIO_ACCESS = SharedSecrets.getJavaNioAccess();
static void acquireScope(ByteBuffer bb, boolean async) {
if (async && NIO_ACCESS.isThreadConfined(bb)) {
throw new IllegalStateException("Confined session not supported" );
}
NIO_ACCESS.acquireSession(bb);
}
private static void releaseScope(ByteBuffer bb) {
try {
NIO_ACCESS.releaseSession(bb);
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
static Runnable acquireScopes(ByteBuffer[] buffers) {
return acquireScopes(null , buffers);
}
static Runnable acquireScopes(ByteBuffer buf, ByteBuffer[] buffers) {
if (buffers == null ) {
assert buf != null ;
IOUtil.acquireScope(buf, true );
return IOUtil.Releaser.of(buf);
} else {
assert buf == null ;
Runnable handleReleasers = null ;
for (var b : buffers) {
IOUtil.acquireScope(b, true );
handleReleasers = IOUtil.LinkedRunnable.of(IOUtil.Releaser.of(b), handleReleasers);
}
return handleReleasers;
}
}
static void releaseScopes(Runnable releasers) {
if (releasers != null )
releasers.run();
}
record LinkedRunnable(Runnable node, Runnable next) implements Runnable {
LinkedRunnable {
Objects.requireNonNull(node);
}
@Override
public void run() {
try {
node.run();
} finally {
if (next != null )
next.run();
}
}
static LinkedRunnable of(Runnable first, Runnable second) {
return new LinkedRunnable(first, second);
}
}
record Releaser(ByteBuffer bb) implements Runnable {
Releaser {
Objects.requireNonNull(bb);
}
@Override
public void run() {
releaseScope(bb);
}
static Runnable of(ByteBuffer bb) {
return NIO_ACCESS.hasSession(bb)
? new Releaser(bb)
: () -> {};
}
}
static long bufferAddress(ByteBuffer buf) {
return NIO_ACCESS.getBufferAddress(buf);
}
public 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) throws IOException;
static native int write1(int fd, byte b) throws IOException;
/**
* Read and discard all bytes .
*/
static native boolean drain(int fd) throws IOException;
/**
* Read and discard at most one byte
* @ return the number of bytes read or IOS_INTERRUPTED
*/
static native int drain1(int fd) throws IOException;
public static native void configureBlocking(FileDescriptor fd,
boolean blocking)
throws IOException;
public static native int fdVal(FileDescriptor fd);
static native void setfdVal(FileDescriptor fd, int value);
static native int fdLimit();
static native int iovMax();
static native long writevMax();
static native void initIDs();
/**
* Used to trigger loading of native libraries
*/
public static void load() { }
static {
jdk.internal.loader.BootLoader.loadLibrary("net" );
jdk.internal.loader.BootLoader.loadLibrary("nio" );
initIDs();
IOV_MAX = iovMax();
WRITEV_MAX = writevMax();
}
}
Messung V0.5 in Prozent C=95 H=81 G=88
¤ Dauer der Verarbeitung: 0.10 Sekunden
¤
*© Formatika GbR, Deutschland