Signal handling: printing something and then taking the default behaviour - linux

My requirement is that whenever a program terminates in any way other than its normal completion [i.e. exit() system call at the end], I need to handle it (say, hook a print "Hello" statement) before it actually terminates.
For example, when I hit Ctrl+C while running a program, it should print Hello and continue the way a SIGINT must have been handled.
If I use my custom signal handler function (having a print statement logic) in my source code, it would alter the default behavior i.e. how SIGINT would have ideally terminated.
1) Can anyone help me achieve both of this? What other signals I need to handle explicitly (maybe SIGTERM ?) which can cause termination of a running process?
2) How can I generate/test them ?(say, SIGINT can be generated by hitting Ctrl + C in linux)

there are several signals supported in unix/linux.
Except SIGKILL, SIGSTOP, all others can be interpreted and handled.
process of registering the handler to a particular signumber should be same.
We can use kill command to send signals to other process.
For example: it sends TERM signal to processid 1234
kill -s TERM 1234

The sigaction(2) man page has some useful info. For one thing, every signal but SIGKILL and SIGSTOP can be caught.
In your signal handler, you have two options:
puts(3) and then manually do something (exit() or raise(SIGSTOP) or something).
puts(3) and then try to get the default signal behaviour by setting the handler back to SIG_DFL, and sending the signal to yourself with raise(3). I'm not sure whether you can just sigaction() to restore your signal handler right after raise() from inside that signal handler, and whether that would be portable even if it happens to work on Linux.
List all signals with kill -l
Send a signal with kill -INT 1234, or in the shell you started a background process from: kill -INT %1. Or to avoid copy/pasting a PID every time: pkill -INT process_name (pkill and pgrep are related.)

Related

How to know where does a signal come from on Linux?

I'm running a python script but it is always stopped somehow. So I need to know who stopped this process.
Is there any tool to know who sent the signal that stopped a process?
If you are able to wait at the end of your main process, you can add something like:
import signal
siginfo = signal.sigwaitinfo({signal.SIGTERM})
print("got %d from %d by user %d\n" % (siginfo.si_signo,
siginfo.si_pid,
siginfo.si_uid))
(Adapted from here: works on Python 3.5.2 on Linux)
which will block your script and make it wait until it gets a SIGTERM, then it'll print out the pid of the process that sent the SIGTERM. You can swap SIGTERM for SIGINT if it was a SIGINT that stopped your program. Unfortunately you can only catch signals in the main process and not in seperate threads, see here for more information.

Handle and propogate SIGHUP signal to child process without parent termination

I've got a piece of classic problem, but can't figure out how to deal with it. There is a bash process which executes children, and I want to send some signal to it (SIGHUP), handle it there and propagate this signal to one of the children (another_long_running_process for example). Here is snippet:
#!/bin/bash
long_running_process &
another_long_running_process &
pid=$!
trap 'kill -1 $pid' HUP
wait $pid
Ok, now I setup trap, create handler to send signal to particular pid, but then find out that my script just exits after first SIGHUP receiving and handling. The problem that bash returns immediately from wait built-in:
When Bash receives a signal for which a trap has been set while waiting for a command to complete, the trap will not be executed until the command completes. When Bash is waiting for an asynchronous command via the wait built-in, the reception of a signal for which a trap has been set will cause the wait built-in to return immediately with an exit status greater than 128, immediately after which the trap is executed.
And yes, my script just exits after first time I send SIGHUP, by design. But I need to keep it running.
And I can't figure out how to wait children processes, and propagate one of them (ok, even all of them) SIGHUP signals multiple times while they're running. Is this achievable in such problem definition? I think with parent pid I can iterate over children and find required process and then send signal particularly there, but it looks a bit overengineering, or not?
Ok, finally I fix my problem with following approach: I setup ignore signal handler in bash-script and make it leader of process group. Then redefine SIGHUP handler in another_long_running_process and then send signal to process group. So bash-script and long_running_process ignore that signal, and another_long_running_process catch signal and handle it.

How do I learn about unknown children exiting in Go on Unix/Liunx?

It doesn't look like Go has a way to register a signal handler, so I can't catch SIGCHLD. So, how do I learn about a process exiting that I may not known about because my process has its CHILD_SUBREAPER flag set or is PID 1 in a PID namespace.
You can register signal handlers using signal.Notify

What key combinations are associated with signals

I am writing some perl scripts and I want to utilize signals to perform certain routines at any time. I see all over the place the ability to print out what the signals are,
perl -e 'foreach (keys %SIG) { print "$_\n" }'
and I have already been using "INT" to go to a subroutine which is activated with ctrl+c.
I cant find anywhere what key combinations are associated with the other signals. Is there a list somewhere? The script I'm writing should work on mac and linux computers.
I know the ctrl+c signal is analogous between systems, what other "signals" can be utilized in perl and what keys activate them?
what other "signals" can be utilized in perl
These are the signal names recognized by Perl:
$ perl -V:sig_name
sig_name='ZERO HUP INT QUIT ILL TRAP ABRT BUS FPE KILL USR1 SEGV USR2 PIPE ALRM TERM STKFLT CHLD CONT STOP TSTP TTIN TTOU URG XCPU XFSZ VTALRM PROF WINCH IO PWR SYS NUM32 NUM33 RTMIN NUM35 NUM36 NUM37 NUM38 NUM39 NUM40 NUM41 NUM42 NUM43 NUM44 NUM45 NUM46 NUM4 NUM48 NUM49 NUM50 NUM51 NUM52 NUM53 NUM54 NUM55 NUM56 NUM57 NUM58 NUM59 NUM60 NUM61 NUM62 NUM63 RTMAX IOT CLD POLL UNUSED ';
The above list can also be obtained from Config.pm's $Config{sig_name}.
There's also the two pseudo signals, __WARN__ and __DIE__.
and what keys activate them?
The following signals are often sent in response to terminal input:
SIGINT
SIGQUIT is a more "serious" version of SIGINT that provides a core dump.
SIGTSTP sends a process to the background.
SIGSTOP is an uncatchable signal that freezes the process.
SIGCONT resumes a process frozen by SIGSTOP.
You can see to what key these are bound using the following:
$ stty -a | perl -ne'
$b{$1}=$2 while /\b(intr|quit|susp|stop|start)\s*=\s*([^\s;]+)/g;
END {
print "SIGINT: $b{intr}\n";
print "SIGQUIT: $b{quit}\n";
print "SIGTSTP: $b{susp}\n";
print "SIGSTOP: $b{stop}\n";
print "SIGCONT: $b{start}\n";
}
'
SIGINT: ^C
SIGQUIT: ^\
SIGTSTP: ^Z
SIGSTOP: ^S
SIGCONT: ^Q
Most signals aren't sent as a result of terminal input. The following a commonly used signals and what normally causes them to be sent:
SIGSEGV is sent when the program does an illegal operation (often the result of using a bad pointer).
SIGHUP is sent when the session's terminal disconnects.
SIGTERM is sent to request that a process exits.
SIGKILL can't be caught. It's sent to forcibly terminate a process.
SIGCHLD is sent when a child exits.
SIGALRM is sent by alarm.
SIGPIPE is sent when writing a pipe with a closed read end.

How can a process kill itself?

#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
int main(){
pid_t pid = fork();
if(pid==0){
system("watch ls");
}
else{
sleep(5);
killpg(getpid(),SIGTERM); //to kill the complete process tree.
}
return 0;
}
Terminal:
anirudh#anirudh-Aspire-5920:~/Desktop/testing$ gcc test.c
anirudh#anirudh-Aspire-5920:~/Desktop/testing$ ./a.out
Terminated
for the first 5 secs the output of the "watch ls" is shown and then it terminates because I send a SIGTERM.
Question: How can a process kills itself ? I have done kill(getpid(),SIGTERM);
My hypothesis:
so during the kill() call the process switches to kernel mode. The kill call sends the SIGTERM to the process and copies it in the process's process table. when the process comes back to user mode it sees the signal in its table and it terminates itself (HOW ? I REALLY DO NOT KNOW )
(I think I am going wrong (may be a blunder) somewhere in my hypothesis ... so Please enlighten me)
This code is actually a stub which I am using to test my other modules of the Project.
Its doing the job for me and I am happy with it but there lies a question in my mind how actually a process kills itself. I want to know the step by step hypothesis.
Thanks in advance
Anirudh Tomer
Your process dies because you are using killpg(), that sends a signal to a process group, not to a process.
When you fork(), the children inherits from the father, among the other things, the process group. From man fork:
* The child's parent process ID is the same as the parent's process ID.
So you kill the parent along with the child.
If you do a simple kill(getpid(), SIGTERM) then the father will kill the child (that is watching ls) and then will peacefully exit.
so during the kill() call the process switches to kernel mode. The kill call sends the SIGTERM to the process and copies it in the process's process table. when the process comes back to user mode it sees the signal in its table and it terminates itself (HOW ? I REALLY DO NOT KNOW )
In Linux, when returning from the kernel mode to the user-space mode the kernel checks if there are any pending signals that can be delivered. If there are some it delivers the signals just before returning to the user-space mode. It can also deliver signals at other times, for example, if a process was blocked on select() and then killed, or when a thread accesses an unmapped memory location.
I think it when it sees the SIGTERM signal in its process tables it first kills its child processes( complete tree since I have called killpg() ) and then it calls exit().
I am still looking for a better answer to this question.
kill(getpid(), SIGKILL); // itself I think
I tested it after a fork with case 0: and it quit regular from separate parent process.
I don't know if this is a standard certification method ....
(I can see from my psensor tool that CPU usage return in 34% like a normal program code with
a counter stopped ) .
This is super-easy in Perl:
{
local $SIG{TERM} = "IGNORE";
kill TERM => -$$;
}
Conversion into C is left as an exercise for the reader.

Resources