in reply to IO::Select woes

Hi again Monks,

I have duplicated the issue. I just simply wrapped the STDIN check in a function. When I run this very simple script through the pipe, can_read() doesn't detect anything on STDIN. When I run it through the debugger, it works fine. When I uncomment the print statement in checkPipe, it triggers something and works fine without the debugger! What am I possibly doing wrong here? I am losing my sanity! Could it possibly be the timeout as Bliako stated? I tried changing it, but it doesn't seem to change anything.

# # TEST RUN # # # perl test2.pl | perl test2.pl ## PRINTS NOTHING !!!
# perl test2.pl | perl -d test2.pl reading from pipe data .------------------------------. | Basket | +----+-----------------+-------+ | Id | Name | Price | +----+-----------------+-------+ | 1 | Dummy product 1 | 24.4 | | 2 | Dummy product 2 | 21.2 | | 3 | Dummy product 3 | 12.3 | +----+-----------------+-------+ | | Total | 57.9 | '----+-----------------+-------'
## test2.pl # #!/usr/bin/perl5.26.1 use strict; use Text::ASCIITable; use IO::Select; use strict; use warnings; $|=1; checkPipe(); sub checkPipe { #print "checking pipe\n"; #<==== UNCOMMENT IT WORKS!! my $s = IO::Select->new(); $s->add(\*STDIN); if ($s->can_read(.5)) { print STDOUT "reading from pipe data\n"; dumpTable(); } } sub dumpTable { my $t = Text::ASCIITable->new({ headingText => 'Basket' }); $t->setCols('Id','Name','Price'); $t->addRow(1,'Dummy product 1',24.4); $t->addRow(2,'Dummy product 2',21.2); $t->addRow(3,'Dummy product 3',12.3); $t->addRowLine(); $t->addRow('','Total',57.9); print STDOUT $t ."\n"; }

Replies are listed 'Best First'.
Re^2: IO::Select woes
by hv (Prior) on May 05, 2023 at 17:52 UTC

    I think there is a confusion here between what the first process is doing and what the second process is doing.

    I think your intention was that the first process prints the table, and the second process reads it; however both are running the same code, so in the normal course of events the first process sees nothing to read, so does not dump its table; since it outputs nothing, the second process also sees nothing to read, and also does not dump a table.

    When you add print "checking pipe\n";, the first process outputs that, sees nothing to read, and exits. The second process now does see something to read - the diagnostic emitted by the first process - so it now calls dumpTable().

    The first thing I would suggest to reduce confusion is to use "warn" rather than "print" for your diagnostics, so that they show up on STDERR and not on the pipeline; it may also be useful to show the process id ($$) in those diagnostics, so that you can distinguish the two processes.

    I'm not familiar with the debugger, but since it will try to use STDIN to get console input it is certainly likely to confuse the issue.

    I tested this with the code below:

    % cat t0 #!/usr/bin/perl use strict; use warnings; use IO::Select; $|=1; warn "pid $$ checking pipe\n"; my $s = IO::Select->new(); $s->add(\*STDIN); if ($s->can_read(.5)) { warn "pid $$ can read\n"; print "here is my table\n"; } else { warn "pid $$ cannot read\n"; } % ./t0 | ./t0 pid 24811 checking pipe pid 24810 checking pipe pid 24811 cannot read pid 24810 cannot read % echo "go" | ./t0 | ./t0 pid 26452 checking pipe pid 26452 can read pid 26453 checking pipe pid 26453 can read here is my table %

    Update: remove unneeded '(a)'

      Thank you hv ! This is so super helpful. I put the following code at the top of my test script, included the diagnostic process warnings, and now the test script works fine. Also, It makes perfect sense that the debugger interacts with STDIN. So, unfortunately, I am still stuck with my original problem so I will continue to make the test script look like my production script. Thank you !

      if (-t STDIN) { dumpTable(); }
Re^2: IO::Select woes
by haj (Vicar) on May 05, 2023 at 17:54 UTC

    This is a race condition between your processes.

    The process left of the pipe has no STDIN defined, so it runs into the else path no matter what. And then... it terminates, closing its STDOUT during the process.

    The process right of the pipe tries to read. If the "left" process has not yet terminated, it will find something readable (at EOF, though), and that's why you can make it work in the debugger or with extra print statements (a print to a pipe blocks until it is read). In most cases, however, the left process will already be gone before Perl is done parsing your script, which then doesn't see anything left on STDIN.