> > Yes, it's a NOP (just to be sure). The difference is in child.hs:
> > 
> > callIO (\ps -> "Kommando fehlgeschlagen mit " ++ show ps 
> >         ++ ":\n" ++ kommando prog par)
> >            (executeFile' prog True par Nothing)
> > -- instead, to avoid bug:
> > --         (hClose stdin >> executeFile' prog True par Nothing)
> > 
> > If you use the commented out line instead of the one in effect
> > ("(executeFile' prog..."), you get the first behaviour, 
> which is, the
> > problem doesn't occur.
> 
> I'm still investigating this.  It appears that the child process *is*
> reading from stdin before doing the exec, but I'm not sure why.  But
> this at least partially explains why the parent process doesn't get to
> see all the data on stdin.

Ok, here's my explanation.  Let's take a look at the code for child
(parent is unimportant - you can pipe data into child using 'cat' and
still observe the disputed behaviour).  Here's the code, simplified
slightly:

  main = do
    qinh <- getContents
    let pfade = zeilen qinh
    mapM_ (\pfad -> run "/bin/true" [pfad]) pfade

  zeilen :: String -> [String]
  zeilen txt =
    let gruppen = groupBy (\a b -> (a == '\n') == (b == '\n')) txt
    in  filter (\str -> filter (/= '\n') str /= "") gruppen

  run prog par = callIO (executeFile' prog True par Nothing)

  callIO :: IO () -> IO ()
  callIO io = do
    maybepid <- forkProcess
    case maybepid of
       Nothing ->
           io >> exitWith ExitSuccess
       Just pid -> do
           (Just ps) <- getProcessStatus True True pid
           if ps == Exited ExitSuccess
               then return ()
               else failIO (show ps)

The issue here is whether the child process (i.e. the Nothing case in
callIO) can cause any reading from stdin by virtue of evaluating the
lazy stream returned by getContents.  If the child process does cause
any reading from stdin, then the parent process will lose data, because
any reading by the child won't be seen by the parent.

Looking at the code, it appears that the arguments passed to 'run',
namely [pfad], will be fully evaluated by this point because groupBy has
to examine the characters of the stream in order to split it up into
chunks, and furthermore the call to filter will compare the chunk
against the empty string.

But on further investigation, groupBy is much lazier than this:

  groupBy               :: (a -> a -> Bool) -> [a] -> [[a]]
  groupBy _  []         =  []
  groupBy eq (x:xs)     =  (x:ys) : groupBy eq zs
                           where (ys,zs) = span (eq x) xs

ie. it returns the chunk immediately with only the first character
evaluated.  Since the call to filter only needs to examine the chunk to
determine whether it is empty or not, the rest of the chunk, and hence
everything beyond the next character in the lazy stream, will be
unevaluated until the child process needs to construct its argument list
to pass to executeFile.  Hence the child process pokes on the lazy
stream, and when the parent process subsequently demands data from the
lazy stream, there is a buffer's worth missing.

Moral of this story: don't use lazy I/O.  I'll say that again in case
you missed it:

   ____              _ _                    
  |  _ \  ___  _ __ ( ) |_   _   _ ___  ___ 
  | | | |/ _ \| '_ \|/| __| | | | / __|/ _ \
  | |_| | (_) | | | | | |_  | |_| \__ \  __/
  |____/ \___/|_| |_|  \__|  \__,_|___/\___|
   _                   ___    _____  
  | | __ _ _____   _  |_ _|  / / _ \ 
  | |/ _` |_  / | | |  | |  / / | | |
  | | (_| |/ /| |_| |  | | / /| |_| |
  |_|\__,_/___|\__, | |___/_/  \___/ 
               |___/                 

Cheers,
        Simon
             
_______________________________________________
Glasgow-haskell-bugs mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs

Reply via email to