hPutStrLn and hFlush

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

hPutStrLn and hFlush

Gracjan Polak

Hi all,

A bit strange behaviour with hPutStrLn. Consider following program:

main = do
    handle <- openFile "output.txt" WriteMode
    hPutStrLn handle (unlines contLines2)
    -- hFlush houtput
    where
        contLines2 = flip map [1..2000] $
              \x -> show x ++ " been there done that"

Outputs file which ends with following lines:

1989 been there done that
1990 been there done that
1991 been there done that
1992 been there done that
199
(END)

So the output is truncated. When I uncomment hFlush, file is fully written.
Is this expected/documented behaviour?

Platform: WinXP, GHC version 6.4.1

--
Regards,
Gracjan


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: hPutStrLn and hFlush

Sebastian Sylvan
On 1/9/06, Gracjan Polak <[hidden email]> wrote:

>
> Hi all,
>
> A bit strange behaviour with hPutStrLn. Consider following program:
>
> main = do
>     handle <- openFile "output.txt" WriteMode
>     hPutStrLn handle (unlines contLines2)
>     -- hFlush houtput
>     where
>         contLines2 = flip map [1..2000] $
>               \x -> show x ++ " been there done that"
>
> Outputs file which ends with following lines:
>
> 1989 been there done that
> 1990 been there done that
> 1991 been there done that
> 1992 been there done that
> 199
> (END)
>
> So the output is truncated. When I uncomment hFlush, file is fully written.
> Is this expected/documented behaviour?
>
> Platform: WinXP, GHC version 6.4.1
>

Looks like the buffering is BlockBuffering for your output. Try
changing that using hSetBuffering stdout LineBuffering (or
NoBuffering).

I believe it gets flushed if you close the file as well...

/S


--
Sebastian Sylvan
+46(0)736-818655
UIN: 44640862
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: hPutStrLn and hFlush

Sebastian Sylvan
On 1/9/06, Sebastian Sylvan <[hidden email]> wrote:

> On 1/9/06, Gracjan Polak <[hidden email]> wrote:
> >
> > Hi all,
> >
> > A bit strange behaviour with hPutStrLn. Consider following program:
> >
> > main = do
> >     handle <- openFile "output.txt" WriteMode
> >     hPutStrLn handle (unlines contLines2)
> >     -- hFlush houtput
> >     where
> >         contLines2 = flip map [1..2000] $
> >               \x -> show x ++ " been there done that"
> >
> > Outputs file which ends with following lines:
> >
> > 1989 been there done that
> > 1990 been there done that
> > 1991 been there done that
> > 1992 been there done that
> > 199
> > (END)
> >
> > So the output is truncated. When I uncomment hFlush, file is fully written.
> > Is this expected/documented behaviour?
> >
> > Platform: WinXP, GHC version 6.4.1
> >
>
> Looks like the buffering is BlockBuffering for your output. Try
> changing that using hSetBuffering stdout LineBuffering (or
> NoBuffering).

Err, you'd want to change the buffering on  your handle, not stdout,
obviously. :-)

--
Sebastian Sylvan
+46(0)736-818655
UIN: 44640862
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: hPutStrLn and hFlush

Stepan Golosunov
In reply to this post by Gracjan Polak
On Mon, Jan 09, 2006 at 04:57:51PM +0100, Gracjan Polak wrote:

> Hi all,
>
> A bit strange behaviour with hPutStrLn. Consider following program:
>
> main = do
>     handle <- openFile "output.txt" WriteMode
>     hPutStrLn handle (unlines contLines2)
>     -- hFlush houtput
>     where
>         contLines2 = flip map [1..2000] $
>               \x -> show x ++ " been there done that"
>
> Outputs file which ends with following lines:
>
> 1989 been there done that
> 1990 been there done that
> 1991 been there done that
> 1992 been there done that
> 199
> (END)
>
> So the output is truncated. When I uncomment hFlush, file is fully written.
> Is this expected/documented behaviour?

This is the usual behavior when file is not closed. And example from
http://www.haskell.org/onlinereport/io.html suggests that using hClose
is necessary.
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: hPutStrLn and hFlush

Donn Cave-2
On Mon, 9 Jan 2006, Stepan Golosunov wrote:
> On Mon, Jan 09, 2006 at 04:57:51PM +0100, Gracjan Polak wrote:
...
>> So the output is truncated. When I uncomment hFlush, file is fully written.
>> Is this expected/documented behaviour?
>
> This is the usual behavior when file is not closed. And example from
> http://www.haskell.org/onlinereport/io.html suggests that using hClose
> is necessary.

I guess it may be the usual behavior for ghc, since it works the
same for me on MacOS X.

In other languages with similar buffered output, finalizers deal with
this automatically on exit, and explicit flush or close is needed only
in relatively rare circumstances.  C, for example ... in fact, I'm
surprised to see this behavior in any I/O library.  The point of difference
I expect, in more modern languages, is between immediate and deferred
finalization.

        Donn Cave, [hidden email]

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: hPutStrLn and hFlush

John Meacham
Yeah. this is a major bug in ghc IMHO. I believe it has been fixed, but
am unsure. Since we can't rely on finalizers to run in general, some
sort of 'atexit' routine is needed. (which would be a good addition to
the standard libraries anyway)
        John
--
John Meacham - ⑆repetae.net⑆john⑈
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: hPutStrLn and hFlush

Gracjan Polak

Thanks for the answers. I can go with hFlush or hClose, no problem here. Anyway this is a bit surprising that default stdout behaves different than file opened with default options.

--
Gracjan


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: hPutStrLn and hFlush

Simon Marlow
In reply to this post by John Meacham
John Meacham wrote:
> Yeah. this is a major bug in ghc IMHO. I believe it has been fixed, but
> am unsure.

It hasn't been fixed, this is the current behaviour and it's likely to
stay that way, I'm afraid.

We used to run finalizers on exit, but we stopped doing that for various
reasons.  Even when we did run finalizers on exit, we couldn't guarantee
to run all of them.

> Since we can't rely on finalizers to run in general, some
> sort of 'atexit' routine is needed. (which would be a good addition to
> the standard libraries anyway)

You can implement atexit quite straightforwardly, if that's what you want.

exits = unsafePerformIO (newIORef []) :: IORef [IO ()]
main = do_stuff `finally` (readIORef exits >>= sequence_ . reverse)
atexit io = modifyIORef exits (io:)

In reality you probably want to use weak pointers here.  Using this
version of atexit to close Handles is bad, because it holds on to the
Handle until the end of the program.  Better to use a Weak pointer and
allow the Handle to be GC'd, but then you still need finalizers.

Cheers,
        Simon

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Re: hPutStrLn and hFlush

John Meacham
On Tue, Jan 10, 2006 at 09:40:41AM +0000, Simon Marlow wrote:

> John Meacham wrote:
> >Yeah. this is a major bug in ghc IMHO. I believe it has been fixed, but
> >am unsure.
>
> It hasn't been fixed, this is the current behaviour and it's likely to
> stay that way, I'm afraid.
>
> We used to run finalizers on exit, but we stopped doing that for various
> reasons.  Even when we did run finalizers on exit, we couldn't guarantee
> to run all of them.

oh, the bug I was refering to was not not running finalizers on exit
(which makes sense) but rather not flushing file handles on exit. the
implication being that flushing the file handles should be done via some
other mechanism than the GC finalizer.

> >Since we can't rely on finalizers to run in general, some
> >sort of 'atexit' routine is needed. (which would be a good addition to
> >the standard libraries anyway)
>
> You can implement atexit quite straightforwardly, if that's what you want.
>
> exits = unsafePerformIO (newIORef []) :: IORef [IO ()]
> main = do_stuff `finally` (readIORef exits >>= sequence_ . reverse)
> atexit io = modifyIORef exits (io:)

The problem is that people would have to know to put that in main, so
the atexit functionality could not be used from libraries. I am thinking
something more akin to C's atexit(3) function provided by its standard
libraries.

a proposed interface would be

module System.Exit  -- append to the current System.Exit

data AtExitHandle

-- | add a routine to be called on program exit
addHandle :: IO () -> IO AtExitHandle
-- | remove a routine previously set to be run on program exit, this actios is idempotent.
removeHandle :: AtExitHandle -> IO ()
-- | run and remove a routine atomically, guarenteed to run routine at most once, even if called multiple times
runRemoveHandle :: AtExitHandle -> IO ()


so, hOpen will do an
addHandle (hClose h) stowing the AtExitHandle and hClose will do a removeHandle on the AtExitHandle

I will happily implement this, I have needed it on several occasions
when working on real-world programs especially since the (correct)
decision to not ensure finalizers are run. (like making sure the terminal mode
is reset, or that certain resources (lock files, SYSV semaphores) are released)

in addition, I would add a _exitWith to System.Exit as the obvious
parallel to _exit(2).

        John

--
John Meacham - ⑆repetae.net⑆john⑈
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe