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?
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
| [reply] [d/l] |
|
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?
| [reply] |
|
| [reply] |
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.
| [reply] [d/l] [select] |
|
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". ;-)
| [reply] |
|
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.
| [reply] |
|
|
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?
| [reply] [d/l] |
|
I think we are getting far afield from what the OP asked.
| [reply] |
|
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.
| [reply] |
|
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.
| [reply] [d/l] [select] |
|
| [reply] |
|
|