Version française
Home     About     Download     Resources     Contact us    
Browse thread
Strange buffering interaction: stdout / file_descr
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Alexander Fuchs <fuchs@c...>
Subject: Strange buffering interaction: stdout / file_descr
Hi,

I am trying to use Unix.create_process to create a process and redirect
its input/output channels. Actually, as a first step I want to determine
if process creation succeeded. I couldn't find any straightforward way
to figure this out, so I am just making the program output its version,
and them I am trying to read from its output channel. If the output
channel is ready according to Unix.select, but returns 0 bytes with
Unix.read, I can conclude that process creation failed (e.g. the wrong
path was given). I hope I am just missing something obvious here and
someone can point me to a better solution.

Anyway, when doing this, I get some strange behavior. First the main
program outputs something on stdout, without flushing stdout. Then a
process is created, with redirecting it input/output channels to new
socket pairs, but process creation fails (intentionally). But now
reading from the process' stdout, which should be completely independent
from the main program's stdout, yields what was previously output on the
main program's stdout. If instead I flush stdout before calling
Unix.create_process, this doesn't happen, and nothing can be read from
the failed process' stdout, as expected.

Is this a bug in the interaction of channels / file_descr, or should
this be make sense? 

For illustration I attached a sample program, compile with ocamlc
unix.cma <file_name>. It first outputs "main" on its stdout, then tries
to create a process, fails, reads "main" from the process' stdout, and
prints it.

Tested with ocaml 3.11.0 native and byte code, on x86_64 GNU/Linux.


Thanks,
	Alex




let () =
  print_string "main";

  let (stdout_r, stdout_w) = Unix.socketpair Unix.PF_UNIX
Unix.SOCK_STREAM 0 in
  let (stdin_r, stdin_w) = Unix.socketpair Unix.PF_UNIX Unix.SOCK_STREAM
0 in

  let cmd = "none" in

  (* without flush reading from stdout_r yields "main" *)
  (* flush stdout; *)
  let pid = Unix.create_process cmd [| cmd; "-version" |] stdin_r
stdout_w stdout_w in

  Unix.close stdin_r;
  Unix.close stdout_w;

  begin

    let (outs, _, _) = Unix.select [stdout_r] [] [] (-1.0) in

    match outs with
    | [out] ->
        let buffer = String.make 100 ' ' in
        let size =  Unix.read out buffer 0 100 in

        if size > 0 then begin
          print_endline (buffer)
        end

        else begin
          print_endline "create_process failed"
        end

    | _ ->
        assert false;
  end;

  Unix.close stdout_r;
  Unix.close stdin_w;
  Unix.kill pid Sys.sigkill;
  let (_, _status) = Unix.waitpid [] pid in
  ()