Wiggins has asked for the wisdom of the Perl Monks concerning the following question:

My chosen quest is to extend Srinivasn's Msg.pm (Advanced Perl Programming, Rel 1) by adding a 'workproc' capability. A callback that is called when the TIMEOUT in a select expires. That term came from X11. I used these a lot in X11R3 days.

I start by looking up Perl's handling of a TIMEOUT by IO:Select :

perldoc IO::Socket says
"TIMEOUT" is optional and has the same effect as for the core select call.
Rather terse and not of much help. This will not be a trivial quest! Me thinks there will be much testing and gnashing of teeth.
"core select call"... can't mean the Perl 'select' of the default FILE handle to print to. But perldoc -f select shows a more promising overloading of select! The documentation on the format of the TIMEOUT argument and response to it expiring are:
perldoc -f select says
The timeout, if specified, is in seconds, which may be fractional.
...
On error, "select" behaves like the select(2) system call : it returns -1 and sets $!.
Is a timeout treated as an error? Questing on leading to
man 2 select says
return the number of file descriptors contained in the three returned descriptor sets (that is, the total number of bits that are set in readfds, writefds, exceptfds) which may be zero if the timeout expires before anything interesting happens.
...
On error, -1 is returned, and errno is set appropriately; the sets and timeout become undefined, so do not rely on their contents after an error.
Gashing of teeth begins quickly...

It is always better to have seen your target for yourself, rather than depend upon someone else's description.

  • Comment on Msg.pm extended with "workproc". IO::Select docs

Replies are listed 'Best First'.
Re: Msg.pm extended with "workproc". IO::Select docs
by Wiggins (Hermit) on Oct 10, 2009 at 20:40 UTC
    I just started the testing and gnashing. The following is the test program.
    use IO::Select; use IO::Socket; use strict; my $lsn = new IO::Socket::INET(Listen => 1, LocalPort => 8080); my $sel = new IO::Select( $lsn ); my $rc= $sel->select ($sel,undef,undef, 2.2); #my $s= IO::Select->new(); #my $rc= $s->select (undef,undef,undef, 2.2); print "\$rc=<$rc>\n"; print "\$! <$!>\n"; print "\$@ <$@>\n";
    I have tried the above in different configurations of arguments to the ->select(...); and in no cases did the timeout fire. The program just blocked until it recieves a connection.

    From another xterm I then did:

    tuser> echo "x" |nc localhost 8080
    which produced the following at the blocked test program:
    $rc=<3>; $! <Illegal seek> $@ <> tuser>

    This may be moot if IO::Select doesn't process the timeout. The code examples in perldoc all show a fully blocked architecture using the 'can-read' sort of function.

    Puzzling...

    It is always better to have seen your target for yourself, rather than depend upon someone else's description.

timeouts and errors with IO::Select:: and CORE:: select (was Re: Msg.pm extended with "workproc". IO::Select docs)
by ikegami (Patriarch) on Oct 11, 2009 at 18:28 UTC

    Test based on documentation:

    use strict; use warnings; use IO::Select qw( ); use IO::Socket qw( ); my $lsn = IO::Socket::INET->new(Listen => 1, LocalPort => 8080); my $sel = IO::Select->new( $lsn ); my $no_error = my ($r_ready, $w_ready, $e_ready) = IO::Select->select($sel, undef, undef, 2.2); if ($no_error) { print("No error\n"); print("Num readers ready: ", 0+@$r_ready, "\n"); print("Num writers ready: ", 0+@$w_ready, "\n"); print("Num errors ready: ", 0+@$e_ready, "\n"); } else { print("Error ", 0+$!, ": $!\n"); }
    Win>perl a.pl Error 0: linux$ perl a.pl Error 29: Illegal seek

    Timeout returns as an error, but with a useless error message. There's no way to differentiate between errors and timeouts, and $! is only valid for errors.

    What about select? It could possibly return undef on error and 0 on timeout.

    Turns out it returns -1 on error.

    use strict; use warnings; use IO::Socket qw( ); my $lsn = IO::Socket::INET->new(Listen => 1, LocalPort => 8080); my $r_in = my $w_in = my $e_in = ''; vec($r_in, fileno($lsn), 1) = 1; vec($r_in, 100, 1) = 1 if $ARGV[0]; my $nfound = select( my $r_ready = $r_in, my $w_ready = $w_in, my $e_ready = $e_in, 2.2, ); $nfound >= 0 or die("select: (" . (0+$^E) . ") $^E\n"); if ($nfound) { print("nfound = $nfound\n"); } else { print("Timeout\n"); }
    Win>perl a.pl 0 Timeout Win>perl a.pl 1 select: (10038) Unknown error Using $^E instead of $! gives select: (10038) An operation was attempted on something that is not a socket linux$ perl a.pl 0 Timeout linux$ perl a.pl 1 select: (9) Bad file descriptor

    So the documentation for select needs to mention it returns -1 on error and that a timeout is not an error.

    And the following line needs to be changed in IO::Select's select:

    - if(select($rb,$wb,$eb,$t) > 0) + if(select($rb,$wb,$eb,$t) >= 0)

    (Well, you could come up with a more efficient implementation.)

    With the fix to IO::Select, the usage would be:

    use strict; use warnings; use IO::Select qw( ); use IO::Socket qw( ); my $lsn = IO::Socket::INET->new(Listen => 1, LocalPort => 8080); my $sel = IO::Select->new( $lsn ); my ($r_ready, $w_ready, $e_ready) = IO::Select->select($sel, undef, undef, 2.2) or die("Can't select: (" . (0+$!) . ") $!\n"); if (@$r_ready + @$w_ready + @$e_ready == 0) { print("Timeout\n"); } else { print("Num readers ready: ", 0+@$r_ready, "\n"); print("Num writers ready: ", 0+@$w_ready, "\n"); print("Num errors ready: ", 0+@$e_ready, "\n"); }
      Thanks... I obviously got my metaphors mixed. All is well and the quest continues...
      Clarification for my enlightenment. The fore part of the statement
      my $no_error = my ($r_ready, $w_ready, $e_ready) = IO::Select->select($sel, undef, undef, 2.2);
      sets $no_error true if any of the element in the list are defined. And in the case of the TIMEOUT, they will always all be undefined?

      It is always better to have seen your target for yourself, rather than depend upon someone else's description.

        IO::Select::select is documented to return an empty list (zero values) on error. It also returns this on timeout.

        And in the case of the TIMEOUT, they will always all be undefined?

        Assigning an empty list to a variable will undefine it, so yes.

        sets $no_error true if any of the element in the list are defined.

        Yes, but not directly. $no_error is set to the number of values returned by IO::Select::select. Since IO::Select::select returns either an empty list or three references, the vars are only undefined when $no_error is false, and they're always undefined when $no_error is false.