[Melbourne-pm] Term::ReadLine && ctrl-C

Tim Connors tconnors+pmmelb at astro.swin.edu.au
Sun Jan 14 08:29:46 PST 2007


This post partly for the sake of goggles, since many searches along the 
lines of '"ctrl c" "term readline"', 'deferred signals gnu term readline' 
etc return a whole bunch of people over time that have asked similar 
questions to me, and never obtained an answer.  Nevertheless, comments?  
Anyone done this an easier, more correct, way?

man perlipc tells me that since Perl 5.7.3, signals in perl use a deferred 
signal scheme, whereby perl will set a flag telling itself that a signal 
has occurred, and if raise the real handler as soon as it is safe to do 
so.  In the case of IO, the system call is not returned to, but other 
system calls are restarted.

However, Term::ReadLine(::Gnu) is restarting whatever system calls it is 
using.  If I press Ctrl C, or send a SIGINT etc, then my handler doesn't 
get called until I press enter at the readline prompt.  This sucks.

Here's my solution (might not compile, because I've removed a bit of 
irrelevant crap, but should be easy enough to fix).


#these are the handlers for our signals when readline not being called
foreach my $signal (qw (INT TERM HUP)) {
  $SIG{$signal} = \&graceful_exit;
}

#read_line sets it's own special handlers, because it is "special".
sub read_line {
  my $default=$_[0];

  sub unsafe_signals {
    my $signal=$_[0];
    debug "signal called at unsafe time\n";
    debug "signal=$signal\n";

    $term->free_line_state;   #just give readline a chance to cleanup
                              #after itself
    $term->cleanup_after_signal;
    graceful_exit($signal);
  }

  # See
  # 
http://www.perldoc.com/perl5.8.4/pod/perlipc.html#Deferred-Signals-(Safe-Signals)
  # Term::ReadLine::Gnu restarts whatever system call it is using,
  # such that once we ctrl C, we don't get back to Perl until the user
  # presses enter, finally whereupon we get our signal handler called.
  # We use sigaction instead to use the old perl unsafe signal
  # handling, but only in this read routine.  Sure, sigaction poses
  # race conditions, but you'd typically expect ctrl-C when at a
  # prompt when it is quiescent; ie printf and malloc etc aren't
  # currently being called

  my $sigset = POSIX::SigSet->new();
  my $sigaction = POSIX::SigAction->new( \&unsafe_signals, $sigset, 0);

  my $old_int_action=POSIX::SigAction->new;
  #set up our unsafe signal handler
  POSIX::sigaction(&POSIX::SIGINT, $sigaction, $old_action);  #save the default one
  POSIX::sigaction(&POSIX::SIGHUP, $sigaction);
  POSIX::sigaction(&POSIX::SIGTERM, $sigaction);

  my $res = $term->readline("iter2> ", '');

  #restore the real signal handler
  POSIX::sigaction(&POSIX::SIGINT, $old_action);
  POSIX::sigaction(&POSIX::SIGHUP, $old_action);
  POSIX::sigaction(&POSIX::SIGTERM, $old_action);

  if (defined $res) {
    $res =~ s/^\s+|\s+$//g;    # lop off whitespace
    $term->AddHistory($res);
  }
  return $res;
}


-- 
Tim Connors
http://site.aao.gov.au/twc



More information about the Melbourne-pm mailing list