[Rxtx] flush twice, it is a long way to the kitchen
Dr. Douglas Lyon
lyon at docjava.com
Wed Sep 27 06:22:38 MDT 2006
Hi All,
Joachim suggests that:
"This is the one point where I really disagree. Port.close() should
never be used in the meaning of OutputStream.flush(). Port.close() is
the only abort mechanism available. The native implementation should
be free to throw away unsent data on close, abort reads and release
the system resource as soon as possible."
This may be a good point.
http://java.sun.com/j2se/1.4.2/docs/api/java/io/OutputStream.html#close()
Says that:
Closes this output stream and releases any system
resources associated with this stream. The
general contract of close is that it closes the
output stream. A closed stream cannot perform
output operations and cannot be reopened.
This last bit, a closed stream cannot be reopened is really telling.
The roles of "flush" and "close" are often combined in an implementation,
implicitly. They are also often (but not always) left out of the specification!
I would say that is not an optimal treatment and that we can do better.
For example:
http://java.sun.com/j2se/1.4.2/docs/api/java/io/ObjectOutputStream.html#close()
Shows no flush close. But the code at the top of the document shows:
FileOutputStream fos = new FileOutputStream("t.tmp");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeInt(12345);
oos.writeObject("Today");
oos.writeObject(new Date());
oos.close();
There is no flush in the example! Technically, according to the spec,
this should write out NOTHING! But it DOES WORK!! Why?
But from the source code of the ObjectOutputStream.java, I see:
public void close() throws IOException {
flush();
clear();
bout.close();
}
So, the flush is not in the specification, but it is in the implementation.
As a Java programmer, I have gotten used to making the assumption
that flush and close are combined and that the flush is implicit in
the close.
I am now starting to question my assumption. Whatever we decide,
it should probably be explicit in the specification.
There is no consistency on close implementations in the IO package.
Check out the close on the ByteArrayOutputStream:
/**
* Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in
* this class can be called after the stream has been closed without
* generating an <tt>IOException</tt>.
* <p>
*
*/
public void close() throws IOException {
}
Now check the FilterOutputStream:
* The <code>close</code> method of <code>FilterOutputStream</code>
* calls its <code>flush</code> method, and then calls the
* <code>close</code> method of its underlying output stream.
*
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#flush()
* @see java.io.FilterOutputStream#out
*/
public void close() throws IOException {
try {
flush();
} catch (IOException ignored) {
}
out.close();
}
Perhaps something like the FilterOutputStream makes sense for us. But
should we be ignoring exceptions on close? Perhaps we can close by
trying to flush, then release the resource in a finally statement and
STILL throw an exception to the caller.
We may need a different exception for flush than for the internal
close, to facilitate debugging. Thus
public void close() throws IOException, PortInUseException
At present, we have:
public interface CommPortInterface {
/**
* @return the name of this port.
*/
String getName();
/**
* @return a string representation of this port.
*/
String toString();
/**
* Closes this communications port. Further methods on this object will
* throw IllegalStateException. All PortOwnershipListeners will be
* notified of this change of ownership.
*/
void close();
}
Now, RXTXPort shows:
public synchronized void close() {
Is this consistent with the present specification, and if not, what should
we do?
Thanks!
- Doug
>I always appreciate a discussion based on good arguments;-)
>
>I know that Linus T. has argued several times that non-blocking close
>does not work. However in those cases where it does not work on the
>kernel level it can not be made to work on the application level
>neither. In my experience it is impossible to explain to a user why
>an application "hangs" on close. However they do understand that it
>may hang on open.
>
>>> From my experience a usefull implementation for close is a timeout
>>> based synchronous close with a rather small timeout. If the close
>>> "works" (ie no kernel/driver problem preventing it's execution) wait
>>> until it has returned. If it blocks (ie more than 1..4 seconds)
>>> return from the call. The trend for the kernel implementation of
>>> close is clearly "abort" r/w operations. It used to be wait for the
>>> end of r/w operations.
>>
>> Well, serial data can flow slowly compared to what a program can
>> generate. So,
>> it should be possible for an application to open a port at 300baud,
>> send some
>> large amount of data and block on the close, waiting for the send
>> to complete.
>
>This is the one point where I really disagree. Port.close() should
>never be used in the meaning of OutputStream.flush(). Port.close() is
>the only abort mechanism available. The native implementation should
>be free to throw away unsend data on close, abort reads and release
>the system resource as soon as possible.
>
>>> From a user perspective, closing a resource means "I lost all
>>> interest in you". In the case where the (synchronous) close is
>>> immediate that is no problem. However in the case where it is not,
>>> this creates big problems. The application by itself has basicly no
>>> means of dealing with a blocking close. As the user has lost interest
>>> in the port he will not understand any kind of dialog regarding an
>>> already closed port, he might have even decided to close the
>>> application and see that it "hangs" on close.
>>
>> It is possible for a java application to do
>>
>> Thread th = new Thread() {
>> public void run() {
>> try {
>> port.close();
>> } catch( Exception ex ) {
>> log.log( Level.WARNING, ex.toString(), ex );
>> }
>> }
>> };
>> th.setDaemon( true );
>> th.run();
>>
>
>1st problem) This returns immediately (even in the case where close
>does not block and returns within a few seconds). Hence the
>application has no idea of the progress of the close, it has to join
>the close thread or even have a callback interface to get status
>updates. This is what I often do, but it is neither elegant nor simple.
>2nd problem) The application has to keep track of ports which are in
>the state of beeing closed if it wants to reuse/reopen the same ports
>(race conditions).
>3rd problem) From what I have seen the java "process" will not unwind/
>return if a java thread hangs in a kernel call (daemon or not). That
>problem most likely affects my prefered solution as well, but the
>above code "suggests" otherwise.
>
>> ...implementation detail about networking. Serial ports don't have
>> the same
>> negociated close. Close progresses, unimpeded, when the write
>> buffer is empty.
>
>In my experience the kernel level close may block if the USB driver
>is trapped in a weird situation (ie a client device not reacting). It
>may block even if no data remains to be send, I consider this a
>kernel/driver/device bug - but unfortunately changes to the kernel/
>driver/device are often impossible.
>
>> If remote flow control is asserted, there is no negociation for
>> relief. This
>> is why it seems interesting, to let the close happen
>> asynchronously. In single
>> threaded programming environments, it becomes very convenient to do
>> this, but I
>> don't think it's a correct behavior. When serial hardware/software
>> is broken,
>> and the flowcontrol never subsides, the application can hang forever.
>
>I have seen cases where unplugging a USB device at the "right moment"
>or a buggy device that stops responding leads to a close blocking for
>hours. This is nothing the application can influence. Arguing, that
>an application should be allowed to hang if the OS/driver/hardware
>has bugs works in theory but not in (my) practice. I have seen cases,
>where (only) quitting the Java VM will unwind a hanging kernel close.
>I can not explain this behaviour, but I can reproduce it with a buggy
>USB device.
>
>Best regards,
>Joachim
>
>_______________________________________________
>Rxtx mailing list
>Rxtx at qbang.org
>http://mailman.qbang.org/mailman/listinfo/rxtx
More information about the Rxtx
mailing list