Package gnu.java.nio

Source Code of gnu.java.nio.VMChannel

/*
* @(#) $(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);
}
TOP

Related Classes of gnu.java.nio.VMChannel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.