2

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

João Bastos
  • 193
  • 1
  • 10

1 Answers1

3

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.

Jeffrey Scofield
  • 65,646
  • 2
  • 72
  • 108
  • I forgot to add the writing program. This is intended for two separate processes. I'm going to add it in an edit to my question. I don't want it to block, because I want future programs to keep working and only read from time to time... Sort of ADDED - try it now – João Bastos Dec 11 '12 at 01:23
  • I followed your advise and tried a non-blocking IO and I stop having this problem, it reads everything. But why would that happen if I ask it to be non-blocking? Also in the previous case, the only scenario where it would work well, was if I rebooted the computer and only at the first string written. Only this would be correctly read, the following would not. – João Bastos Dec 11 '12 at 01:36
  • My theory is that you're losing data because you open and close the pipe all the time. A named pipe isn't a repository for data--the data goes away if there's nobody reading or writing. – Jeffrey Scofield Dec 11 '12 at 01:52
  • I see. So what would you recommend to comunicate between different independent processes. I liked named pipes because there wasn't the need for a relation of dependence between processes ... What would be the best way? – João Bastos Dec 11 '12 at 01:53
  • Named pipes are fine for one direction of communication. If that's what you need, great. Unix domain sockets are bi-directional and much more flexible. If you have data that needs to persist (beyond the lifetime of the read/write file descriptors) you'll need to store it somewhere. It depends on your problem. – Jeffrey Scofield Dec 11 '12 at 02:07
  • Ok, I understood it! I will keep working on these, I believe FIFO's are what I need. Thank you – João Bastos Dec 11 '12 at 02:11