Using signals in a child process - c

I want to create a simple program that uses fork and creates a child process which with the use of pause is waiting. I want this child process to start after it gets a specific signal from father process. Code I've written:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
pid_t c = fork();
if (c == 0) {
pause();
printf("signal was given");
}
if (c > 0)
kill(c, SIGINT);
return 0;
}
I think kill gives a specific signal to a process with pid c(child) and I thought that pause just waits for a signal to unpause that process. However in this case running this program has no results. I have also tried adding a signal catching function to the child using signal(SIGINT, handler) and creating a handler function that prints the desired result but it is still not working. Any ideas?

If you send SIGINT, whose default disposition is to kill the process, to a process that neither blocks it nor handles it, the process will die.
If you want the signal to interrupt blocking calls like pause(), it needs to have a handler.
But simply installing a handler introduces race conditions:
if (c == 0 ){
//< if the signal arrives here the child dies
signal(SIGINT, handler);
//< if the signal arrives here then nothing happens except the handler is run
pause(); //< if the handler arrives here then pause gets interrupted
printf("signal was given\n");
exit(0);
}
To eliminate the race conditions, you need to
block the signal in the parent so that the child starts with the signal blocked
install the handler in the child
unblock the signal and pause() in one atomic step
To achieve 3. in one step, you need sigsuspend() instead of pause().
#include <stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<signal.h>
void handler(int Sig){}
int main()
{
sigset_t sigint, oldmask; sigemptyset(&sigint); sigaddset(&sigint, SIGINT);
sigprocmask(SIG_BLOCK, &sigint, &oldmask);
pid_t c=fork();
if(0>c) return perror(0),1;
if (c==0){
signal(SIGINT, handler);
sigdelset(&oldmask,SIGINT); /*in (the unlikely) case the process started with SIGINT blocked*/
sigsuspend(&oldmask);
printf("signal was given\n");
exit(0);
}
kill(c,SIGINT);
wait(0);
return 0;
}
Alternatively, you can use sigwait() and drop the need for a handler altogether:
#include <stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<signal.h>
int main()
{
sigset_t sigint, oldmask; sigemptyset(&sigint); sigaddset(&sigint, SIGINT);
sigprocmask(SIG_BLOCK, &sigint, &oldmask);
pid_t c=fork();
if(0>c) return perror(0),1;
if (c==0){
int sig; sigwait(&sigint,&sig);
printf("signal was given\n");
exit(0);
}
kill(c,SIGINT);
wait(0);
return 0;
}

You have two issues:
The child process is getting a signal before it calls pause().
SIGINT by default would kill a process so printf will never be executed.
Try this:
void handler(int signum)
{
//nothing here
}
int main()
{
pid_t c = fork();
if (c == 0) {
signal(SIGINT, handler);
pause();
printf("signal was given");
}
if (c > 0) {
sleep(1); // <-- give the child process some time to pause()
kill(c, SIGINT);
}
return 0;
}

Related

Ubuntu C How to stop child process using SIGTSTP then resume it using SIGCONT?

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int pid = 0;
// some very time-consuming function
void childLabor() {
for (long long i=1;i<=10000000000;i++) {
//printf("i'm printing\n");
fflush(stdout);
}
}
// stop the process who calls this
void stopYourself() {
// TODO
}
void childReceiveStop() {
signal(SIGTSTP, childReceiveStop);
printf("I have important things to do first before stopping\n");
fflush(stdout);
// do important things
printf("I stop myself now\n");
fflush(stdout);
stopYourself();
}
void childReceiveContinue() {
signal(SIGCONT, childReceiveContinue);
}
int main()
{
pid = fork();
if (pid==0) {
signal(SIGTSTP, childReceiveStop);
signal(SIGCONT, childReceiveContinue);
stopYourself(); // wait until parent sends SIGCONT
childLabor();
}
else {
// start/stop child every 2 second
kill(pid,SIGCONT);
for (int i=1; i<=100; i++) {
printf("sending signal stop\n");
fflush(stdout);
kill(pid, SIGTSTP);
sleep(3);
printf("sending signal start\n");
kill(pid, SIGCONT);
sleep(1);
}
}
return 0;
}
Basically what I want to do in this example is let the child print for 3 seconds, then stop it, then let it print again, ... When the child receives SIGTSTP, it should stop. And when it receives SIGCONT, it should continue.
However, with or without handler, when the child process receives the SIGTSTP signal, it does not stop at all.
How can I fix this problem? Thank you.
SIGTSTP for sending stop signal from the terminal to a process. In your case, you ant to send stop signal from parent process. So you'd need SIGSTOP instead of SIGTSTP. So replace SIGTSTP with SIGSTOP.
Also SIGSTOP can't caught. So you don't need to have handlers for SIGSTOP.

Using signals in c

I was writing a simple program in c where via fork i create i child process:
#include <stdio.h>
#include <stdlib.h>
#include<signal.h>
#include<sys/types.h>
int handler(){
}
int main(int argc, char **argv)
{
pid_t c=fork();
if(c>0){
sleep(1);
printf("f:pid is %d \n",getpid());
kill(c,SIGINT);
wait(NULL);
}
if(c==0){
pause();
signal(SIGINT,handler);
printf("child:pid is %d \n",getpid());
}
}
The problem is that the child prints nothing. I thought that pause just waits for a signal to unpause the process and i can't understand why the print never happens.Any ideas?
You need to set up the handler before you pause. Otherwise, pause() will be interrupted by the signal, then the default action of the signal will be taken, which is to terminate the process. It will never add the handler because the process is killed first.
if(c==0){
signal(SIGINT,handler);
pause();
printf("child:pid is %d \n",getpid());
}

Can not register handler for SIGTRAP

I am trying to register a handler for the SIGTRAP caused by calling int3 in child, but it does not work. Changing SIGTRAP to SIGCHLD works.
#include <signal.h>
#include <wait.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
void child();
void parent(pid_t pid);
void sigtrap_handler(int sig);
int main(){
pid_t pid = fork();
if(pid == 0){
child();
} else {
parent(pid);
}
}
void child(){
sleep(1);
asm("int3");
exit(EXIT_SUCCESS);
}
void parent(pid_t pid){
signal(SIGTRAP, sigtrap_handler);
int status;
do{
waitpid(pid, &status, WUNTRACED | WCONTINUED);
} while(!WIFEXITED(status) && !WIFSIGNALED(status));
exit(EXIT_SUCCESS);
}
void sigtrap_handler(int sig){
printf("Process %d received sigtrap %d.\n", getpid(), sig);
}
Only the parent process has registered a signal handler for SIGTRAP but not the child process. So when you raise SIGTRAP in child process, the parent process process is not aware of it.
SIGCHLD works (i.e. received by parent) because when the child process terminates (or stops), the signal SIGCHLD is sent to the parent process. But in case of SIGTRAP (or any other signal), it's not sent to the parent process. SIGCHLD is special in the sense, it's sent by default to the parent process on termination whereas other signals are not.
If you add a handler in child process, you'll see the handler getting invoked:
void child(){
signal(SIGTRAP, sigtrap_handler);
sleep(1);
asm("int3");
exit(EXIT_SUCCESS);
}
By the way, printf() is not an async-signal-safe function, so you can't safely call it in a signal handler.

How to wait for the children processes to send signals?

#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
void handler(int signumber)
{
return;
}
int main()
{
int i, pid;
int children_count = 5;
int arr_childprocesses[5];
int parent_pid = getpid();
for(i=0;i<children_count;i++)
{
pid = fork();
if(pid == -1)
{
perror("Err");
exit(EXIT_FAILURE);
}
if(pid == 0) break;
arr_childprocesses[i] = pid;
}
if (pid == 0) // children
{
kill(parent_pid,SIGUSR1);
printf("Child(%d) sig sent. Waiting 5s...\n",getpid());
sleep(5);
printf("Child(%d) terminated.\n",getpid());
}
else // parent
{
signal(SIGUSR1,handler);
for(i=0;i<children_count;++i)
{
waitpid(arr_childprocesses[i],NULL,0);
printf("Parent: Signal received.\n");
}
printf("Parent(%d) signals received. Waiting 3s...\n",getpid());
sleep(3);
printf("Parent(%d) terminated.\n",getpid());
}
exit(EXIT_SUCCESS);
}
I want to wait until all the children send me a signal. Then do some work with the children and with the parent too. But the program stops until all the children terminate. How should I do this?
Result:
Update 1: full code plus result included
You are probably facing a race here.
The parent receives the SIGUSR1 before its handler for this signal had been set up. As the default behaviour on receiving a SIGUSR1 is to end, the parent dies.
You want to setup the signal handler inside the parent before forking off the child.
(If from the programs design it is unacceptbale for the child to have SIGUSR1 signal handler set up, just call signal(SIGUSR1, SIG_DFL) as the 1st statement inside the child to deinstall this handler.)
To prove this theory you might like to temporarily add a sleep(1); inside the child just before the call to kill().
As a hint to fulfill your assignment:
Have a look at sigaction() as it provides a much more powerful interface to signalling then the function signal() does. Especially read about the SA_SIGINFO flag as it enables passing a siginfo_t typed variable to your signal handler. This latter variable carries info on who (identified by PID) sent the signal, which is the key to your solution.

Why the child process doesn't reply to the signal sent from parent process?

I'm learning the signal of inter process communication, I made the very simple test code below:
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
void sighup();
void sigint();
void sigquit();
int main(int argc, const char *argv[])
{
int child_pid;
if((child_pid = fork()) < 0) exit (1);
if(child_pid == 0) {
sleep(2);
signal(SIGHUP, sighup);
signal(SIGINT, sigint);
signal(SIGQUIT, sigquit);
puts("this is the end of the child process");
} else {
printf("\n Parent: sending SIGHUP signal to child\n\n");
kill(child_pid, SIGHUP);
printf("\n Parent: sending SIGINT signal to child\n\n");
kill(child_pid, SIGINT);
printf("\n Parent: sending SIGQUIT signal to child\n\n");
kill(child_pid, SIGQUIT);
}
}
void sighup() {
signal(SIGHUP, sighup);
printf("CHILD: I have received a SIGHUP\n");
}
void sigint() {
signal(SIGINT, sigint);
printf("CHILD: I have received a SIGINT\n");
}
void sigquit() {
sleep(2);
printf("CHILD: My parent process has killed me!!");
printf("CHILD: cleaning up...\n");
exit(0);
}
It seems like the child process doesn't do anything, even doesn't print the end of the process string. any idea?
Your signal handlers are not being invoked in the child because of a race condition. The parent thread sends the child thread a signal before the child calls signal() that overrides the signal handling behavior.
In this case, the child receives a SIGINT and performs its default behavior, which is to terminate. Thus the child terminates before executing the statements after sleep(2).

Resources