Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

When to use sigtrap, when to assign to %SIG?

by Anonymous Monk
on Jan 02, 2012 at 08:29 UTC ( [id://945858]=perlquestion: print w/replies, xml ) Need Help??

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

When should I use sigtrap, when should I assign to %SIG? Is local $SIG{INT} important?

Replies are listed 'Best First'.
Re: When to use sigtrap, when to assign to %SIG?
by Old_Gray_Bear (Bishop) on Jan 02, 2012 at 08:50 UTC
    You use the sigtrap pragma when you need the extra mojo it supplies. In absence of any code, any further answer would be pure speculation.

    "Is local $SIG{INT} important?" -- that would depend on how it's used in the code that you haven't shown us. In absence of any code, any further answer would be pure speculation.

    UPDATE -- Fixed the link; thanks tanktalus

    ----
    I Go Back to Sleep, Now.

    OGB

      You use the sigtrap pragma when you need the extra mojo it supplies. In absence of any code, any further answer would be pure speculation.

      What mojo? Yes, do speculate

      "Is local $SIG{INT} important?" -- that would depend on how it's used in the code that you haven't shown us. In absence of any code, any further answer would be pure speculation.

      Is using local $SIG... important?

        Is using local $SIG... important?
        Sometimes it is. Usually, it doesn't matter as you want the same handler for the entire run of your program. Most of the time though, it doesn't hurt to have it localized.

        As a rule of thumb, I always localize my sig handlers, unless there's a good reason not to.

Re: When to use sigtrap, when to assign to %SIG?
by Marshall (Canon) on Jan 02, 2012 at 10:18 UTC
    local $SIG{INT} is a rather strange thing to attempt because that implies that CTRL-C has different meanings at different places in the code. I figure this is a "bad" idea.

    Update: Well text editors do re-define CTRL-C to mean copy-to-pasteboard. But they do it for the entire program. This is "well-known" behavior and is assumed to be global for the program. Even text editors do not do, and I do not recommend any context specific re-definition of CTL-C. I figure this is a "bad" idea. CTRL-C should mean something like: "abort" and that is the standard expected definition.

    Overriding say $SIG{__WARN__} in a local sense can be a good idea. I use that idea below to add extra info to a WARNING message in a DB subroutine. In this case, its a "non-numeric" operation attempted, or whatever...

    local $SIG{__WARN__} = sub { my $msg = shift; print STDERR "*******\n"; print STDERR $msg; print STDERR "current DB record: id=", $x->[$dbc_id]\n"; }; ..code that might cause an WARNING follows...
    However, I would personally not re-define what CTRL-C does within a program. Mileage of course does vary.

    There is a common misperception that signals don't work on Windows Perl. Not true. sleep() is implemented in terms of ALRM and that can and does cause difficulties, but the basic signals do work on Windows XP.

    Perl signals are actually easier than old-fashioned raw C signals (in some ways). However that gets into a lot more complex subject.

    #!/usr/bin/perl -w use strict; $SIG{INT} = 'CtrlC'; for (1..10) { print "$_\n"; sleep(1); } sub CtrlC { print "CTRL-C seen and ignored!\n"; } __END__ Example run:... I am just hitting CTRL-C at various times... C:\TEMP>perl ctrlc.pl 1 2 3 CTRL-C seen and ignored! 4 CTRL-C seen and ignored! 5 6 7 CTRL-C seen and ignored! 8 9 10
    Update: I don't see much reason to mess with sigtrap.
      There is a common misperception that signals don't work on Windows Perl. Not true. sleep() is implemented in terms of ALRM and that can and does cause difficulties, but the basic signals do work on Windows XP.

      Funny. Windows doesn't even have an API for signals, so how could they "work"?

      Perl emulates signals on Windows, and that emulation is not perfect. It "works" for some common cases, but even then, the emulation behaves different from a Unix system. See also perlport, perlwin32.

      Alexander

      --
      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
        Update: Something about this post "tweaked some go-buttons", I don't know why, but I think further posts make what I intended very clear. I can just strike this without changing the advice.

        Alexander, Perl provides the basic signal functions on Windows meaning emulate.

        The OP was asking about CTRL-C.
        And I provided some code that runs even on Windows! Although the question was not about Windows.

        If the question is about Windows specifically, lets start a new thread about it.

        My advice and code stands for *nix also.

      To be pedantic, setting $SIG{INT} does not define what ctrl-C does. It defines what action to take on receiving an interrupt signal. It's typically the shell that maps ctrl-C to an interrupt signal, but that can be set using stty.
      Well text editors do re-define CTRL-C to mean copy-to-pasteboard. But they do it for the entire program. This is "well-known" behavior and is assumed to be global for the program.
      Are you sure? Or is the text editor that you are using a graphical program (that is, doesn't run inside a terminal), and hence, ctrl-C isn't mapped to the "send SIGINT to foreground process" action in the first place? What happens if you actually send a SIGINT signal to the editor from a different process?
        I think we are getting far afield from what the OP asked.

      local $SIG{INT} is a rather strange thing to attempt because that implies that CTRL-C has different meanings at different places in the code. I figure this is a "bad" idea.

      It makes sense if you have a block of code that must be completed either in its entirety or not at all, to temporarily disable interrupts. For example, you want to remove a row from one database table and add a corresponding row to another database table. You don't want your code to be interrupted and leave the operation in an incomplete state.

      OK, so you'd normally use SQL transactions for that, but what if these two tables are in two different databases, on two different servers, at two different sites?

      Easy enough to locally override $SIG{INT}, to catch Ctrl+C and rather than exiting immediately, set an $interrupt_caught variable, and then when it is safe, check $interrupt_caught and exit.

        Easy enough to locally override $SIG{INT}, to catch Ctrl+C and rather than exiting immediately, set an $interrupt_caught variable, and then when it is safe, check $interrupt_caught and exit.

        This is not the right way because you are replicating OS functionality.

        The right way is to set the sigprocmask. You can use this to temporarily disable handling of a particular signal or all of them. If a signal occurs while it is blocked, that status is saved by the OS and when handling is re-enabled, it will be processed. This is called a "pending signal".

        I give you some C code for a routine that I called right before exiting (while updating a critical structure). The code below didn't save the current mask for later restore, but this is the idea.

        There are Perl equivalents to this. But since I haven't tested the exact code, and I might make a mistake, I will leave to the reader to research some more.

        Update: see sigproc mask for the Perl way.

        The basic idea is not to change "what happens" but rather to delay "what happens". This enables you to right there, in the code that does a critical action, surround it by "block" then "unblock" signal code - no other changes required.

        void block_all_signals(void) /* Block 'em Danno! */ { sigset_t all; Sigfillset(&all); Sigprocmask(SIG_BLOCK, &all, NULL); return; }
        Note: the capital letter forms, like Sigprocmask() instead of sigprocmask() are re-defined versions that do error processing. Handling these extremely rare, but yet important errors is important and it is too easy to forget to check the error return every time so, this technique does that.
        void Sigprocmask(int how, const sigset_t *mask, sigset_t *old) { if (sigprocmask(how, mask, old) < 0) { perror("sigprocmask"); exit(1); } }
        Oh, the "block 'em Danno!" comment is a nod to the Hawaii-five-O TV series. At the end to the show, the main cop always says: "Book 'em Danno" when the bad guys get arrested. I don't consider a bit of small humor in a comment to be an error - so I left it there. In this case it was the "final act" before exit.
        For example, you want to remove a row from one database table and add a corresponding row to another database table. [...] OK, so you'd normally use SQL transactions for that, but what if these two tables are in two different databases, on two different servers, at two different sites?

        <offtopic>Well, Oracle can do that in one transaction, if you use a DB link.</offtopic>

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://945858]
Approved by Old_Gray_Bear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (2)
As of 2024-04-26 01:31 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found