[Rxtx] flush twice, it is a long way to the kitchen
Joachim Buechse
joachim at buechse.de
Wed Sep 27 09:33:00 MDT 2006
man tcdrain
On 27.09.2006, at 17:10, Gregg Wonderly wrote:
> Dr. Douglas Lyon wrote:
>> 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!
>
> In the Unix I/O implementation, there is no flush call. Only write
> (2) and
> close(2) are documented to work for any particular fd returned from
> open(2).
> So, historically, close(2) has always had to include a wait for
> buffers to
> empty. In the early days of various Unix implementations, when
> every terminal
> was connected via a serial port, new serial hardware had new bugs.
> Close was
> always a problem. When we used modems to do UUCP, kermit etc, we
> always had to
> make sure and use appropriate ioctl(2) settings to manage the
> recognition of
> flow control at particular moments so as to avoid certain bugs and
> situations
> arrising from broken hardware and software.
>
>> 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()
> ...
>> There is no flush in the example! Technically, according to the spec,
>> this should write out NOTHING! But it DOES WORK!! Why?
>
> As noted above, this, historically has had to work because there is
> not always
> an equivalent flush() at the OS level.
>
>> 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.
>
> The buffering mechanism available in Java are a design paradigm
> meant to allow
> functionality similar to what stdio(3) provides to the Unix
> programmer. The
> issue is that various I/O streams are bi-directional, and it is
> necessary then
> to flush the output before reading more input, in order for these
> conversational
> exchanges to work. In raw Unix/C I/O with read(2) and write(2),
> there is an
> implicit flush, because there is no other mechanism available. For
> certain
> types of devices, there are ioctl() operations to do line mode
> buffering. For
> some types of I/O, such as to a Unix PIPE, you are dealing with a
> one-way based
> I/O subsystem that may perform buffering in particular
> circumstances. This is
> one of the reasons why Berkeley Unix folks created Unix-Domain
> Sockets. They
> allow conversational I/O to occur between processes without
> interfering buffering.
>
>> 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.
>
> Don't question your assumption. close() must include flush(), in
> Java to be
> correct. There is no ifs, ands, or buts about it.
>
>> 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 {
>> }
>
> This is a bad example, because the write() operation extends the array
> automatically, and makes the implementation meet the requirements
> all the APIs
> represented in the class. If write did not extend the array, the
> toByteArray()
> and close() would have to do that eventually. The implementation
> is less
> complex because it does the work early rather than defering it to
> later and thus
> requiring a check to see if the flush activity had been done.
>
>> Now check the FilterOutputStream:
>> * The <code>close</code> method of <code>FilterOutputStream</code>
>
>> 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.
>
> FilterOutputStream is just a delegating OutputStream that allows
> the write() or
> other methods to be overridden so that you can replace certain
> logic to create
> filtered results. So, it has to call flush, close and everything
> else to meet
> the contract of the I/O apis.
>
>> We may need a different exception for flush than for the internal
>> close, to facilitate debugging. Thus
>> public void close() throws IOException, PortInUseException
>
> The correct way to do this is to subclass an IOException to create
> PortInUseException. Some applications might deal with it
> explicitly if they
> allow multiple ports to be used, such as application using a bank
> of modems that
> just needs one that's not in use. Others, might just let this
> exception go up
> to a higher level to tell other code, or the user of the
> application that the
> selected port is not available. At the application level, this
> exception can be
> used to create small delays and retries while waiting for close to
> settle (if
> close is done asynchronously).
>
> Gregg Wonderly
> _______________________________________________
> Rxtx mailing list
> Rxtx at qbang.org
> http://mailman.qbang.org/mailman/listinfo/rxtx
More information about the Rxtx
mailing list