Catching 2 signals with the same code causes hang?

Doing What Sounds Right <[email protected]>
Newsgroups gmane.comp.lang.perl.poe
Message-ID <[email protected]>
Ok, so I officially broke the time-space continuum today.

I'm writing a PoCo::IRC bot for an IRC server that I frequent, partly to 
help them out, and partly as a learning experience in writing OO Perl. 
Recently, I ran into a brick wall while trying to catch signals coming 
from the operating system. I got POE to catch HUP, KILL, TERM, and INT 
and whenever it receives INT or TERM, to call a sub to "gracefully" (I 
don't know how graceful most people would consider graceful) shut the 
bot down with a nice little quit message and everything. I had a 
momentary swelling of ego, until I tried the code to handle SIGINT. I 
noticed that the bot hung whenever it handled SIGINT (I'd have to send a 
second SIGINT to completely kill it). After a bit of help with dumping 
some debugging information from perigrin, I got a stack trace, which 
looks like this:

<dt> Cannot resolve ``2'' into a session reference at /usr/local/lib/perl5/site_perl/5.8.5/POE/Component/IRC.pm line 1906
        POE::Component::IRC::yield('POE::Component::IRC::State=HASH(0x86857c4)', 'privmsg', '#test', 'NOTICE->Shutting down... (command given by system) (Reason: R...') called at ./main.pl line 1099
        main::putlog('Shutting down... (command given by system) (Reason: Received ...', 'notice') called at ./main.pl line 700
        main::closedown('system', 'SIGINT', 'POE::Kernel=ARRAY(0x829d530)', 'Received SIGINT from the system') called at ./main.pl line 135
        main::on_int('INT') called at /usr/local/lib/perl5/site_perl/5.8.5/POE/Loop/Select.pm line 310
        eval {...} called at /usr/local/lib/perl5/site_perl/5.8.5/POE/Loop/Select.pm line 310
        POE::Kernel::loop_do_timeslice('POE::Kernel=ARRAY(0x829d530)') called at /usr/local/lib/perl5/site_perl/5.8.5/POE/Loop/Select.pm line 333
        POE::Kernel::loop_run('POE::Kernel=ARRAY(0x829d530)') called at /usr/local/lib/perl5/site_perl/5.8.5/POE/Kernel.pm line 1072
        POE::Kernel::run('POE::Kernel=ARRAY(0x829d530)') called at ./main.pl line 80
Died at /usr/local/lib/perl5/site_perl/5.8.5/POE/Kernel.pm line 321.
Died at /usr/local/lib/perl5/site_perl/5.8.5/POE/Kernel.pm line 321.


The code involved in closing down the bot is as follows:

These are the subs handling catching INT and TERM:
sub on_int
{
  closedown("system", "SIGINT" , $poe_kernel , "Received SIGINT from the system");
}
sub on_term
{
  closedown("system", "SIGTERM" , $poe_kernel , "Received SIGTERM from the system");
}

This is closedown():
sub closedown
{
  my ( $nick, $command, $kernel, $text ) = @_;
  putlog( "Shutting down... (command given by $nick" . ") (Reason: $text" . ")", "notice" );
  $kernel->alarm_remove_all( );
  unlink $bot{pidfile};
  $irc->yield( shutdown => uc($command) . " from $nick" . ": $text" . "." );
}

This is the sub that contains line 1099:
sub putlog
{

  # What are we logging, and what level is it?
  my ( $text, $level ) = @_[ 0, 1 ];

  # Convert the text level into a numeric for later filtering
  my $lnum;
  if ( $level eq "debug" )   { $lnum = 1; }
  if ( $level eq "info" )    { $lnum = 2; }
  if ( $level eq "notice" )  { $lnum = 3; }
  if ( $level eq "warning" ) { $lnum = 4; }
  if ( $level eq "error" )   { $lnum = 5; }

  # If our level is greater than or equal to the level we want logged..
  if ( $lnum >= $bot{loglevel} )
  {

    # Put stuff to $bot{logfile}
    open( LOGFILE, ">> $bot{logfile}" );
    print( LOGFILE ts() . " -" . uc($level) . "- " . $text . "\n" );
    close(LOGFILE);
  }

  # Default to $bot{loglevel} if our channel log level is not specified.
  if ( !$bot{monchan_level} )
  {
    $bot{monchan_level} = $bot{loglevel};
  }

# Check our channel specific level, and output to channel if we want the events logged.
  if ( $lnum >= $bot{monchan_level} )
  {
    $irc->yield( privmsg => $bot{monchan_chan} => uc($level) . "->" . $text );
  }

}

perigrin suggested changing this line:

$irc->yield( privmsg => $bot{monchan_chan} => uc($level) . "->" . $text );
  

to this:

$irc->call( privmsg => $bot{monchan_chan} => uc($level) . "->" . $text );
  

because call will block, while yield won't. This seems to fix the problem.

I'm just wondering what I'm doing (or not doing) that would cause POE to 
act like this. As I said before, handling SIGTERM (with on_term) works 
whether I use $irc->yield() or $irc->call(), but handling SIGINT (with 
on_int) only works if I use $irc->call().

PS $irc is my PoCo::IRC object.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.