aboutsummaryrefslogtreecommitdiff
path: root/libjava/java/io/PipedReader.java
diff options
context:
space:
mode:
authorTom Tromey <tromey@cygnus.com>2000-04-21 01:18:16 +0000
committerTom Tromey <tromey@gcc.gnu.org>2000-04-21 01:18:16 +0000
commitd3474943bf309f085d515d7b20cb80c1d50e14cd (patch)
treedec5c6d7c3d3c314853e857fd39856ceb50ec5db /libjava/java/io/PipedReader.java
parent21caf59006e2c7dd06bf9840a7fc3cea321282f7 (diff)
downloadgcc-d3474943bf309f085d515d7b20cb80c1d50e14cd.zip
gcc-d3474943bf309f085d515d7b20cb80c1d50e14cd.tar.gz
gcc-d3474943bf309f085d515d7b20cb80c1d50e14cd.tar.bz2
Fix for PR java.io/204:
* java/io/PipedInputStream.java, java/io/PipedReader.java, java/io/PipedOutputStream.java, java/io/PipedWriter.java: Imported from Classpath. From-SVN: r33300
Diffstat (limited to 'libjava/java/io/PipedReader.java')
-rw-r--r--libjava/java/io/PipedReader.java703
1 files changed, 506 insertions, 197 deletions
diff --git a/libjava/java/io/PipedReader.java b/libjava/java/io/PipedReader.java
index faac986..72e516a 100644
--- a/libjava/java/io/PipedReader.java
+++ b/libjava/java/io/PipedReader.java
@@ -1,210 +1,519 @@
-// PipedReader.java - Piped character stream.
+/* PipedReader.java -- Input stream that reads from an output stream
+ Copyright (C) 1998, 1999 Free Software Foundation, Inc.
-/* Copyright (C) 1998, 1999 Free Software Foundation
+This file is part of GNU Classpath.
- This file is part of libgcj.
+GNU Classpath 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.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+As a special exception, if you link this library with other files to
+produce an executable, this library does not by itself cause the
+resulting executable to be covered by the GNU General Public License.
+This exception does not however invalidate any other reasons why the
+executable file might be covered by the GNU General Public License. */
-This software is copyrighted work licensed under the terms of the
-Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
-details. */
package java.io;
/**
- * @author Tom Tromey <tromey@cygnus.com>
- * @date September 25, 1998
+ * This class is an input stream that reads its chars from an output stream
+ * to which it is connected.
+ * <p>
+ * Data is read and written to an internal buffer. It is highly recommended
+ * that the <code>PipedReader</code> and connected <code>PipedWriter</code>
+ * be part of different threads. If they are not, there is a possibility
+ * that the read and write operations could deadlock their thread.
+ *
+ * @version 0.0
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class PipedReader extends Reader
+{
+
+/*************************************************************************/
+
+/*
+ * Class Variables
*/
-/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
- * "The Java Language Specification", ISBN 0-201-63451-1
- * Status: Complete to 1.1.
+/**
+ * The size of the internal buffer used for input/output. Note that this
+ * can be overriden by setting the system property
+ * <code>gnu.java.io.PipedReader.pipe_size</code> to the desired size shown
+ * in chars. This is not a standard part of the class library. Note that
+ * since this variable is <code>final</code>, it cannot be changed to refect
+ * the size specified in the property.
+ * <p>
+ * The value for this variable is 2048.
+ */
+private static final int PIPE_SIZE = 2048;
+
+/**
+ * This is the real pipe size. It defaults to PIPE_SIZE, unless overridden
+ * by use of the system property <code>gnu.java.io.PipedReader.pipe_size</code>.
+ */
+private static int pipe_size;
+
+/**
+ * This variable indicates whether or not the <code>read()</code> method will attempt
+ * return a short count if this will possibly keep the stream from blocking.
+ * The default for this is <code>false</code> because that is what what the JDK seems
+ * to imply in its javadocs. We set this to <code>false</code> if the system
+ * property <code>gnu.java.io.try_not_to_block</code> is set.
+ */
+private static boolean try_not_to_block = false;
+
+static
+{
+ pipe_size = Integer.getInteger("gnu.java.io.PipedReader.pipe_size",
+ PIPE_SIZE).intValue();
+
+ String block_prop = System.getProperty("gnu.java.io.try_not_to_block");
+ if (block_prop != null)
+ try_not_to_block = true;
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
*/
-public class PipedReader extends Reader
+/**
+ * This is the internal circular buffer used for storing chars written
+ * to the pipe and from which chars are read by this stream
+ */
+private char[] buffer = new char[pipe_size];
+
+/**
+ * The index into buffer where the chars written char the connected
+ * <code>PipedWriter</code> will be written. If this variables is less
+ * than 0, then the buffer is empty. If this variable is equal to
+ * <code>out</code>, then the buffer is full
+ */
+private int in = -1;
+
+/**
+ * This index into the buffer where chars will be read from.
+ */
+private int out = 0;
+
+/**
+ * This variable is <code>true</code> if this object has ever been connected
+ * to a <code>PipedWriter</code>, and <code>false</code> otherwise. It is used
+ * to detect an attempt to connect an already connected stream or to
+ * otherwise use the stream before it is connected.
+ */
+private boolean ever_connected = false;
+
+/**
+ * This variable is set to <code>true</code> if the <code>close()</code> method is
+ * called. This value is checked prevents a caller from re-opening the
+ * stream.
+ */
+private boolean closed = false;
+
+/**
+ * This variable is the PipedWriter to which this stream is connected.
+ */
+PipedWriter src;
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * This constructor creates a new <code>PipedReader</code> that is not
+ * connected to a <code>PipedWriter</code>. It must be connected before
+ * chars can be read from this stream.
+ */
+public
+PipedReader()
+{
+ return;
+}
+
+/*************************************************************************/
+
+/**
+ * This constructor creates a new <code>PipedReader</code> and connects
+ * it to the passed in <code>PipedWriter</code>. The stream is then read
+ * for reading.
+ *
+ * @param src The <code>PipedWriter</code> to connect this stream to
+ *
+ * @exception IOException If an error occurs
+ */
+public
+PipedReader(PipedWriter src) throws IOException
+{
+ connect(src);
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
+ */
+
+/**
+ * This method connects this stream to the passed in <code>PipedWriter</code>.
+ * This stream is then ready for reading. If this stream is already
+ * connected or has been previously closed, then an exception is thrown
+ *
+ * @param src The <code>PipedWriter</code> to connect this stream to
+ *
+ * @exception IOException If an error occurs
+ */
+public void
+connect(PipedWriter src) throws IOException
+{
+ if (src == this.src)
+ return;
+
+ if (ever_connected)
+ throw new IOException("Already connected");
+
+ if (closed)
+ throw new IOException("Stream is closed and cannot be reopened");
+
+ synchronized (lock) {
+
+ src.connect(this);
+
+ ever_connected = true;
+
+ } // synchronized
+}
+
+/*************************************************************************/
+
+/**
+ * This methods closes the stream so that no more data can be read
+ * from it.
+ *
+ * @exception IOException If an error occurs
+ */
+public void
+close() throws IOException
+{
+ synchronized (lock) {
+
+ closed = true;
+ notifyAll();
+
+ } // synchronized
+}
+
+/*************************************************************************/
+
+/**
+ * This method determines whether or not this stream is ready to be read.
+ * If this metho returns <code>false</code> an attempt to read may (but is
+ * not guaranteed to) block.
+ *
+ * @return <code>true</code> if this stream is ready to be read, <code>false</code> otherwise
+ *
+ * @exception IOException If an error occurs
+ */
+public boolean
+ready() throws IOException
{
- public void close () throws IOException
- {
- closed = true;
- }
-
- public void connect (PipedWriter src) throws IOException
- {
- if (closed)
- throw new IOException ("already closed");
- if (writer != null)
- {
- if (writer == src)
- return;
- throw new IOException ("already connected");
- }
- try
- {
- writer = src;
- writer.connect(this);
- }
- catch (IOException e)
- {
- writer = null;
- throw e;
- }
- }
-
- public PipedReader ()
- {
- super ();
- writer = null;
- closed = false;
- in = -1;
- out = 0;
- pipeBuffer = new char[1024];
- }
-
- public PipedReader (PipedWriter src) throws IOException
- {
- super ();
- closed = false;
- in = -1;
- out = 0;
- pipeBuffer = new char[1024];
- connect (src);
- }
-
- public int read (char buf[], int offset, int count) throws IOException
- {
- if (closed)
- throw new IOException ("closed");
- if (count < 0)
- throw new ArrayIndexOutOfBoundsException ();
- int toCopy = count;
- synchronized (lock)
- {
- while (toCopy > 0)
- {
- // Wait for data in the pipe. If the writer is closed and
- // no data has been copied into the output buffer, return
- // the magic EOF number.
- while (in == -1)
- {
- if (writer.isClosed())
- {
- if (toCopy < count)
- return count - toCopy;
- return -1;
- }
-
- // Note that JCL doesn't say this is the right thing
- // to do. Still, it feels right, and we must deal
- // with an interrupt somehow.
- try
- {
- lock.wait();
- }
- catch (InterruptedException e)
- {
- InterruptedIOException io
- = new InterruptedIOException (e.getMessage());
- io.bytesTransferred = count - toCopy;
- throw io;
- }
- }
- // Now copy some data from pipe into user buffer.
- int len;
- if (in < out)
- len = pipeBuffer.length - out;
- else
- len = in - out;
- len = len > toCopy ? toCopy : len;
- System.arraycopy(pipeBuffer, out, buf, offset, len);
- out += len;
- if (out == pipeBuffer.length)
- out = 0;
- toCopy -= len;
- offset += len;
- // If we've read all the data, then reset so that we know
- // there is nothing left to be read.
- if (in == out)
- in = -1;
- // Tell anybody waiting for space in the buffer.
- lock.notifyAll();
- }
- }
- return count;
- }
-
- void receive (char buf[], int offset, int count) throws IOException
- {
- if (count < 0)
- throw new ArrayIndexOutOfBoundsException ();
- int original = count;
- synchronized (lock)
- {
- while (count > 0)
- {
- // Wait until there is some space in the buffer.
- while (in == out)
- {
- try
- {
- lock.wait();
- }
- catch (InterruptedException e)
- {
- // Turn interrupts into IO interrupts.
- InterruptedIOException io
- = new InterruptedIOException (e.getMessage());
- io.bytesTransferred = original - count;
- throw io;
- }
- }
-
- // Compute destination in the pipe.
- int base, len;
- if (in == -1)
- {
- base = 0;
- len = pipeBuffer.length;
- }
- else if (in < out)
- {
- base = in;
- len = out - in;
- }
- else
- {
- base = in;
- len = pipeBuffer.length - in;
- }
- int copyLen = len > count ? count : len;
- // Copy data and update local state.
- System.arraycopy(buf, offset, pipeBuffer, base, copyLen);
- in = base + copyLen;
- if (in == pipeBuffer.length)
- in = 0;
- count -= copyLen;
- offset += copyLen;
- // Tell anybody waiting for data.
- lock.notifyAll();
- }
- }
- }
-
-
- boolean isClosed ()
- {
- return closed;
- }
-
- // The associated writer.
- private PipedWriter writer;
- // True if this reader has been closed.
- boolean closed;
-
- // Index of next character to overwrite when receive() is called.
- // If -1, then that means the buffer is empty.
- private int in;
- // Index of next character to return from read().
- private int out;
-
- // The pipe buffer itself.
- private char[] pipeBuffer;
+ if (in == -1)
+ return(false);
+
+ if (out == (in - 1))
+ return(false);
+
+ if ((out == pipe_size) && (in == 0))
+ return(false);
+
+ return(true);
}
+
+/*************************************************************************/
+
+/**
+ * This method reads a single char from the pipe and returns it as an
+ * <code>int</code>.
+ * <p>
+ * This method will block if no chars are available to be read.
+ *
+ * @return An char read from the pipe, or -1 if the end of stream is
+ * reached.
+ *
+ * @exception IOException If an error occurs.
+ */
+public int
+read() throws IOException
+{
+ char[] buf = new char[1];
+
+ return(read(buf, 0, buf.length));
+}
+
+/*************************************************************************/
+
+/**
+ * This method reads chars from the stream into a caller supplied buffer.
+ * It starts storing chars at position <code>offset</code> into the buffer and
+ * reads a maximum of <cod>>len</code> chars. Note that this method can actually
+ * read fewer than <code>len</code> chars. The actual number of chars read is
+ * returned. A -1 is returned to indicated that no chars can be read
+ * because the end of the stream was reached. If the stream is already
+ * closed, a -1 will again be returned to indicate the end of the stream.
+ * <p>
+ * This method will block if no chars are available to be read.
+ *
+ * @param buf The buffer into which chars will be stored
+ * @param offset The index into the buffer at which to start writing.
+ * @param len The maximum number of chars to read.
+ */
+public int
+read(char[] buf, int offset, int len) throws IOException
+{
+ if (!ever_connected)
+ throw new IOException("Not connected");
+
+ synchronized (lock) {
+
+ int chars_read = 0;
+ for (;;)
+ {
+ // If there are chars, take them
+ if (in != -1)
+ {
+ int desired_chars = len - chars_read;
+
+ // We are in a "wrap" condition
+ if (out > in)
+ {
+ if (desired_chars > (pipe_size - out))
+ {
+ if (in == 0)
+ desired_chars = (pipe_size - out) - 1;
+ else
+ desired_chars = pipe_size - out;
+
+ System.arraycopy(buffer, out, buf, offset + chars_read,
+ desired_chars);
+
+ chars_read += desired_chars;
+ out += desired_chars;
+ desired_chars = len - chars_read;
+
+ if (out == pipe_size)
+ out = 0;
+
+ notifyAll();
+ }
+ else
+ {
+ if ((out + desired_chars) == in)
+ --desired_chars;
+
+ if (((out + desired_chars) == pipe_size) && (in == 0))
+ desired_chars = (pipe_size - out) - 1;
+
+ System.arraycopy(buffer, out, buf, offset + chars_read,
+ desired_chars);
+
+ chars_read += desired_chars;
+ out += desired_chars;
+ desired_chars = len - chars_read;
+
+ if (out == pipe_size)
+ out = 0;
+
+ notifyAll();
+ }
+ }
+
+ // We are in a "no wrap" or condition (can also be fall through
+ // from above
+ if (in > out)
+ {
+ if (desired_chars >= ((in - out) - 1))
+ desired_chars = (in - out) - 1;
+
+ System.arraycopy(buffer, out, buf, offset + chars_read,
+ desired_chars);
+
+ chars_read += desired_chars;
+ out += desired_chars;
+ desired_chars = len - chars_read;
+
+ if (out == pipe_size)
+ out = 0;
+
+ notifyAll();
+ }
+ }
+
+ // If we are done, return
+ if (chars_read == len)
+ return(chars_read);
+
+ // Return a short count if necessary
+ if (chars_read < len)
+ if (try_not_to_block)
+ return(chars_read);
+
+ // Handle the case where the end of stream was encountered.
+ if (closed)
+ {
+ // We never let in == out so there might be one last char
+ // available that we have not copied yet.
+ if (in != -1)
+ {
+ buf[offset + chars_read] = buffer[out];
+ in = -1;
+ ++out;
+ ++chars_read;
+ }
+
+ if (chars_read != 0)
+ return(chars_read);
+ else
+ return(-1);
+ }
+
+ // Wait for a char to be read
+ try
+ {
+ wait();
+ }
+ catch(InterruptedException e) { ; }
+ }
+
+ } // synchronized
+}
+
+/*************************************************************************/
+
+/**
+ * This method is used by the connected <code>PipedWriter</code> to
+ * write chars into the buffer. It uses this method instead of directly
+ * writing the chars in order to obtain ownership of the object's monitor
+ * for the purposes of calling <code>notify</code>.
+ *
+ * @param buf The array containing chars to write to this stream
+ * @param offset The offset into the array to start writing from
+ * @param len The number of chars to write.
+ *
+ * @exception IOException If an error occurs
+ */
+void
+write(char[] buf, int offset, int len) throws IOException
+{
+ if (len <= 0)
+ return;
+
+ synchronized (lock) {
+
+ int total_written = 0;
+ while (total_written < len)
+ {
+ // If we are not at the end of the buffer with out = 0
+ if (!((in == (buffer.length - 1)) && (out == 0)))
+ {
+ // This is the "no wrap" situation
+ if ((in - 1) >= out)
+ {
+ int chars_written = 0;
+ if ((buffer.length - in) > (len - total_written))
+ chars_written = (len - total_written);
+ else if (out == 0)
+ chars_written = (buffer.length - in) - 1;
+ else
+ chars_written = (buffer.length - in);
+
+ if (chars_written > 0)
+ System.arraycopy(buf, offset + total_written, buffer, in,
+ chars_written);
+ total_written += chars_written;
+ in += chars_written;
+
+ if (in == buffer.length)
+ in = 0;
+
+ notifyAll();
+ }
+ // This is the "wrap" situtation
+ if ((out > in) && (total_written != len))
+ {
+ int chars_written = 0;
+
+ // Do special processing if we are at the beginning
+ if (in == -1)
+ {
+ in = 0;
+
+ if (buffer.length > len)
+ chars_written = len;
+ else
+ chars_written = buffer.length - 1;
+ }
+ else if (((out - in) - 1) < (len - total_written))
+ {
+ chars_written = (out - in) - 1;
+ }
+ else
+ {
+ chars_written = len - total_written;
+ }
+
+ // If the buffer is full, wait for it to empty out
+ if ((out - 1) == in)
+ {
+ try
+ {
+ wait();
+ }
+ catch (InterruptedException e)
+ {
+ continue;
+ }
+ }
+
+ System.arraycopy(buf, offset + total_written, buffer, in,
+ chars_written);
+ total_written += chars_written;
+ in += chars_written;
+
+ if (in == buffer.length)
+ in = 0;
+
+ notifyAll();
+ }
+ }
+ // Wait for some reads to occur before we write anything.
+ else
+ {
+ try
+ {
+ wait();
+ }
+ catch (InterruptedException e) { ; }
+ }
+ }
+ } // synchronized
+}
+
+} // class PipedReader
+