Talk:IPC via named pipe

From Rosetta Code
Latest comment: 12 years ago by Ledrug in topic Tricky to open "out"

Tricky to open "out"

This is tricky! The “in” reader side is normal asynchronous IO (the pipe becomes readable when there's data available) but the “out” writer side is very awkward because you can't open the writer side of a FIFO if there is no reader there. You've either got to use a blocking open() — which might or might not work with a threaded solution — or deal with the failure to open() it in non-blocking mode by polling regularly. Tricky stuff! –Donal Fellows 09:38, 30 September 2011 (UTC)Reply[reply]

Actually I don't think O_WRONLY|O_NONBLOCK on a fifo will ever succeed on a POSIX system.(unless there is already a reader) On Linux, you can O_RDWR open a fifo, and it will not block (because the program itself is the reader then), but then you can't select it for write readiness because it always returns immediately with success. Luckily here one thread blocking on open will not hold up the entire process, so it's relatively easy to deal with. --Ledrug 11:44, 30 September 2011 (UTC)Reply[reply]
You only want to have one end of each named pipe open in the process; using O_RDWR is opening both ends, and that's semantically wrong anyway (irrespective of whether or not it “works” with select()). It's irritating that O_NONBLOCK doesn't work for the pipe writer — POSIX specifies that behavior for reasons that are unclear to me, which scuppers the whole plan of using select() to wait for a reader, and the rationale doesn't go into enough depth — but at least it means that we can handle it with polling to give the right overall effect. (Sockets are nicer.) –Donal Fellows 12:23, 3 October 2011 (UTC)Reply[reply]
O_RDWR is semantically wrong, but POSIX specifically left it undefined instead of an error, which might be an intentional shortcut left to individual OS implementations. O_NONBLOCK|O_WRONLY behavior, as I vaguely understand it, has something to do with the pipe buffer management, though I'm very unsure about it. --Ledrug 00:43, 4 October 2011 (UTC)Reply[reply]

OpenBSD blocks the entire process

<lang ruby>$ irb -rthread irb(main):001:0> q = Queue.new; Thread.new {q << open("out", "w")} => #<Thread:0x0000020da6a630 run> irb(main):002:0> ^C irb(main):002:0> q.empty? => true</lang>

With OpenBSD, I observed that open("out", O_WRONLY) does block the entire process. This is a bug in the thread library, because an IO system call must block only the current thread; it is wrong to also block other threads. This irb session comes from Ruby MRI 1.9.4dev above OpenBSD. My first line tries to open "out" in another thread. This blocks the other thread, but because of this bug, also blocks my entire irb process! I must hit Control-C to cancel the open.

OpenBSD is also among the last systems to implement threads in userspace. OpenBSD pthreads(3) is a "user-level library" that uses non-blocking IO with the kernel. We know that open("out", O_WRONLY|O_NONBLOCK) is not possible, so I guess that the library blocks the entire process. This bug should only happen with OpenBSD. Other OS (like Linux, FreeBSD, NetBSD) might have kernel threads.

Some interpreters, like Ruby MRI 1.8.x, have "green threads". These interpreters might also use non-blocking IO, so they might block the entire process when opening "out" with any OS. --Kernigh 04:21, 2 October 2011 (UTC)Reply[reply]

Eh so on OpenBSD opening a fifo for readonly also blocks whole process? If so, what's the behavoir of read() or select()? --Ledrug 23:23, 2 October 2011 (UTC)Reply[reply]
Yes, open("in", O_RDONLY) also blocks whole process. Other functions like read(), usleep(), poll() and select() seem to block only current thread. --Kernigh 01:05, 3 October 2011 (UTC)Reply[reply]
Good then. If read() would have also blocked entire process, reading on "in" pipe could have been a serious problem in case of a slow writer because of pipe buffer. As it stands, I guess it's not a problem. --Ledrug 01:19, 3 October 2011 (UTC)Reply[reply]