IPC via named pipe: Difference between revisions

From Rosetta Code
Content added Content deleted
m (omissions)
(Add Ruby {{in progress}}.)
Line 8: Line 8:
* Your program may assume it's the sole reader on "in" and the sole writer on "out".
* Your program may assume it's the sole reader on "in" and the sole writer on "out".
* Read/write operation on pipes are generally blocking. Make your program responsive to both pipes, so that it won't block trying to read the "in" pipe while leaving another process hanging on the other end of "out" pipe indefinitely -- or vice versa. You probably need to either poll the pipes or use multi-threading.
* Read/write operation on pipes are generally blocking. Make your program responsive to both pipes, so that it won't block trying to read the "in" pipe while leaving another process hanging on the other end of "out" pipe indefinitely -- or vice versa. You probably need to either poll the pipes or use multi-threading.

==={{header|Ruby}}===
{{in progress|lang=Ruby|day=30|month=September|year=2011}}

With [[OpenBSD]], we observe that open(2) a named pipe blocks ''all threads'' in a process. (This must be bug in thread library.) So, we fork(2) other process to call open(2), and apply UNIXSocket to send IO object.

<lang ruby>require 'socket'

# Ruby has no direct access to mkfifo(2). We use a shell script.
system 'sh', '-c', <<EOF or abort
test -p in || mkfifo in || exit
test -p out || mkfifo out || exit
EOF

# Forks a process to open _path_. Returns a _socket_ to receive the open
# IO object (by UNIXSocket#recv_io), and the _pid_ of the process.
def open_sesame(path, mode)
reader, writer = UNIXSocket.pair
pid = fork do
begin
reader.close
file = File.open(path, mode)
writer.send_io file
ensure
exit!
end
end
writer.close
return reader, pid
end

insock, inpid = open_sesame("in", "rb")
outsock, outpid = open_sesame("out", "w")
Process.detach(inpid)
Process.detach(outpid)
inpipe, outpipe = nil
count = 0
readers = [insock, outsock]
writers = []
loop do
selection = select(readers, writers)
selection[0].each do |reader|
case reader
when insock
inpipe = reader.recv_io
when outsock
outpipe = reader.recv_io
when inpipe
count += (inpipe.read_nonblock.size rescue 0)
end
end
selection[1].each do |writer|
case writer
when outpipe
outpipe.puts count
exit
end
end
end</lang>

<pre>$ ruby count.rb
count.rb:39:in `recv_io': file descriptor was not passed (msg_controllen=0 smaller than sizeof(struct cmsghdr)=12) (SocketError)
from count.rb:39:in `block (2 levels) in <main>'
from count.rb:36:in `each'
from count.rb:36:in `block in <main>'
from count.rb:34:in `loop'
from count.rb:34:in `<main>'</pre>


{{omit from|GUISS}}
{{omit from|GUISS}}

Revision as of 01:56, 30 September 2011

IPC via named pipe is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Named pipe, or FIFO, is a way of providing inter-process communications (IPC). To demonstrate how it works, create two pipes, say, "in" and "out" (choose suitable names for your system), and write a program that works the two pipes such that:

  1. Data written to the "in" FIFO will be discarded except the byte count, which will be added to a total tally kept by the program;
  2. Whenever another process reads the "out" FIFO, it should receive the total count so far.

Possible issues:

  • Chances are you don't already have "in" and "out" pipes lying around. Create them within your program or without, at your discretion.
  • Your program may assume it's the sole reader on "in" and the sole writer on "out".
  • Read/write operation on pipes are generally blocking. Make your program responsive to both pipes, so that it won't block trying to read the "in" pipe while leaving another process hanging on the other end of "out" pipe indefinitely -- or vice versa. You probably need to either poll the pipes or use multi-threading.

Ruby

This example is under development. It was marked thus on 30/September/2011. Please help complete the example.

With OpenBSD, we observe that open(2) a named pipe blocks all threads in a process. (This must be bug in thread library.) So, we fork(2) other process to call open(2), and apply UNIXSocket to send IO object.

<lang ruby>require 'socket'

  1. Ruby has no direct access to mkfifo(2). We use a shell script.

system 'sh', '-c', <<EOF or abort test -p in || mkfifo in || exit test -p out || mkfifo out || exit EOF

  1. Forks a process to open _path_. Returns a _socket_ to receive the open
  2. IO object (by UNIXSocket#recv_io), and the _pid_ of the process.

def open_sesame(path, mode)

 reader, writer = UNIXSocket.pair
 pid = fork do
   begin
     reader.close
     file = File.open(path, mode)
     writer.send_io file
   ensure
     exit!
   end
 end
 writer.close
 return reader, pid

end

insock, inpid = open_sesame("in", "rb") outsock, outpid = open_sesame("out", "w") Process.detach(inpid) Process.detach(outpid) inpipe, outpipe = nil count = 0 readers = [insock, outsock] writers = [] loop do

 selection = select(readers, writers)
 selection[0].each do |reader|
   case reader
   when insock
     inpipe = reader.recv_io
   when outsock
     outpipe = reader.recv_io
   when inpipe
     count += (inpipe.read_nonblock.size rescue 0)
   end
 end
 selection[1].each do |writer|
   case writer
   when outpipe
     outpipe.puts count
     exit
   end
 end

end</lang>

$ ruby count.rb                                                                
count.rb:39:in `recv_io': file descriptor was not passed (msg_controllen=0 smaller than sizeof(struct cmsghdr)=12) (SocketError)
        from count.rb:39:in `block (2 levels) in <main>'
        from count.rb:36:in `each'
        from count.rb:36:in `block in <main>'
        from count.rb:34:in `loop'
        from count.rb:34:in `<main>'