Ambiguous behaviour of kill system call in C - c

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.

Related

Nested signal handlers in C

I want to work on signal handlers in the context of two independent processes namely writer and reader for notification. The writer sends a first signal SIGUSR1 to the reader which loops till it hears the second signal SIGUSR2 from the writer.
reader.c
static volatile sig_atomic_t done_waiting;
int handler1(int signal){
done_waiting = 0;
while( !done_waiting ){
(void)fprintf(stdout, " reader waiting for sigusr2: done_waiting = %d\n", done_waiting );
}
(void)fprintf(stdout, " reader received sigusr2 \n);
}
int handler2 (int signal){
done_waiting = 1;
}
main(){
signal(SIGUSR1, handler1);
signal(SIGUSR2, handler2);
sleep(5); // sleep till we start worker
}
In writer.c, signals are sent to the reader as
main(){
kill(pid_reader, SIGUSR1);
sleep(5);
kill (pid_reader, SIGUSR2);
}
When I execute reader first followed by worker, the program quits at the while loop. And the writer prints that "No matching processes belonging to you were found".
Is nesting signal handlers allowed and if yes, is it recommended? Also, is there any another alternative mechanism for writer to notify reader that it is ready?
Is maybe nested signals actually what you meant, not nested signal handlers ? To clarify, what will happen if a SIGUSR2 is received while the handler for SIGUSR1 is executing, is that what you mean ? I assume so,
I tested your code, with some modifications, to get the pid for the reader process into the writer process I used the args to main.
The results I get is.
First reader is quiet
After receiving SIGUSR1 it starts continuously writing that it waits for SIGUSR2
When receiving SIGUSR2, it prints "reader received SIGUSR2"
This indicates that it is possible to have nested signals. However I would not say it is recommended as an intentional design.
As mentioned in the comments, you should do as little as possible in the signal handlers, definitely not loop in a while-loop.
And as also mentioned in the comments, be very careful what functions you call in signal-context, printf() is not OK, even though it may seem to work fine.
Tested on Linux, with the ancient kernel 3.16 and gcc 4.9

How many kill signals this program needs to be terminqted

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.

SIGTSTP signal handler for child process

So I'm trying to implement a signal handler for the SIGTSTP signal in a child process.
Basically what I'm trying to achieve is this:
Start child Process
Make the parent wait on the child process
call Sleep on the Child process for x seconds.
Before the sleep finishes execution, I want to send a Ctrl+Z signal.
This signal should stop the child process, but resume the parent
process. The parent process should then know the process id of the
stopped process.
I run it using the command: ./testsig sleep 10
This is my code so far:
#include<stdlib.h>
#include<stdio.h>
#include<signal.h>
#include<string.h>
volatile sig_atomic_t last_proc_stopped;
volatile sig_atomic_t parent_proc_id;
void handle_stp(int signum)
{
if(getpid()==parent_proc_id)
{
kill(parent_proc_id,SIGCONT);
signal(SIGTSTP,handle_stp);
}
else
{
last_proc_stopped=getpid();
kill(parent_proc_id,SIGCONT);
}
}
void main(int argc, char *argv[])
{
int childid=0,status;
signal(SIGTSTP,SIG_IGN);
parent_proc_id=getpid();
childid=fork();
if(childid>=0)
{
if(childid==0)//child
{
signal(SIGTSTP,handle_stp);
strcpy(argv[0],argv[1]);
strcpy(argv[1],argv[2]);
argv[2]=NULL;
printf("Passing %s %s %s\n",argv[0],argv[1],argv[2]);
execvp(argv[0],argv);
}
else
{
wait(&status);
printf("Last Proc Stopped:%d\n",last_proc_stopped);
}
}
else
{
printf("fork failed\n");
}
}
Currently, it seems like ctrl+Z has some kind of effect (but definitely not the one I want!)
When I hit ctrl+Z in the middle of the child executing sleep, the cursor continues to blink for the remainder of the (in my case 10) seconds, but control does not reach the parent process.
Without hitting ctrl+Z, control returns to the parent as expected.
What am I doing wrong?
I have seen this answer as well, but I'm not really able to understand it:
After suspending child process with SIGTSTP, shell not responding
You have two processes:
The parent, which ignores the signal,
The child, which sets a handler, then execs another process - this will clear the code of the signal handler from the memory (the executed program will be loaded in place of the calling process), therefore will also clear the signal settings as well. So, your signal handler function will never be called. Is it possible to signal handler to survive after “exec”?
What you could do to achieve your goal?
The parent should ignore the signal,
The child should leave the default signal handling (which stops it),
The parent should use waitpid() to see if the child process exited or was stopped, and act accordingly (this involves actually killing the stopped child process).

Waiting for child process to terminate, or not - C

I'm trying to do an assignment for one of my classes and no professors/fellow classmates are getting back to me. So before you answer, please don't give me any exact answers! Only explanations!
What I have to do is write a c program (timeout.c) that takes in two command line arguments, W and T, where W is the amount of time in seconds the child process should take before exiting, and T is the amount of time the parent process should wait for the child process, before killing the child process and printing out a "Time Out" message. Basically, if W > T, there should be a timeout. Otherwise, the child should finish its work and then no timeout message is printed.
What I wanted to do was just have the parent process sleep for T seconds, and then kill the child process and print out the timeout, however printing out the timeout message would happen no in both cases. How do I check to see that the child process is terminated? I was told to use alarm() for this, however I have no idea of what use that function would serve.
Here's my code in case anyone wants to take a look:
void handler (int sig) {
return;
}
int main(int argc, char* argv[]){
if (argc != 3) {
printf ("Please enter values W and T, where W\n");
printf ("is the number of seconds the child\n");
printf ("should do work for, and T is the number\n");
printf ("of seconds the parent process should wait.\n");
printf ("-------------------------------------------\n");
printf ("./executable <W> <T>\n");
}
pid_t pid;
unsigned int work_seconds = (unsigned int) atoi(argv[1]);
unsigned int wait_seconds = (unsigned int) atoi(argv[2]);
if ((pid = fork()) == 0) {
/* child code */
sleep(work_seconds);
printf("Child done.\n");
exit(0);
}
sleep(wait_seconds);
kill(pid, SIGKILL);
printf("Time out.");
exit(0);
}
Although waitpid would get you the return status of the child, its default usage would force parent to wait until the child terminates.
But your requirement (if i understood correctly) only wants parent to wait for a certain time, alarm() can be used to do that.
Then, you should use waitpid() with a specific option that returns immediately if the child has not exited yet (study the api's parameters). So if the child didn't exit, you could kill it, else you already receive its return status.
You want the timeout program to stop more or less as soon as the command finishes, so if you say timeout -t 1000 sleep 1 the protecting program stops after about 1 second, not after 1000 seconds.
The way to do that is to set an alarm of some sort — classically, with the alarm() system call and a signal handler for SIGALRM — and then have the main process execute wait() or waitpid() so that when the child dies, it wakes up and collects the corpse. If the parent process gets the alarm signal, it can print its message and send death threats of some sort to its child. It might be sensible to try SIGTERM and/or SIGHUP before resorting to SIGKILL; the SIGTERM and SIGHUP signals give the errant child a chance to clean up whereas SIGKILL does not.
If you know how to manage signals, you could catch SIGALRM and SIGCHLD in your parent process. SIGCHLD will be raised when the client terminates, and SIGALRM when the timer expires. If the first raised signal is SIGALRM, the timeout expired, otherwise, if the first SIGNAL that the parent catches is SIGCHLD, the child has stopped before the expiration of the timeout.
wait() or waitpid() would still be necessary to collect the terminated child.

C using Signals to stop child processes

My current program is creating child processes and giving them work (CPU intensive work). The main() sits there and waits for the child processes to send data via pipes (using select).
What I wanted to do is when the program is processing data I could press CTRL+C to stop the child processes from working and asking the user if he wants to quit or resume work.
If user wants to quit, the program would kill all the processes. If user wants to resume work, it would tell the child processes to resume the computation.
I already have the code in place but it's not quite working right.
In main I have signal(SIGINT, pausar); to handle SIGINT (CTRL+C).
This is the pausar() function:
void pausar(int signum){
signal(SIGINT, pausar);
int i;
// pid[] contains all the child processes
for(i = 0; i<CORES; i++)
{
kill(pid[i], SIGSTOP);
}
char option[2];
printf("\n Computacao pausada.\n'S' para sair ou 'C' para continuar: ");
scanf("%1s", option);
if (option[0] == 's' || option[0] == 'S') {
printf("A desligar...\n");
//if user wants to quit, kill all the child processes
for(i = 0; i<CORES; i++)
{
kill(pid[i], SIGKILL);
}
exit(0);
}
else
{
printf("[%d] A resumir computacao...\n",getpid());
kill(getpid(), SIGCONT);
//if user wants to resume work, send signal to continue
for(i = 0; i<CORES; i++)
{
kill(pid[i], SIGCONT);
printf("%d resumiu\n", pid[i]);
}
}
}
The problem is that sometimes I press CTRL+C and nothing shows in the console (but the processes STOP because I'm paying attention to the process manager). The other problem is that after I enter 'C' to resume work, I get errors in select() and the children never resume work.
Using select() and signal-handler at the same time is prone to race conditions - a signal could occur during the select() call, but also in every other line of code.
If your are on linux: create an event socket with signalfd() and add this socket to the read set passed to select(). Signals are then handled at a fixed point in your code and you do not need to worry about race conditions.
First, for what you're trying to-do, your signal handler is way too complex. Secondly, calling signal() inside your signal handler is not a good idea ... it's not an asynchronous signal-safe function.
What you can do is the following:
In your main, set the signal handler function using signal() like you've done.
Block the SIGINT signal via sigprocmask(). This prevents a spurious signal from arriving before the call to pselect().
Inside your signal handler only set a simple global flag that is a sig_atomic_t
Use pselect() instead of select(). This will allow you to change the process signal mask to allow a SIGINT signal to arrive, and it will do-so in an atomic manner with respect to signals. Otherwise, you could have your SIGINT arrive before the call to select(), and then you have "lost" that signal, even though it does set the flag in the handler.
When the pselect() call returns, detect whether the flag has been set.
If the global sig_atomic_t flag was set, and you returned from pselect because of a caught signal, then launch another function that will actually do all the ending of the child-processes and prompt the user, etc.
Doing these steps will simplify your signal-handling code and reduce the chances of race-conditions or other unexpected results because of the asynchronous nature of signal arrival.
If you'd like some more information on pselect(), you there is a nice article on that here.

Resources