public synchronized ByteList readnonblock(int number) throws IOException, BadDescriptorException, EOFException { assert number >= 0; if (number == 0) { return null; } if (descriptor.getChannel() instanceof SelectableChannel) { SelectableChannel selectableChannel = (SelectableChannel) descriptor.getChannel(); synchronized (selectableChannel.blockingLock()) { boolean oldBlocking = selectableChannel.isBlocking(); try { selectableChannel.configureBlocking(false); return readpartial(number); } finally { selectableChannel.configureBlocking(oldBlocking); } } } else if (descriptor.getChannel() instanceof FileChannel) { return fread(number); } else { return null; } }
private ByteList bufferedRead(int number) throws IOException, BadDescriptorException { checkReadable(); ensureRead(); int resultSize = 0; // 128K seems to be the minimum at which the stat+seek is faster than reallocation final int BULK_THRESHOLD = 128 * 1024; if (number >= BULK_THRESHOLD && descriptor.isSeekable() && descriptor.getChannel() instanceof FileChannel) { // // If it is a file channel, then we can pre-allocate the output buffer // to the total size of buffered + remaining bytes in file // FileChannel fileChannel = (FileChannel) descriptor.getChannel(); resultSize = (int) Math.min( fileChannel.size() - fileChannel.position() + bufferedInputBytesRemaining(), number); } else { // // Cannot discern the total read length - allocate at least enough for the buffered data // resultSize = Math.min(bufferedInputBytesRemaining(), number); } ByteList result = new ByteList(resultSize); bufferedRead(result, number); return result; }
/** * Flush the write buffer to the channel (if needed) * * @throws IOException */ private boolean flushWrite(final boolean block) throws IOException, BadDescriptorException { if (reading || !modes.isWritable() || buffer.position() == 0) return false; // Don't bother int len = buffer.position(); int nWritten = 0; buffer.flip(); // For Sockets, only write as much as will fit. if (descriptor.getChannel() instanceof SelectableChannel) { SelectableChannel selectableChannel = (SelectableChannel) descriptor.getChannel(); synchronized (selectableChannel.blockingLock()) { boolean oldBlocking = selectableChannel.isBlocking(); try { if (oldBlocking != block) { selectableChannel.configureBlocking(block); } nWritten = descriptor.write(buffer); } finally { if (oldBlocking != block) { selectableChannel.configureBlocking(oldBlocking); } } } } else { nWritten = descriptor.write(buffer); } if (nWritten != len) { buffer.compact(); return false; } buffer.clear(); return true; }
public synchronized int writenonblock(ByteList buf) throws IOException, BadDescriptorException { checkWritable(); ensureWrite(); // Ruby ignores empty syswrites if (buf == null || buf.length() == 0) return 0; if (buffer.position() != 0 && !flushWrite(false)) return 0; if (descriptor.getChannel() instanceof SelectableChannel) { SelectableChannel selectableChannel = (SelectableChannel) descriptor.getChannel(); synchronized (selectableChannel.blockingLock()) { boolean oldBlocking = selectableChannel.isBlocking(); try { if (oldBlocking) { selectableChannel.configureBlocking(false); } return descriptor.write(ByteBuffer.wrap(buf.getUnsafeBytes(), buf.begin(), buf.length())); } finally { if (oldBlocking) { selectableChannel.configureBlocking(oldBlocking); } } } } else { // can't set nonblocking, so go ahead with it...not much else we can do return descriptor.write(ByteBuffer.wrap(buf.getUnsafeBytes(), buf.begin(), buf.length())); } }
public int ready() throws IOException { if (descriptor.getChannel() instanceof SelectableChannel) { int ready_stat = 0; java.nio.channels.Selector sel = SelectorFactory.openWithRetryFrom( null, ((SelectableChannel) descriptor.getChannel()).provider()); SelectableChannel selchan = (SelectableChannel) descriptor.getChannel(); synchronized (selchan.blockingLock()) { boolean is_block = selchan.isBlocking(); try { selchan.configureBlocking(false); selchan.register(sel, java.nio.channels.SelectionKey.OP_READ); ready_stat = sel.selectNow(); sel.close(); } catch (Throwable ex) { } finally { if (sel != null) { try { sel.close(); } catch (Exception e) { } } selchan.configureBlocking(is_block); } } return ready_stat; } else { return newInputStream().available(); } }
public void setBlocking(boolean block) throws IOException { if (!(descriptor.getChannel() instanceof SelectableChannel)) { return; } synchronized (((SelectableChannel) descriptor.getChannel()).blockingLock()) { blocking = block; try { ((SelectableChannel) descriptor.getChannel()).configureBlocking(block); } catch (IllegalBlockingModeException e) { // ignore this; select() will set the correct mode when it is finished } } }
private void resetForWrite() throws IOException { if (descriptor.isSeekable()) { FileChannel fileChannel = (FileChannel) descriptor.getChannel(); if (buffer.hasRemaining()) { // we have read ahead, and need to back up fileChannel.position(fileChannel.position() - buffer.remaining()); } } // FIXME: Clearing read buffer here...is this appropriate? buffer.clear(); reading = false; }
/** * Invalidate buffer before a position change has occurred (e.g. seek), flushing writes if * required, and correcting file position if reading * * @throws IOException */ private void invalidateBuffer() throws IOException, BadDescriptorException { if (!reading) flushWrite(); int posOverrun = buffer.remaining(); // how far ahead we are when reading buffer.clear(); if (reading) { buffer.flip(); // if the read buffer is ahead, back up FileChannel fileChannel = (FileChannel) descriptor.getChannel(); if (posOverrun != 0) fileChannel.position(fileChannel.position() - posOverrun); } }
/** * Implementation of libc "lseek", which seeks on seekable streams, raises EPIPE if the fd is * assocated with a pipe, socket, or FIFO, and doesn't do anything for other cases (like stdio). * * @throws IOException * @throws InvalidValueException */ public synchronized void lseek(long offset, int type) throws IOException, InvalidValueException, PipeException, BadDescriptorException { if (descriptor.isSeekable()) { FileChannel fileChannel = (FileChannel) descriptor.getChannel(); ungotc = -1; int adj = 0; if (reading) { // for SEEK_CUR, need to adjust for buffered data adj = buffer.remaining(); buffer.clear(); buffer.flip(); } else { flushWrite(); } try { switch (type) { case SEEK_SET: fileChannel.position(offset); break; case SEEK_CUR: fileChannel.position(fileChannel.position() - adj + offset); break; case SEEK_END: fileChannel.position(fileChannel.size() + offset); break; } } catch (IllegalArgumentException e) { throw new InvalidValueException(); } catch (IOException ioe) { throw ioe; } } else if (descriptor.getChannel() instanceof SelectableChannel) { // TODO: It's perhaps just a coincidence that all the channels for // which we should raise are instanceof SelectableChannel, since // stdio is not...so this bothers me slightly. -CON throw new PipeException(); } else { } }
/** @throws IOException */ public synchronized long fgetpos() throws IOException, PipeException, InvalidValueException, BadDescriptorException { // Correct position for read / write buffering (we could invalidate, but expensive) if (descriptor.isSeekable()) { FileChannel fileChannel = (FileChannel) descriptor.getChannel(); long pos = fileChannel.position(); // Adjust for buffered data if (reading) { pos -= buffer.remaining(); return pos - (pos > 0 && ungotc != -1 ? 1 : 0); } else { return pos + buffer.position(); } } else if (descriptor.isNull()) { return 0; } else { throw new PipeException(); } }
public synchronized ByteList readpartial(int number) throws IOException, BadDescriptorException, EOFException { assert number >= 0; if (number == 0) { return null; } if (descriptor.getChannel() instanceof FileChannel) { return fread(number); } if (hasBufferedInputBytes()) { // already have some bytes buffered, just return those return bufferedRead(Math.min(bufferedInputBytesRemaining(), number)); } else { // otherwise, we try an unbuffered read to get whatever's available return read(number); } }
public synchronized void ftruncate(long newLength) throws IOException, BadDescriptorException, InvalidValueException { Channel ch = descriptor.getChannel(); if (!(ch instanceof FileChannel)) { throw new InvalidValueException(); } invalidateBuffer(); FileChannel fileChannel = (FileChannel) ch; long position = fileChannel.position(); if (newLength > fileChannel.size()) { // truncate can't lengthen files, so we save position, seek/write, and go back int difference = (int) (newLength - fileChannel.size()); fileChannel.position(fileChannel.size()); // FIXME: This worries me a bit, since it could allocate a lot with a large newLength fileChannel.write(ByteBuffer.allocate(difference)); } else { fileChannel.truncate(newLength); } fileChannel.position(position); }
/** * @deprecated readall do busy loop for the IO which has NONBLOCK bit. You should implement the * logic by yourself with fread(). */ @Deprecated public synchronized ByteList readall() throws IOException, BadDescriptorException { final long fileSize = descriptor.isSeekable() && descriptor.getChannel() instanceof FileChannel ? ((FileChannel) descriptor.getChannel()).size() : 0; // // Check file size - special files in /proc have zero size and need to be // handled by the generic read path. // if (fileSize > 0) { ensureRead(); FileChannel channel = (FileChannel) descriptor.getChannel(); final long left = fileSize - channel.position() + bufferedInputBytesRemaining(); if (left <= 0) { eof = true; return null; } if (left > Integer.MAX_VALUE) { if (getRuntime() != null) { throw getRuntime().newIOError("File too large"); } else { throw new IOException("File too large"); } } ByteList result = new ByteList((int) left); ByteBuffer buf = ByteBuffer.wrap(result.getUnsafeBytes(), result.begin(), (int) left); // // Copy any buffered data (including ungetc byte) // copyBufferedBytes(buf); // // Now read unbuffered directly from the file // while (buf.hasRemaining()) { final int MAX_READ_CHUNK = 1 * 1024 * 1024; // // When reading into a heap buffer, the jvm allocates a temporary // direct ByteBuffer of the requested size. To avoid allocating // a huge direct buffer when doing ludicrous reads (e.g. 1G or more) // we split the read up into chunks of no more than 1M // ByteBuffer tmp = buf.duplicate(); if (tmp.remaining() > MAX_READ_CHUNK) { tmp.limit(tmp.position() + MAX_READ_CHUNK); } int n = channel.read(tmp); if (n <= 0) { break; } buf.position(tmp.position()); } eof = true; result.length(buf.position()); return result; } else if (descriptor.isNull()) { return new ByteList(0); } else { checkReadable(); ByteList byteList = new ByteList(); ByteList read = fread(BUFSIZE); if (read == null) { eof = true; return byteList; } while (read != null) { byteList.append(read); read = fread(BUFSIZE); } return byteList; } }
private final int refillBuffer() throws IOException { buffer.clear(); int n = ((ReadableByteChannel) descriptor.getChannel()).read(buffer); buffer.flip(); return n; }
public synchronized int read(ByteBuffer dst) throws IOException, BadDescriptorException, EOFException { return read(dst, !(descriptor.getChannel() instanceof FileChannel)); }