Brethren,

I have a mystery to present today.

I have a threaded Perl ICB client. (If you don't know what ICB is, don't worry about it, that's not important to the question.) It was written as a multithreaded application for several reasons, not the least of them being to learn how to use Perl threads. One of its six total threads creates a FIFO, then listens on it for external input piped into the client and passes anything it receives to the input thread, in order to allow external files or program output to be piped into the program as though typed or pasted in directly. The handler for that FIFO is the following function:

sub fifocmd { my ($output_window, $input_window, $status_line, $connection) = @_ +; my ($fifodata, $rin, $rout); if (mkfifo($icbmfifo, oct('0600'))) { icb_debug ($output_window, 1, "fifocmd() opening command FIFO +%s", $icbmfifo); # We have to use sysopen() here rather than 'open (FIFO, $icbm +fifo);' # because on many preinstalled Perls, open() does NOT use O_NO +NBLOCK. # This causes breakage, as in the open() call never returns un +til and # unless something writes to the other end of the pipe. sysopen (FIFO, $icbmfifo, O_RDONLY|O_NONBLOCK); icb_debug ($output_window, 1, "Command FIFO %s is open", $icbm +fifo); while ($input_thread_running > 0) { $rout = $rin = $fifodata = ''; vec($rin, fileno(FIFO), 1) = 1; select($rout = $rin, undef, undef, 0.01); if (vec($rout, fileno(FIFO), 1)) { chomp($fifodata = <FIFO>); icb_debug ($output_window, 1, "Read '%s' from FIFO\n", + $fifodata); next if ($fifodata eq '/x' || $fifodata eq '/exit' || +$fifodata eq '/quit'); handle_input($fifodata, $output_window, $input_window, $status_line, $connection) if (length($fifodata)); } threads->yield if ($input_thread_running > 0); } icb_debug ($output_window, 1, "Input thread stopped; fifocmd() + exiting"); close (FIFO); unlink ($icbmfifo); } else { icb_print ($output_window, 'status', "Could not open %s as FIF +O", $icbmfifo); icb_print ($output_window, 'status', "Remote control functiona +lity will not be available."); } }

The last time I used the external input FIFO functinality, which was quite some time ago, it worked perfectly. I had cause to use it again this morning, and found that it has begun malfunctioning. As soon as anything is written to the FIFO, the FIFO input is processed as it should be, but then CPU utilization goes to 100% and stays there. The debug asserts that I inserted into the code show that after the initial handling of the input, the function goes into a tight loop repeatedly reading nothing from the FIFO:

Group: *test* (mil) Mod: Testric Topic: (None) *Testric - 11:43:09 alaric@babcom.com <[DEBUG]> fifocmd() opening command FIFO /home/alaric/.icbm/SOCKETS/ +ICBM-cmdfi fo.22166 <[DEBUG]> Command FIFO /home/alaric/.icbm/SOCKETS/ICBM-cmdfifo.22166 + is open <[DEBUG]> Read '/.' from FIFO Group: *test* (mil) Mod: Testric Topic: (None) *Testric - 11:43:09 alaric@babcom.com <[DEBUG]> Read '' from FIFO <[DEBUG]> Read '' from FIFO <[DEBUG]> Read '' from FIFO <[DEBUG]> Read '' from FIFO <[DEBUG]> Read '' from FIFO

It appears that once the FIFO has been written to, the select() ALWAYS says there is unread data waiting on the FIFO, yet nothing can be actually read from it. During the tight loop, an eof(FIFO) call inserted at the beginning of the innermost loop always returns true. There is no data on the FIFO to read; but the select() call thinks there is. I see that 'perldoc perlfunc' says:

Note: on some Unixes, the select(2) system call may report a socket file descriptor as "ready for reading", when actually no data is available, thus a subsequent read blocks. It can be avoided using always the O_NONBLOCK flag on the socket. See select(2) and fcntl(2) for further details.

However, I am already using O_NONBLOCK. It also says:

WARNING: One should not attempt to mix buffered I/O (like "read" or <FH>) with "select", except as permitted by POSIX, and even then only on POSIX systems. You have to use "sysread" instead.

But I have tried replacing the line:

chomp($fifodata = <FIFO>);

with the following construct:

my $l; while (sysread(FIFO, $l, 255)) { $fifodata .= $l; }

I have also tried replacing:

select($rout = $rin, undef, undef, 0.01); if (vec($rout, fileno(FIFO), 1)) {

with:

if (select($rout = $rin, undef, undef, 0.01)) {

or even:

if (select($rout = $rin, undef, undef, undef)) {

The behavior remains unchanged, though. No matter what I do, the select() continues to ALWAYS immediately show the FIFO as having data pending after it has been written to once.

Can anyone enlighten me as to why this should be, and what I can do to fix it?


In reply to Malfunctioning select() call on a FIFO by Llew_Llaw_Gyffes

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.