[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