* [Caml-list] Flush behavior of baseic I/O class type
@ 2004-10-16 15:52 Yamagata Yoriyuki
2004-10-16 16:26 ` David MENTRE
2004-10-16 22:30 ` skaller
0 siblings, 2 replies; 6+ messages in thread
From: Yamagata Yoriyuki @ 2004-10-16 15:52 UTC (permalink / raw)
To: gerd; +Cc: caml-list
Hi,
In http://www.ocaml-programming.de/rec/IO-Classes.html, flush method
is defined as "The implementation may choose that put does not write
directly to the underlying resource, but into a buffer. In this case,
the call of flush writes the contents of the buffer to the
resource. When there is no such buffer, the call does nothing."
However if flush cannot output the whole buffer, what should it do?
The underlying output channel could be blocked, or the channel is code
converter and flush is called in the middle of the multibyte
character.
I think three possibility.
1) Output as far as possible, and leave the rest.
2) raise an exception
3) undefined.
What is your opinion?
--
Yamagata Yoriyuki
-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Caml-list] Flush behavior of baseic I/O class type
2004-10-16 15:52 [Caml-list] Flush behavior of baseic I/O class type Yamagata Yoriyuki
@ 2004-10-16 16:26 ` David MENTRE
2004-10-16 17:51 ` Yamagata Yoriyuki
2004-10-16 22:30 ` skaller
1 sibling, 1 reply; 6+ messages in thread
From: David MENTRE @ 2004-10-16 16:26 UTC (permalink / raw)
To: Yamagata Yoriyuki; +Cc: gerd, caml-list
Hello,
Yamagata Yoriyuki <yoriyuki@mbg.ocn.ne.jp> writes:
> 1) Output as far as possible, and leave the rest.
> 2) raise an exception
> 3) undefined.
Or 4) call blocked until the whole buffer can be flushed.
My personnal choice: 4, 1, 2, 3
Yours,
d.
PS: I've never used IO-Classes.
--
pub 1024D/A3AD7A2A 2004-10-03 David MENTRE <dmentre@linux-france.org>
5996 CC46 4612 9CA4 3562 D7AC 6C67 9E96 A3AD 7A2A
-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Caml-list] Flush behavior of baseic I/O class type
2004-10-16 16:26 ` David MENTRE
@ 2004-10-16 17:51 ` Yamagata Yoriyuki
2004-10-16 19:40 ` Gerd Stolpmann
2004-10-16 20:16 ` John Prevost
0 siblings, 2 replies; 6+ messages in thread
From: Yamagata Yoriyuki @ 2004-10-16 17:51 UTC (permalink / raw)
To: dmentre; +Cc: gerd, caml-list
From: David MENTRE <dmentre@linux-france.org>
Subject: Re: [Caml-list] Flush behavior of baseic I/O class type
Date: Sat, 16 Oct 2004 18:26:24 +0200
> Yamagata Yoriyuki <yoriyuki@mbg.ocn.ne.jp> writes:
>
> > 1) Output as far as possible, and leave the rest.
> > 2) raise an exception
> > 3) undefined.
>
> Or 4) call blocked until the whole buffer can be flushed.
It may be ok for non-blocking I/O, but it will cause "busy-waiting" ,
so perhaps a user does not like it. Moreover, for example, if the
channel is actually a filter, and it needs more inputs to determine
the next output, then it will stuck forever. (See the case of the
multibyte charcter code converter in the previous mail)
The easiest way (from the implementer's point of the view) would be
1), or 1') do the best effort to output, but nothing is guaranteed.
However I'm afraid that it will cause a subtle I/O bug.
--
Yamagata Yoriyuki
-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Caml-list] Flush behavior of baseic I/O class type
2004-10-16 17:51 ` Yamagata Yoriyuki
@ 2004-10-16 19:40 ` Gerd Stolpmann
2004-10-16 20:16 ` John Prevost
1 sibling, 0 replies; 6+ messages in thread
From: Gerd Stolpmann @ 2004-10-16 19:40 UTC (permalink / raw)
To: Yamagata Yoriyuki; +Cc: dmentre, gerd, caml-list
On Sam, 2004-10-16 at 19:51, Yamagata Yoriyuki wrote:
> From: David MENTRE <dmentre@linux-france.org>
> Subject: Re: [Caml-list] Flush behavior of baseic I/O class type
> Date: Sat, 16 Oct 2004 18:26:24 +0200
>
> > Yamagata Yoriyuki <yoriyuki@mbg.ocn.ne.jp> writes:
> >
> > > 1) Output as far as possible, and leave the rest.
> > > 2) raise an exception
> > > 3) undefined.
> >
> > Or 4) call blocked until the whole buffer can be flushed.
>
> It may be ok for non-blocking I/O, but it will cause "busy-waiting" ,
> so perhaps a user does not like it. Moreover, for example, if the
> channel is actually a filter, and it needs more inputs to determine
> the next output, then it will stuck forever. (See the case of the
> multibyte charcter code converter in the previous mail)
>
> The easiest way (from the implementer's point of the view) would be
> 1), or 1') do the best effort to output, but nothing is guaranteed.
> However I'm afraid that it will cause a subtle I/O bug.
Which one?
We need "flush" to ensure data is actually communicated to the other
endpoint of the channel, i.e. it is a means of synchronisation. When the
data are sent in a way this synchronisation cannot be done, this feature
is used in the wrong way, and I think raising an exception would be
justified.
Well, this is why we _need_ "flush" sometimes. There may be other
situations where softer requirements suffice, e.g. when "flush" is
called for debugging purposes such that as much as data as possible are
printed.
So I think there is no general rule, it depends on the purpose "flush"
is used for.
Gerd
--
------------------------------------------------------------
Gerd Stolpmann * Viktoriastr. 45 * 64293 Darmstadt * Germany
gerd@gerd-stolpmann.de http://www.gerd-stolpmann.de
------------------------------------------------------------
-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Caml-list] Flush behavior of baseic I/O class type
2004-10-16 17:51 ` Yamagata Yoriyuki
2004-10-16 19:40 ` Gerd Stolpmann
@ 2004-10-16 20:16 ` John Prevost
1 sibling, 0 replies; 6+ messages in thread
From: John Prevost @ 2004-10-16 20:16 UTC (permalink / raw)
To: Yamagata Yoriyuki; +Cc: caml-list
> It may be ok for non-blocking I/O, but it will cause "busy-waiting" ,
> so perhaps a user does not like it. Moreover, for example, if the
> channel is actually a filter, and it needs more inputs to determine
> the next output, then it will stuck forever. (See the case of the
> multibyte charcter code converter in the previous mail)
>
> The easiest way (from the implementer's point of the view) would be
> 1), or 1') do the best effort to output, but nothing is guaranteed.
> However I'm afraid that it will cause a subtle I/O bug.
If there is an explicit "flush" call, then the only reasonable thing
to do is to block until everything that may be written has been
written. In fact, the flush call on a filter should write everything,
and then tell the next level down to also flush.
For the MBCS implementation that you describe, you're right that
things are slighlty more complicated. In that case, the MBCS
implementation could choose to *either* "break" the incomplete
multi-byte character somehow (in a similar way to how it would have to
somehow deal with an incomplete multi-byte character when the file is
closed), or it might choose to flush everything up to that incomplete
multi-byte character, but keep the incomplete character in the buffer.
My choice would probably be to "break" it. Either way, the
implementation should describe what it does.
Finally, you mention difficulties with blocking vs. non-blocking I/O
here. You are correct that there is a problem with flush in this
case--and the problem (to me) seems to be in the API design for these
I/O classes. If you look at the design for Java I/O, you'll notice
that the java.io output classes contain flush methods but do not
support non-blocking I/O, and the java.nio classes support
non-blocking I/O but do not support flush methods. In C, the fflush
call "may also fail and set errno for any of the errors specified for
the routine write(2)." And write may return EAGAIN in order to
indicate that the write would block. And finally, it's worth noting
that the "write" family of calls make a lot more sense in a
non-blocking situation than the "fwrite" family of calls.
So I would suggest that the solution for non-block I/O here is that
the API should be changed. One choice is that either flush must be
able to return a result or it must be able to raise an exception that
indicates that not all of the output has yet been written (and it's
important that callers don't see the "broken MBCS character" above as
something they can re-try).
The other choice is that there should be a slightly different set of
operations on blocking and non-blocking streams. In that case:
Non-blocking output operations should always be attempted immediately,
and return a result indicating that there is a problem if they cannot
write everything. Non-blocking I/O should therefore not have a flush
operation. (If I am writing an application that uses non-blocking I/O,
this is the API I want: I am doing my own buffering, and need to know
exactly what has been written and what still needs to be written.)
Blocking output should never return until every character has either
been written completely, or has been placed in an intermediate buffer.
And the flush operation should block until all output has been
written (and the MBCS implementor must make the choice I described
above.) (If I am writing an application that uses blocking I/O, this
is again the API I want: I do not want to worry about buffering, and
either don't care about blocking or am handling it with multiple
threads. When I want to make sure that everything has been written, I
am happy to call flush.)
Finally, one might argue that if an *output* channel of multi-byte
characters has received a partial character, then a type error has
occurred. I understand, however, that there may be issues of
expediency that prevent you from making each character atomic.
John.
-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Caml-list] Flush behavior of baseic I/O class type
2004-10-16 15:52 [Caml-list] Flush behavior of baseic I/O class type Yamagata Yoriyuki
2004-10-16 16:26 ` David MENTRE
@ 2004-10-16 22:30 ` skaller
1 sibling, 0 replies; 6+ messages in thread
From: skaller @ 2004-10-16 22:30 UTC (permalink / raw)
To: Yamagata Yoriyuki; +Cc: gerd, caml-list
On Sun, 2004-10-17 at 01:52, Yamagata Yoriyuki wrote:
> I think three possibility.
> 1) Output as far as possible, and leave the rest.
> 2) raise an exception
> 3) undefined.
>
> What is your opinion?
Hmmm, well having read all the other replies so far,
perhaps I can contribute to the confusion with
a slighly different approach.
Your specification says '... the call of flush writes .. '
but that's an imperative description.
Instead, you could use a declarative description,
that is, specify the pre- and post- conditions.
For example:
pre-condition: the buffer contains whole characters
post-condition: the buffer is empty and its data is
scheduled for transmission
With this specification:
(1) if you find yourself in the middle of a multi-byte
character, the post condition is not guarranteed
because the pre-condition is not met. The behaviour
may vary depending on the kind of device, communication
path, time of day, and version of the program.
(2) The words 'scheduled for transmission' imply
flush can return before actual transmission.
You have to say that, because you cannot possibly
ensure the transmission on a high level operating
system. On Linux for example there is no way
to ensure disk writes end up on the media.
Just try writing to a floppy. On RH9 the only
way to physically write the floppy is to
unmount it.
It's quite possible that flushing a buffer works
by unlinking the memory block from the IO object,
and adding it to a queue 'to be written', and then
sometime later another thread writes it.
It's *also* possible you have a block device that
cannot support partial writing: you have to write
256 bytes, period, end of story. In this case,
flush will not be able to write everything, period,
end of story .. it isn't acceptable to write a padded
block out except at the end of the file. This may
be the case for a tape drive, for example.
In this case the write is still scheduled, meaning
the level of abstraction the current class deals
with has lost control of the situation and delegated
it to another layer .. but no assurance that the
physical transmission will occur is made, unless
subsequent operations on those lower levels
are done correctly. However, the class managing
the buffer has still carried out its job by delegating
to a lower level.
As an example -- you have an object designed to
physically write, and a program that flushes
at the end of each line. But the problem is you
are getting a huge bill from your ISP, by sending
twice the number of TCP/IP packets you would need to,
because most are only half full.
So you just add a buffering class into the chain,
which captures physical write from its owner
and buffers them. The upchain class is still satisfying
its post-condition. The downchain class doesn't write,
even when flush is called. It's *designed* that way.
As far as it is concerned, once stuff is given
to it that stuff is *already* scheduled for transmission
by definition, and so flush on it does nothing -- the post
condition is already satisfied.[Caveat: its buffer
must be 'empty' after flush. But what that means is
also an abstraction.. it probably doesn't have floating
buffers, but uses a single fixed one .. in which case
the 'floating buffer it would have had' is deemed
flushed at all times anyhow .. :]
(3) When you have blocking IO, nothing changes.
Flush should block, if it is necessary to satisfy
the post-condition.
The bottom line is that 'scheduled for transmission'
is itself an abstract phrase. What it means depends
on the class. Each class should define this phrase,
so the programmer can choose an appropriate class
for their needs.
Finally, I'd like to give a 'real world' and critical
example. C++ has three kinds of device:
(1) ostream
(2) FILE*
(3) Unix file handle
Typically, ostreams and FILE* both write via Unix file handle.
So what if you use the ostream 'cout' and the FILE* 'stdout'
and the Unix file handle '1' all in the same program??
Well, the ISO Standard in *this* case requires that
interleaved calls to cout and stdout (but not 1) work
'properly' (So they're required to share the same buffer).
[AFAIC remember :]
This is not so in general for other objects such
as a disk file or communication port. It's not even
required for streams on the same disk file --
they can use different buffers "just don't do that" :)
--
John Skaller, mailto:skaller@users.sf.net
voice: 061-2-9660-0850,
snail: PO BOX 401 Glebe NSW 2037 Australia
Checkout the Felix programming language http://felix.sf.net
-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2004-10-16 22:30 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-10-16 15:52 [Caml-list] Flush behavior of baseic I/O class type Yamagata Yoriyuki
2004-10-16 16:26 ` David MENTRE
2004-10-16 17:51 ` Yamagata Yoriyuki
2004-10-16 19:40 ` Gerd Stolpmann
2004-10-16 20:16 ` John Prevost
2004-10-16 22:30 ` skaller
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox