Question

Ok, so I am working with FIFO's and I was trying to build a small library to use in future programs.

It should be able to create a named pipe, read it and write in it.

I was able to do all these functions, but it isn't reading correctly. The problem is the following:

If I say it should be reading buffers of size 10 characters, it will only print correctly if I write more than 10 characters, ex:

write = "0123456789" -> reads = "" write = "012345678910111213" -> reads = "","10111213"

I tried the code a bit more and place a small debug on the exception "with". This exception exists in case the read fails... what it does is: dismiss, wait, restart, and in the end return 0 (nothing)

Then I have an if that will only right if the number of characters is only bigger than 0, if not it will print "empty"

So, what happened was: write = "0123456789" -> reads = "empty" write = "012345678910111213" -> reads = "empty","10111213"

So on the first 10 characters he says the read failed, but he removes them from the FIFO. Why?

Sorry if it was a bit confusing. Here is the code:

Program to Read:

let fifo_name = "la_fila";;

(*define the length of the buffer*)
let buflen = 2;;

let main () =
Printf.printf "Hello! Any readers? ...\n";
flush stdout;
while true do
print_string ("I've read \"" ^ bufferRead fifo_name buflen  ^ "\" from the fifo!\n");
flush stdout
done;;

(* run it *)
bufferCreate fifo_name;;
let _ = main ();;

and here is the BufferLibrary:

(* Buffer Functions *)
let bufferCreate name = 
  try Unix.mkfifo name 0o664 with
    Unix.Unix_error(n,f,arg) -> Printf.printf "%s(%s) : %s\n" f arg 
      (Unix.error_message n);;

let bufferRead name size =
let frd = Unix.openfile name [Unix.O_RDONLY;Unix.O_NONBLOCK] 0o644 in
 let rec aux () =  
    let nothing = flush_all ()
    in
    let buffer = String.create size in
    let n = try (Unix.read frd buffer 0 size) with 
        Unix.Unix_error(n,f,arg) -> begin (); aux (); 0; end
    in
    if n > 0 then String.sub buffer 0 n else "empty"
 in
 aux ();; 
 (*(String.sub buffer 0 n)*)

let bufferWrite name str = 
  let length = String.length str in
  let fwr = Unix.openfile name [Unix.O_WRONLY] 0o644 in 
  Unix.write fwr str 0 length;;

Edit

open Buffers;;

let fifo_name = "la_fila";;


let main () = 
Printf.printf "CUCKOO! any consumer down there? ...\n";
flush stdout;
Printf.printf "cuckoo! Here comes a consumer! \n";

let rec reget () =
Printf.printf "-type something for it\n";
flush stdout;
let str = read_line() (*here it blocks*) in
bufferWrite fifo_name str;
reget () in
reget ();;

(* run it *)
bufferCreate fifo_name;;
main ();;

I would love some light, its killing me...

Thank you

Was it helpful?

Solution

I don't think you want non-blocking IO, at least not for your initial tests. You actually want your reader to block until somebody is ready to write. But then you also probably don't want to reopen the pipe for each read, as that will wait for a writer each time. If you do want to reopen the pipe for each read, then you should also close it. In my tests of your code, the program runs until it uses up all the available file descriptors.

Edit: If you ask for non-blocking I/O your test program is basically polling (burning up CPU cycles) waiting for input to show up. You'll see some arbitrary number of 0-length reads before you start seeing any data. That seems to be what you're reporting. If you open and close the pipe all the time you might lose data if there's a period where no reader or writer has the pipe open.

What you really want to do for an initial test (I'm pretty sure) is open the pipe once for normal (blocking) IO and leave it open forever in the reader (until the end of the test). That should make sure you see all the data. You can try variations after that works.

As a side comment, I think many people eventually decide that the semantics of named pipes are just too finicky. They end up using Unix domain stream sockets instead.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top