I was given the program below in an exam and the question was how many kill signals must be sent to the process in order to terminate it. My answer was 3 signals, but the professor insisted on only 2 signals are needed to terminate the process? How is so?
static void action(int sig)
{
signal(SIGINT,SIG_DFL);
}
int main()
{
signal(SIGINT,SIG_IGN);
signal(SIGUSR1,action);
while(1)
pause();
}
You need to send SIGUSR1 to invoke the action. And all action does is set SIGINT to its default signal handler (SIG_DFL). Then you send the SIGINT, that then triggers the default handler which terminates the process.
NOTE: It must be done in that order, any attempt to send SIGINT before SIGUSR1 will be ignored because of the bind to SIG_IGN.
Related
I read:
There are two signals that a process can’t ignore – SIGKILL =
terminate the receiving process – SIGSTOP = suspend the receiving
process
And some even claimed there is no way we can declare handlers for them
But In C I can write:
#include <signal.h>
#include <stdio.h>
void sigint_handler(int signum) {
printf("I'm ignoring you!\n");
}
int main() {
signal(SIGKILL,sigint_handler);
for(;;) { /*endless loop*/ } return 0;
}
Isn't this a contradiciton?
Side Question, When I write kill 123 in the terminal what signal will be sent I can't find this information anywhere in the internet?
Per POSIX-1.2017 General Information §2.4.3 Signal Actions
, a signal may have one of three different dispositions or "actions taken" when it is delivered to a process:
SIG_DFL: take the default or "normal" action.
SIG_IGN: ignore the signal (take no action).
user-defined: the signal is "caught" by a user-defined signal handler.
That said, the same section of POSIX also clarifies:
The system shall not allow the action for the signals SIGKILL or SIGSTOP to be set to SIG_IGN.
....
The system shall not allow a process to catch the signals SIGKILL and SIGSTOP.
If you checked the return code and errno of your signal() call, you'd almost certainly see it failing with EINVAL.
I have made this program and the output so far doesn't make much sense to me. Can someone please explain what is going on?
void handler1a(int x){
printf("A\n");
}
int main(){
signal(SIGUSR1, handler1a);
int p = fork();
if(p==0)
{
sleep(5);
printf("L \n");
}
else
{
kill(0,SIGUSR1);
kill(0,SIGUSR1);
kill(0,SIGUSR1);
//kill(0,SIGUSR1);
wait(NULL);
}
}
With 3 kill signals, my output is- 5A and 1L. With 2 kill signals, the output is- 4A and 1L. With 4 kill signals, output is- 6A and 1L. It seems like upto 2 kill signals, both parent and child process are using my custom handler but somehow one of them isn't using the handler or isn't getting the kill signal after receiving the signal it twice already (it would explain why only a single A is printed when I add another kill system call after 2 kill system calls).
Signals aren't queued. So if you send the same signal to a process multiple times, it may get processed any number of times from 1 to the number of times you sent the signal.
Or, to put it another way, for each combination of process and signal, the signal can be in the signaled state. If you send a signal to a process when that process is already in the signaled state for that signal, nothing happens.
A process cannot have two SIGUSR1 signals pending. Either SIGUSR1 is pending or it isn't.
Here kill is called by the parent process P with 0 as its pid value which means that all the processes in its group (P itself, as well as the child C) will get the signal and the same custom signal handler will be used to process it.
If you are sending multiple signals to the process C that are of same type (SIGUSR1 here), they will not be queued because that signal will be blocked until the first one received is handled, and they will be discarded.
Only when the signal handler for C returns, C is ready to process the signal again. This explains why there are fewer "A"s in the output from C's invocation of the handler.
You can see which process has called the handler by adding printf("A %d\n", getpid()) inside the handler.
I want to simulate a game server that should continuously send and receive signals with its parent. The scenario is as follows:
Parent sends signal to game.
Game catches the signal and sends a signal to the parent.
Parent catches the signal and sends again a signal to game.
and so on...
The problem is that the stops receiving or sending after the first lap:
static int game_s;
void game()
{
printf("game\n");
signal(SIGUSR1,game);
sleep(1);
kill(getppid(),SIGUSR1);
pause();
}
void parent()
{
printf("parent\n");
signal(SIGUSR1,parent);
sleep(1);
kill(game_s,SIGUSR1);
pause();
}
void main()
{
game_s = fork();
if(game_s>0)
{
signal(SIGUSR1,parent);
sleep(1);
kill(game_s,SIGUSR1);
pause();
}
else
{
signal(SIGUSR1,game);
pause();
}
}
The output is the following:
game
parent
Why it stopped here? Shouldn't the game server catch parent's signal and print "game" again...
By default the reception of a specific signal is blocked from the moment a process received this specific signal until the related signal handler had been left.
From man 3 signal:
void (*signal(int sig, void (*func)(int)))(int);
[...]
When a signal occurs, and func points to a function, it is implementation-defined whether the equivalent of a:
signal(sig, SIG_DFL);
is executed or the implementation prevents some implementation-defined set of signals (at least including sig) from occurring until the current signal handling has completed.
To change this behaviour establish the signal handling via sigaction() instead of signal() (which one should do any ways for portability reasons).
sigaction() takes a struct sigaction. The member sa_flags of the latter should have SA_NODEFER set.
From Linux' man 2 sigaction:
SA_NODEFER
Do not prevent the signal from being received from within its own signal handler. This flag is meaningful only when establishing a signal handler.
POSIX words this differently:
SA_NODEFER
If set and sig is caught, sig shall not be added to the
thread's signal mask on entry to the signal handler
unless it is included in sa_mask. Otherwise, sig shall
always be added to the thread's signal mask on entry to
the signal handler.
Be aware that each signal handler gets it's own stack allocated each time it gets invoked, so sooner or later this recursive ping-pong ends up in an out-of-memory condition.
Use message queues, or shared memory to do this. As stated above, this will eventually run out of memory and it will crash.
I have a parent process that manages a child (fork, execve). I created a handler in the parent to catch SIGCHLD signals from the child in order to call waitpid() and take appropriate action such as restarting the child.
I understood from the manual page for sigaction() that, while inside a signal handler, further signals of the same type would be blocked by default. I definitely wish for this behaviour so I decided to test it.
I put a sleep (my own implementation using clock_nanosleep() in a loop which resumes when interrupted) at the end of the signal handler and sent a SIGINT to the child. This duly made it quit and sent SIGCHLD to the parent. I logged the fact and started my sleep for 10 seconds. Now, I sent another SIGINT to the new child (sighandler restarted it first time) and was surprised to see another log and sleep happen.
How can this be? When I attached using a debugger to the parent it clearly showed two different threads interrupted to call my signal handler, both now sat in sleep. If that keeps up I will run out of threads!
I understand putting long sleeps into a signal handler is a daft thing to do but it does illustrate the point; I expected to see the second signal marked as pending in /proc/[PID]/status but instead it's delivered.
Here's the relevant bits of my code:
Set up the SIGCHLD handler:
typedef struct SigActType {
struct sigaction act;
int retval;
void (*func)(int);
}SigActType;
static SigActType sigActList[64];
public void setChildHandler(void (*func)(int)) {
SigActType *sat = &sigActList[SIGCHLD];
sat->act.sa_sigaction = sigchldHandler;
sigemptyset(&sat->act.sa_mask);
sigaddset (&sat->act.sa_mask, SIGTERM);
sigaddset (&sat->act.sa_mask, SIGINT);
sigaddset (&sat->act.sa_mask, SIGCHLD);
sat->act.sa_flags = SA_SIGINFO;
sat->retval = 0;
sat->func = func;
sigaction(SIGCHLD, &sat->act, NULL);
}
static void sigchldHandler(int sig, siginfo_t *si, void *thing) {
SigActType *sat = &sigActList[SIGCHLD];
if (sat->func) {
sat->func(si->si_pid);
}
}
and using this:
int main(int argc, char **argv) {
setChildHandler(manageChildSignals);
...
}
static void manageChildSignals(int d) {
if ((pid = waitpid(-1, &stat, WAIT_MYPGRP)) > 0) {
... restart child if appropriate
}
printf("start of pause...\n");
mySleep(10);
printf("end of pause...\n");
}
Stdout clearly shows:
(when I type kill -2 [PID]
start of pause
(when the new child is started and I type kill -2 [NEWPID]
start of pause
...10 seconds slide past...
end of pause
end of pause
I am puzzled as to why this happens. As you can see I even added SIGCHLD to the block mask for sigaction() to try to encourage it to do the right thing.
Any pointers most welcome!
signals of the same type would be blocked by default.
Yes, but only for the thread sigaction() is called from.
From man sigaction (bold emphasis by me):
sa_mask specifies a mask of signals which should be blocked (i.e.,
added to the signal mask of the thread in which the signal handler is
invoked) during execution of the signal handler.
As signal dispostion is per process any other thread not blocking the signal in question might receive it, that is get interupted and process it.
If this behaviour is not what you want you should perhaps modify the design of the way your program handles signals in such a way that per default all signals are blocked for each thread, and only one specifiy thread has signal reception unblocked.
Update:
Signals masks are inherited from the parent thread by the child thread.
If signal handling shall be done by one specific thread only, have the main thread block all signals prior to creating any other thread. Then create one specfic thread to do the signal handling, and have this thread unblock the signals to be handled. This concept also allows models like one thread per signal.
In a mutlithreaded environment use pthread_sigmask() to mask signals on a per thread base.
Please note that the behaviour of sigprocmask() in a multithreaded process is unspecified, use pthread_sigmask() then.
My function created to handle the SIGINT signal is stuck in a constant loop. The idea is to make CTRL-C ignored by the parent process but sent to the child process (and they handle it as default). What happens is when I press CTRL-C, the signal handler function is called but gets stuck in an endless loop. The kill call is supposed to send SIGTERM to all process in the process group except for the sender process. Any help would be appreciated.
the function code is:
void intHandler(int signum) {
kill(0, SIGTERM);
}
the function call code (in main) is:
(void) sigset(SIGINT, intHandler);
From the kill man page.
If pid is 0, sig shall be sent to all processes (excluding an unspecified set of system processes) whose process group ID is equal to the process group ID of the sender, and for which the process has permission to send a signal.
Nothing about not sending the signal to the sender, so you most likely want something like:
void intHandler(int signum) {
sigset(SIGINT, SIG_DFL);
kill(0, SIGTERM);
}
This will reset your signal handler in the sender to default before sending the SIGTERM to all members of the process group.