/* * @(#) $(JCGO)/goclsp/vm/gnu/java/nio/VMChannel.java -- * VM specific channel operations implementation. ** * Project: JCGO (http://www.ivmaisoft.com/jcgo/) * Copyright (C) 2001-2009 Ivan Maidanski <ivmai@ivmaisoft.com> * All rights reserved. ** * Class specification origin: GNU Classpath v0.93 vm/reference */ /* * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. ** * This software 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 (GPL) for more details. ** * Linking this library statically or dynamically with other modules is * making a combined work based on this library. Thus, the terms and * conditions of the GNU General Public License cover the whole * combination. ** * As a special exception, the copyright holders of this library give you * permission to link this library with independent modules to produce an * executable, regardless of the license terms of these independent * modules, and to copy and distribute the resulting executable under * terms of your choice, provided that you also meet, for each linked * independent module, the terms and conditions of the license of that * module. An independent module is a module which is not derived from * or based on this library. If you modify this library, you may extend * this exception to your version of the library, but you are not * obligated to do so. If you do not wish to do so, delete this * exception statement from your version. */ package gnu.java.nio; import gnu.java.net.VMAccessorGnuJavaNet; import java.io.File; import java.io.IOException; import java.io.InterruptedIOException; import java.io.SyncFailedException; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.NonReadableChannelException; import java.nio.channels.NonWritableChannelException; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.net.SocketException; public final class VMChannel { private static abstract class Handle { /* used by VM classes only */ Handle() {} abstract int getNativeFD() throws IOException; abstract void setNonBlocking(boolean on) throws IOException; abstract int available() throws IOException; abstract int read(byte[] buffer, int off, int len) throws IOException; abstract void write(byte[] buffer, int[] offArr, int len) throws IOException; abstract void flush(boolean metadata) throws IOException; abstract void close() throws IOException; abstract boolean needsCloseOnFinalize(); } private static final class FileHandle extends Handle { /* used by VM classes only */ private int fd = -1; private final int mode; private boolean isNonBlocking; FileHandle(int mode) { this.mode = mode; } int getNativeFD() throws IOException { int fd = this.fd; if (fd == -1) throw new IOException("invalid file descriptor"); return fd; } void setNonBlocking(boolean on) throws IOException { getNativeFD(); isNonBlocking = on; } synchronized int available() throws IOException { int fd = getNativeFD(); return (mode & FileChannelImpl.READ) != 0 ? fileAvailable(fd) : 0; } synchronized int read(byte[] buffer, int off, int len) throws IOException { int fd = getNativeFD(); if ((mode & FileChannelImpl.READ) == 0) throw new NonReadableChannelException(); return fileRead(fd, buffer, off, len, isNonBlocking); } synchronized void write(byte[] buffer, int[] offArr, int len) throws IOException { int fd = getNativeFD(); if ((mode & FileChannelImpl.WRITE) == 0) throw new NonWritableChannelException(); fileWrite(fd, buffer, offArr, len, isNonBlocking); } void flush(boolean metadata) throws IOException { int fd = getNativeFD(); if ((mode & FileChannelImpl.WRITE) != 0) fileFlush(fd, metadata); } void close() throws IOException { int fd = this.fd; this.fd = -1; VMChannel.close(fd); } boolean needsCloseOnFinalize() { return !isStdInOutErr(fd); } void setNativeFD(int fd) throws IOException { if (this.fd != -1) throw new IOException("file descriptor already initialized"); this.fd = fd; } synchronized long position() throws IOException { return filePosition(getNativeFD()); } synchronized void seek(long newPosition) throws IOException { fileSeek(getNativeFD(), newPosition); } synchronized void truncate(long size) throws IOException { fileTruncate(getNativeFD(), size); } synchronized long size() throws IOException { return fileSize(getNativeFD()); } synchronized boolean lock(long pos, long len, boolean shared, boolean wait) throws IOException { return fileLock(getNativeFD(), pos, len, shared, wait); } synchronized void unlock(long pos, long len) throws IOException { fileUnlock(getNativeFD(), pos, len); } } private static final class SocketHandle extends Handle { /* used by VM classes only */ private int fd = -1; private final boolean stream; private boolean isNonBlocking; private boolean isConnectPending; private InetSocketAddress peerSocketAddress; SocketHandle(boolean stream) { this.stream = stream; } int getNativeFD() throws IOException { int fd = this.fd; if (fd == -1) throw new IOException("invalid file descriptor"); return fd; } void setNonBlocking(boolean on) throws IOException { int fd = getNativeFD(); if (isNonBlocking != on) { VMAccessorGnuJavaNet.socketSetNonBlockingVMPlainSocketImpl(fd, on); isNonBlocking = on; } } int available() throws IOException { return VMAccessorGnuJavaNet.socketAvailableVMPlainSocketImpl( getNativeFD()); } int read(byte[] buffer, int off, int len) throws IOException { int fd = getNativeFD(); if (peerSocketAddress == null || isConnectPending) throw new SocketException("not connected"); int[] offArr = { off }; VMAccessorGnuJavaNet.socketRecvFromVMPlainSocketImpl(fd, buffer, offArr, len, false, false, false, stream, isNonBlocking); return offArr[0] - off; } void write(byte[] buffer, int[] offArr, int len) throws IOException { int fd = getNativeFD(); if (peerSocketAddress == null || isConnectPending) throw new SocketException("not connected"); VMAccessorGnuJavaNet.socketSendToVMPlainSocketImpl(fd, buffer, offArr, len, null, false, isNonBlocking); } void flush(boolean metadata) throws IOException { throw new IOException("not a file"); } void close() throws IOException { int fd = this.fd; this.fd = -1; if (fd != -1) VMAccessorGnuJavaNet.socketCloseVMPlainSocketImpl(fd); } boolean needsCloseOnFinalize() { return true; } void setNativeFD(int fd) throws IOException { if (this.fd != -1) throw new IOException("file descriptor already initialized"); this.fd = fd; } InetSocketAddress receive(byte[] buffer, int[] offArr, int len) throws IOException { return VMAccessorGnuJavaNet.socketRecvFromVMPlainSocketImpl( getDatagramSocketFD(), buffer, offArr, len, false, false, true, stream, isNonBlocking); } void send(byte[] buffer, int[] offArr, int len, InetSocketAddress address) throws IOException { VMAccessorGnuJavaNet.socketSendToVMPlainSocketImpl(getDatagramSocketFD(), buffer, offArr, len, address, false, isNonBlocking); } VMChannel accept() throws IOException { int[] fdArr = { getNativeFD() }; if (!stream) throw new SocketException("not a stream socket"); InetSocketAddress address = VMAccessorGnuJavaNet.socketAcceptVMPlainSocketImpl(fdArr, isNonBlocking); VMChannel ch = null; if (address != null) { try { ch = new VMChannel(); } catch (OutOfMemoryError e) { if (fdArr[0] != -1) { try { VMAccessorGnuJavaNet.socketCloseVMPlainSocketImpl(fdArr[0]); } catch (IOException ex) {} } throw e; } State chState = ch.getState(); chState.setNativeSocketFD(fdArr[0], true); chState.getSocketHandle().peerSocketAddress = address; } return ch; } boolean connect(InetSocketAddress address, int timeout) throws IOException { if (address == null) throw new NullPointerException(); int fd = getNativeFD(); if (peerSocketAddress != null) throw new SocketException(isConnectPending ? "connection pending" : "already connected"); boolean completed = false; try { isConnectPending = true; peerSocketAddress = address; if (VMAccessorGnuJavaNet.socketConnectVMPlainSocketImpl(fd, address, isNonBlocking ? 0 : timeout != 0 ? timeout : -1)) isConnectPending = false; completed = true; } finally { if (!completed) { peerSocketAddress = null; isConnectPending = false; } } return !isConnectPending; } InetSocketAddress getPeerSocketAddress() throws IOException { InetSocketAddress address = peerSocketAddress; if (address != null && isConnectPending) { try { if (!VMAccessorGnuJavaNet.socketConnectVMPlainSocketImpl(getNativeFD(), address, 0)) return null; } catch (IOException e) { peerSocketAddress = null; isConnectPending = false; throw e; } isConnectPending = false; } return address; } void disconnect() throws IOException { VMAccessorGnuJavaNet.socketDisconnectVMPlainSocketImpl( getDatagramSocketFD()); peerSocketAddress = null; } private int getDatagramSocketFD() throws IOException { int fd = this.fd; if (fd == -1) throw new IOException("invalid file descriptor"); if (stream) throw new SocketException("not a datagram socket"); return fd; } } public final class State { private Handle handle; private boolean closed; State() {} public boolean isValid() { return handle != null; } public boolean isClosed() { return closed; } public int getNativeFD() throws IOException { return getHandle().getNativeFD(); } void setNativeFD(int fileFd) throws IOException { setNativeFileFD(fileFd, FileChannelImpl.READ | FileChannelImpl.WRITE); } public void close() throws IOException { Handle handle = getHandle(); this.handle = null; closed = true; handle.close(); } public String toString() { if (closed) return "<<closed>>"; Handle handle = this.handle; if (handle != null) { try { return String.valueOf(handle.getNativeFD()); } catch (IOException e) {} } return "<<invalid>>"; } final Handle getHandle() throws IOException { /* used by VM classes only */ Handle handle = this.handle; if (handle == null) throw new IOException("invalid file descriptor"); return handle; } final void setNativeFileFD(int fd, int mode) throws IOException { /* used by VM classes only */ checkUnset(); FileHandle handle; try { handle = new FileHandle(mode); } catch (OutOfMemoryError e) { try { VMChannel.close(fd); } catch (IOException ex) {} throw e; } handle.setNativeFD(fd); this.handle = handle; } final FileHandle getFileHandle() throws IOException { /* used by VM classes only */ Handle handle = this.handle; if (!(handle instanceof FileHandle)) throw new IOException(handle != null ? "not a file" : "invalid file descriptor"); return (FileHandle) handle; } final void setNativeSocketFD(int fd, boolean stream) throws IOException { /* used by VM classes only */ checkUnset(); SocketHandle handle; try { handle = new SocketHandle(stream); } catch (OutOfMemoryError e) { if (fd != -1) { try { VMAccessorGnuJavaNet.socketCloseVMPlainSocketImpl(fd); } catch (IOException ex) {} } throw e; } handle.setNativeFD(fd); this.handle = handle; } final SocketHandle getSocketHandle() throws IOException { /* used by VM classes only */ Handle handle = this.handle; if (!(handle instanceof SocketHandle)) throw new IOException(handle != null ? "not a socket" : "invalid file descriptor"); return (SocketHandle) handle; } private void checkUnset() throws IOException { if (handle != null || closed) throw new IOException("file descriptor already initialized"); } protected void finalize() throws Throwable { Handle handle = this.handle; if (handle != null && handle.needsCloseOnFinalize()) close(); } } private static final byte[] EMPTY_BUF = {}; private static final int stdin_fd = getStdinFD0(); private static final int stdout_fd = getStdoutFD0(); private static final int stderr_fd = getStderrFD0(); private static final boolean lockingOpHasPos = lockingOpHasPos0() != 0; private static final boolean preventBlocking = VMAccessorJavaLang.preventIOBlockingVMRuntime(); private final State state = new State(); public VMChannel() {} VMChannel(int fileFd) throws IOException { state.setNativeFD(fileFd); } public State getState() { return state; } public static VMChannel getStdin() throws IOException { VMChannel ch = new VMChannel(); ch.state.setNativeFileFD(stdin_fd, FileChannelImpl.READ); return ch; } public static VMChannel getStdout() throws IOException { VMChannel ch = new VMChannel(); ch.state.setNativeFileFD(stdout_fd, FileChannelImpl.WRITE); return ch; } public static VMChannel getStderr() throws IOException { VMChannel ch = new VMChannel(); ch.state.setNativeFileFD(stderr_fd, FileChannelImpl.WRITE); return ch; } public void setBlocking(boolean blocking) throws IOException { state.getHandle().setNonBlocking(!blocking); } public int available() throws IOException { return state.getHandle().available(); } public int read(ByteBuffer dst) throws IOException { int len = dst.remaining(); byte[] buffer; int off; boolean hasArray = false; if (dst.hasArray()) { buffer = dst.array(); off = dst.arrayOffset() + dst.position(); hasArray = true; } else { buffer = len > 0 ? new byte[len] : EMPTY_BUF; off = 0; } int res = state.getHandle().read(buffer, off, len); if (res > 0) { if (hasArray) dst.position(dst.position() + res); else dst.put(buffer, 0, res); } return res; } public long readScattering(ByteBuffer[] dsts, int offset, int length) throws IOException { if ((offset | length) < 0 || dsts.length - offset < length) throw new IndexOutOfBoundsException(); long result = 0L; while (length-- > 0) { ByteBuffer dst = dsts[offset++]; int res = read(dst); if (result == 0L || res >= 0) result += res; if (res <= 0 && (res != 0 || dst.remaining() > 0)) break; } return result; } public int read() throws IOException { byte[] buffer = new byte[1]; int res; while ((res = state.getHandle().read(buffer, 0, 1)) == 0) { threadYield(); checkThreadInterrupted(); } return res > 0 ? buffer[0] & 0xff : -1; } public int write(ByteBuffer src) throws IOException { int len = src.remaining(); byte[] buffer; int off; if (src.hasArray()) { buffer = src.array(); off = src.arrayOffset() + src.position(); } else { buffer = len > 0 ? new byte[len] : EMPTY_BUF; src.get(buffer, 0, len); src.position(src.position() - len); off = 0; } int[] offArr = { off }; try { state.getHandle().write(buffer, offArr, len); } finally { if ((len = offArr[0] - off) > 0) src.position(src.position() + len); } return len; } public long writeGathering(ByteBuffer[] srcs, int offset, int length) throws IOException { if ((offset | length) < 0 || srcs.length - offset < length) throw new IndexOutOfBoundsException(); long result = 0L; while (length-- > 0) { ByteBuffer src = srcs[offset++]; int res = write(src); if (res <= 0 && src.remaining() > 0) break; result += res; } return result; } public void write(int b) throws IOException { byte[] buffer = { (byte) b }; int[] offArr = new int[1]; do { state.getHandle().write(buffer, offArr, 1); if (offArr[0] > 0) break; threadYield(); checkThreadInterrupted(); } while (true); } public SocketAddress receive(ByteBuffer dst) throws IOException { int len = dst.remaining(); byte[] buffer; int off; boolean hasArray = false; if (dst.hasArray()) { buffer = dst.array(); off = dst.arrayOffset() + dst.position(); hasArray = true; } else { buffer = len > 0 ? new byte[len] : EMPTY_BUF; off = 0; } int[] offArr = { off }; InetSocketAddress address; try { address = state.getSocketHandle().receive(buffer, offArr, len); } finally { if ((len = offArr[0] - off) > 0) { if (hasArray) dst.position(dst.position() + len); else dst.put(buffer, 0, len); } } return address; } public int send(ByteBuffer src, InetSocketAddress address) throws IOException { int len = src.remaining(); if (address == null) throw new NullPointerException(); byte[] buffer; int off; if (src.hasArray()) { buffer = src.array(); off = src.arrayOffset() + src.position(); } else { buffer = len > 0 ? new byte[len] : EMPTY_BUF; src.get(buffer, 0, len); src.position(src.position() - len); off = 0; } int[] offArr = { off }; try { state.getSocketHandle().send(buffer, offArr, len, address); } finally { if ((len = offArr[0] - off) > 0) src.position(src.position() + len); } return len; } public void initSocket(boolean stream) throws IOException { if (state.isValid() || state.isClosed()) throw new IOException("cannot reinitialize this channel"); state.setNativeSocketFD(VMAccessorGnuJavaNet.socketCreateVMPlainSocketImpl( stream), stream); } public boolean connect(InetSocketAddress address, int timeout) throws SocketException { try { return state.getSocketHandle().connect(address, timeout); } catch (SocketException e) { throw e; } catch (IOException e) { throw (SocketException) (new SocketException()).initCause(e); } } public void disconnect() throws IOException { state.getSocketHandle().disconnect(); } public InetSocketAddress getLocalAddress() throws IOException { return state.isValid() ? VMAccessorGnuJavaNet.socketGetLocalAddrPortVMPlainSocketImpl( state.getSocketHandle().getNativeFD()) : null; } public InetSocketAddress getPeerAddress() throws IOException { return state.isValid() ? state.getSocketHandle().getPeerSocketAddress() : null; } public VMChannel accept() throws IOException { return state.getSocketHandle().accept(); } public void openFile(String path, int mode) throws IOException { if (state.isValid() || state.isClosed()) throw new IOException("cannot reinitialize this channel"); int[] fdArr = new int[1]; checkIOResCode(fileOpen(path, mode, fdArr)); state.setNativeFileFD(fdArr[0], mode); } public long position() throws IOException { return state.getFileHandle().position(); } public void seek(long newPosition) throws IOException { state.getFileHandle().seek(newPosition); } public void truncate(long size) throws IOException { state.getFileHandle().truncate(size); } public long size() throws IOException { return state.getFileHandle().size(); } public boolean lock(long pos, long len, boolean shared, boolean wait) throws IOException { return wait && lockingOpHasPos ? fileLock(state.getFileHandle().getNativeFD(), pos, len, shared, true) : state.getFileHandle().lock(pos, len, shared, wait); } public void unlock(long pos, long len) throws IOException { state.getFileHandle().unlock(pos, len); } public MappedByteBuffer map(char mapMode, long pos, int len) throws IOException { /* not implemented */ state.getFileHandle(); throw new IOException("VMChannel.map() not implemented"); } public boolean flush(boolean metadata) throws IOException { state.getHandle().flush(metadata); return true; } public void close() throws IOException { state.close(); } static final void close(int fileFd) throws IOException { /* used by VM classes only */ if (fileFd != -1 && !isStdInOutErr(fileFd)) { int res; do { res = fileClose0(fileFd); } while (res < 0 && isIOErrorInterrupted0(res) != 0); checkIOResCode(res); } } static final boolean isStdInOutErr(int fileFd) { /* used by VM classes only */ return fileFd == stdin_fd || fileFd == stdout_fd || fileFd == stderr_fd; } static final int fileAvailable(int fd) throws IOException { /* used by VM classes only */ int res; do { res = fileAvailable0(fd); if (res >= 0) return res; } while (isIOErrorInterrupted0(res) != 0); long position; do { position = fileSeek0(0L, fd, 0); } while (position < 0L && isIOErrorInterrupted0((int) position) != 0); if (position >= 0L) { long size; do { size = fileSeek0(0L, fd, -1); } while (size < 0L && isIOErrorInterrupted0((int) size) != 0); if (position != size) fileSeek(fd, position); if (size < 0L) checkIOResCode((int) size); position = size - position; return position > 0L ? (position < (long) (-1 >>> 1) ? (int) position : -1 >>> 1) : 0; } do { res = fileSelect0(fd, 0); } while (res < 0 && isIOErrorInterrupted0(res) != 0); return res > 0 ? 1 : 0; } static final long filePosition(int fd) throws IOException { /* used by VM classes only */ long position; do { position = fileSeek0(0L, fd, 0); } while (position < 0L && isIOErrorInterrupted0((int) position) != 0); if (position < 0L) checkIOResCode((int) position); return position; } static final void fileSeek(int fd, long newPosition) throws IOException { /* used by VM classes only */ long position; do { position = fileSeek0(newPosition, fd, 1); } while (position < 0L && isIOErrorInterrupted0((int) position) != 0); if (position < 0L) checkIOResCode((int) position); if (position != newPosition) throw new IOException("seek() failed"); } static final void fileTruncate(int fd, long size) throws IOException { /* used by VM classes only */ long position = filePosition(fd); try { if (position != size) fileSeek(fd, size); checkIOResCode(fileWrite0(EMPTY_BUF, 0, 0, fd)); if (position >= size) position = size; } finally { if (position != size) fileSeek(fd, position); } } static final long fileSize(int fd) throws IOException { /* used by VM classes only */ long position = filePosition(fd); long size; do { size = fileSeek0(0L, fd, -1); } while (size < 0L && isIOErrorInterrupted0((int) size) != 0); if (position != size) fileSeek(fd, position); if (size < 0L) checkIOResCode((int) size); return size; } static final boolean fileLock(int fd, long pos, long len, boolean shared, boolean wait) throws IOException { /* used by VM classes only */ long position; if (lockingOpHasPos || (position = filePosition(fd)) == pos) return fileLockInner(pos, len, fd, shared, wait); boolean res; try { fileSeek(fd, pos); res = fileLockInner(pos, len, fd, shared, wait); } finally { fileSeek(fd, position); } return res; } static final void fileUnlock(int fd, long pos, long len) throws IOException { /* used by VM classes only */ long position; if (lockingOpHasPos || (position = filePosition(fd)) == pos) fileUnlockInner(pos, len, fd); else { try { fileSeek(fd, pos); fileUnlockInner(pos, len, fd); } finally { fileSeek(fd, position); } } } static final int fileRead(int fd, byte[] buffer, int off, int len, boolean isNonBlocking) throws IOException { /* used by VM classes only */ if ((off | len) < 0 || buffer.length - off < len) throw new ArrayIndexOutOfBoundsException(); int res = 0; if (len > 0 && (!isNonBlocking || fileSelect0(fd, 0) != 0)) { if (isNonBlocking) { res = fileRead0(buffer, off, len, fd); if (res < 0) { if (isIOErrorInterrupted0(res) == 0) checkIOResCode(res); res = 0; } else if (res == 0) res = -1; } else { checkThreadInterrupted(); do { if (!preventBlocking || fileSelect0(fd, 0) != 0) { res = fileRead0(buffer, off, len, fd); if (res >= 0 || isIOErrorInterrupted0(res) == 0) break; } threadYield(); checkThreadInterrupted(); } while (true); checkIOResCode(res); if (res == 0) res = -1; } if (res > len) throw new InternalError("read() fault"); } return res; } static final void fileWrite(int fd, byte[] buffer, int[] offArr, int len, boolean isNonBlocking) throws IOException { /* used by VM classes only */ int off = offArr[0]; if ((off | len) < 0 || buffer.length - off < len) throw new ArrayIndexOutOfBoundsException(); if (len > 0 && (!isNonBlocking || fileSelect0(fd, 1) != 0)) { int remain = len; if (!isNonBlocking) checkThreadInterrupted(); do { if (isNonBlocking || !preventBlocking || fileSelect0(fd, 1) != 0) { int res = fileWrite0(buffer, off, remain, fd); if (res > 0) { off += res; offArr[0] = off; if ((remain -= res) <= 0) break; } else { if (res == 0) throw new IOException("no space left on device"); if (isIOErrorInterrupted0(res) == 0) checkIOResCode(res); } if (isNonBlocking) break; } threadYield(); if (remain == len) checkThreadInterrupted(); } while (true); if (remain < 0) throw new InternalError("write() fault"); } } static final void fileFlush(int fd, boolean metadata) throws IOException { /* used by VM classes only */ do { int res = fileFlush0(fd, metadata ? 1 : 0); if (res >= 0) break; if (isIOErrorInterrupted0(res) == 0) { if (isStdInOutErr(fd)) break; throw new SyncFailedException(getIOErrorMsg0(res)); } threadYield(); } while (true); } final void setNativeFileFD(int fd, int mode) throws IOException { /* used by VM classes only */ state.setNativeFileFD(fd, mode); } static final VMChannel createUnlessExists(File file) throws IOException { /* used by VM classes only */ VMChannel ch = new VMChannel(); int mode = FileChannelImpl.WRITE | FileChannelImpl.EXCL; int[] fdArr = new int[1]; int res = fileOpen(file.getPath(), mode, fdArr); if (res < 0) { if (isIOErrorFileExists0(res) == 0) checkIOResCode(res); return null; } ch.setNativeFileFD(fdArr[0], mode); return ch; } static final void checkIOResCode(int res) throws IOException { /* used by VM classes only */ if (res < 0) throw new IOException(getIOErrorMsg0(res)); } static final boolean isIORetryNeededOnce(int res) { /* used by VM classes only */ if (res >= 0 || isIOErrorNoResources0(res) == 0) return false; VMAccessorJavaLang.gcOnNoResourcesVMRuntime(); Runtime.getRuntime().runFinalization(); return true; } static boolean isThreadInterrupted() { return Thread.currentThread().isInterrupted(); } private static void checkThreadInterrupted() throws IOException { if (Thread.interrupted()) throw new InterruptedIOException(); } private static void threadYield() { Thread.yield(); } private static int fileOpen(String path, int mode, int[] fdArr) { if (path == null) throw new NullPointerException(); int res; boolean retrying = false; do { res = fileOpen0(fdArr, path, mode); if (!retrying && isIORetryNeededOnce(res)) retrying = true; else if (res >= 0 || isIOErrorInterrupted0(res) == 0) break; } while (true); return res; } private static boolean fileLockInner(long pos, long len, int fd, boolean shared, boolean wait) throws IOException { boolean retrying = false; do { int res = fileLock0(pos, len, fd, shared ? 1 : 0, wait ? 1 : 0); if (!retrying && isIORetryNeededOnce(res)) retrying = true; else { if (res >= 0) break; if (isIOErrorInterrupted0(res) == 0) checkIOResCode(res); if (!wait) return false; threadYield(); } } while (true); return true; } private static void fileUnlockInner(long pos, long len, int fd) throws IOException { int res; while ((res = fileLock0(pos, len, fd, -1, 0)) < 0) { if (isIOErrorInterrupted0(res) == 0) checkIOResCode(res); threadYield(); } } private static native int getStdinFD0(); private static native int getStdoutFD0(); private static native int getStderrFD0(); private static native int isIOErrorFileExists0(int res); private static native int isIOErrorNoResources0(int res); private static native int isIOErrorInterrupted0(int res); private static native String getIOErrorMsg0(int res); private static native int fileOpen0(int[] fdArr, String path, int mode); private static native int fileRead0(byte[] buffer, int off, int len, int fd); /* blocking syscall */ private static native int fileWrite0(byte[] buffer, int off, int len, int fd); /* blocking syscall */ private static native int fileAvailable0(int fd); private static native int fileSelect0(int fd, int iswrite); private static native long fileSeek0(long ofs, int fd, int direction); private static native int lockingOpHasPos0(); private static native int fileLock0(long pos, long len, int fd, int sharedOrUnlock, int doWait); /* blocking syscall */ private static native int fileFlush0(int fd, int metadata); /* blocking syscall */ private static native int fileClose0(int fd); }