Using signals in c - 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());
}

Related

If the subprocess does not call the system call, will the signal sent by kill still take effect?

If the subprocess does not call the system call, will the signal sent by kill still take effect?
It worked. But I want to know when did the subprocess enter the kernel mode.
Code as follows.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
int main(int argc, char const *argv[])
{
int pid;
if ((pid = fork()) == 0)
{
while (1)
continue;
exit(0);
}
sleep(3);
kill(pid, SIGINT);
int wid, status;
while ((wid = wait(&status)) != -1)
{
printf("child %d: exited with ", wid);
if (WIFEXITED(status))
printf("%d\n", WEXITSTATUS(status));
if (WIFSIGNALED(status))
printf("%d\n", WTERMSIG(status));
}
return 0;
}
Yes, processes that do not make system calls can still receive signals. You can easily test this by writing an infinite loop program, running it, then pressing Ctrl-C, or using the kill command from another terminal window.

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 a child process

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;
}

How to terminate a child process which is running another program by doing exec

I'm doing fork in my main program,and doing exec in the child process which will run another program. Now i want to terminate the child(i.e., the program invoked by exec) and return back to the main program(or parent program). how could i achieve this.. I tried with ctrl+c but its killing parent process and child also.please help me.
/*This is main.c*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/wait.h>
void sig_int(void);
void sig_term(void);
pid_t pid,ppid;
int main(char argc,char **argv){
int n;
char ch;
printf("***********Application to start or stop services**********\n");
do
{
printf("Enter 1 to start service no.1\n");
printf("Enter 2 to start service no.2\n");
printf("Enter 3 to start service no.3\n");
scanf("%d",&n);
if(fork() == 0)
{
switch(n)
{
case 1: printf("starting service no. 1..\n");
printf("checking whether the given service is already running...\n");
// system("./det.sh ./test")
pid = getpid();
printf("child process pid = %d\n",pid);
// signal(SIGINT,(void *)sig_int);
// signal(SIGTERM,(void *)sig_term);
//execl("/var/vR_main","vR_main",argv[1],argv[2],argv[3],argv[4],NULL);
execl("./test","test",0,0);//will run test.c
break;
case 2: printf("starting service no. 2..\n");
break;
case 3: printf("starting service no. 3..\n");
break;
}
}
else
{
int status;
wait(&status);
if (WIFEXITED(status))
printf("CHILD exited with %d\n", WEXITSTATUS(status));
if (WIFSIGNALED(status))
printf("signaled by %d\n", WTERMSIG(status));
if (WIFSTOPPED(status))
printf("stopped by %d\n", WSTOPSIG(status));
// sleep(2);
ppid = getpid();
printf("%d\n",ppid);
// wait();
printf("\nDo you want to continue...y/n:");
scanf(" %c",&ch);
}
}while(ch == 'y');
return 0;
}
void sig_int(void)
{
printf("caught signal\n");
kill(pid,SIGKILL);
// signal(SIGINT,SIG_DFL);
// exit(0);
}
void sig_term(void)
{
printf("killing the process\n");
signal(SIGINT,SIG_DFL);
// exit(0);
}
/*This is test.c*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
void sig_int(void);
void sig_term(void);
pid_t pid;
int main()
{
// int a=10,b=40,c=50,max;
pid = getpid();
printf("exec pid = %d\n",pid);
while (1)
{
signal(SIGINT,(void *)sig_int);
signal(SIGTERM,(void *)sig_term);
}
// max=a>b?a>c?a:c:b>c?b:c;
// printf("%d\n",max);
}
void sig_int(void)
{
printf("caught signal\n");
// signal(SIGINT,SIG_DFL);
kill(pid,SIGKILL);
// exit(0);
}
void sig_term(void)
{
printf("killing the process\n");
signal(SIGINT,SIG_DFL);
// exit(0);
}
Now I want to kill "test application" (invoked by exec),and return to the parent process or the "else block" to continue the program.
You need to do the following:
Do a kill(pid, SIGTERM) first - this gives the child process an opportunity to terminate gracefully
Wait a period of time (use sleep). The period of time depends on the time the child process takes to close down gracefully.
Use waitpid(pid, &status, WNOHANG) checking the return value. If the process has not aborted do step 4
Do a kill(pid, SIGKILL) then harvest the zombie by doing waitpid(pid, &status, 0).
These steps ensure that you give the child process to have a signal handler to close down and also ensures that you have no zombie processes.
Either in or outside your program, it is possible to use kill. By including <signal.h>, you can kill a process with a given PID (use the fork return value to do this).
#include <signal.h>
int pid;
switch (pid = fork())
{
case -1:
/* some stuff */
break;
case 0:
/* some stuff */
break;
default:
/* some stuff */
kill(pid, SIGTERM);
}
It is also possible to use kill command in the shell. To find the PID of your child process, you can run ps command.
man kill
The kill() function shall send a signal to a process or a group of processes specified by pid. The signal to be sent is specified by sig and is either one from the list given in <signal.h> or 0. If sig is 0 (the null signal), error checking is performed but no signal is actually sent. The null signal can be used to check the validity of pid.
POSIX defines the kill(2) system call for this:
kill(pid, SIGKILL);

Parent process doesn't complete after child is terminated in C

I'm having trouble with a process forking exercise. I want to fork a child process and have it hang after announcing it has been forked, and wait for a signal to terminate, after which the parent process must announce it is terminating and then exit.
I can get the processes forked and have the parent wait for the hanging child to be killed by the signal, but it seems to kill the parent as well. I tried killing the child process specifically by its PID, but with no success.
Thanks for any help!
Code:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
void catchInt (int signum)
{
printf("\nMy sincerest apologies, master\n");
/*kill(0, SIGINT);*/
exit(0);
}
void ignoreInt (int signum)
{
wait(NULL);
}
int main () {
pid_t pid;
/* fork process */
pid = fork();
if (pid < 0) /* error handler */
{
fprintf(stderr, "Fork Failed");
exit(-1);
}
else if (pid == 0) /* child */
{
printf("Child reporting in\n");
signal(SIGINT, catchInt);
for ( ;; )
pause();
}
else /* parent */
{
/* parent will wait for the child to complete */
signal(SIGINT, ignoreInt);
wait(NULL);
printf("You're welcome\n");
exit(0);
}
}
Even assuming you fix the code so it compiles (you've not defined tempPID), there are problems:
You set the child to go to sleep until a signal arrives.
You set the parent to wait until the child dies.
So, you have a state where neither process is going to do anything more.
You probably need the parent to send a signal to the child:
kill(pid, SIGINT);
It is not clear that you need the parent to set a signal handler.
You probably want the child to set a signal handler.
You probably don't want the infinite loop in the child.
Oh, and void main() is incorrect - int main() or int main(void) or int main(int argc, char **argv) are the approved declarations for main().
And it is tidier if you return a value (0) from main(). The C99 standard does permit you to drop off the end of main() and will treat that as returning zero, but only if the function is properly declared as returning an int.
The header for wait() and relatives in POSIX is <sys/wait.h>.
And, because I'm a sucker, here's code that compiles and might even do what you want:
#include <stdio.h>
#include <signal.h>
#include <unistd.h> /* getpid() */
#include <stdlib.h>
#include <sys/wait.h>
void catchInt(int signum)
{
printf("Child's PID is %d\n", (int)getpid());
printf("My sincerest apologies, master\n");
exit(1);
}
int main()
{
pid_t pid = fork();
if (pid < 0) /* error handler */
{
fprintf(stderr, "Fork Failed");
exit(-1);
}
else if (pid == 0) /* child */
{
printf("Child reporting in\n");
signal(SIGINT, catchInt);
pause();
}
else /* parent */
{
sleep(1);
kill(pid, SIGINT);
wait(NULL);
printf("You're welcome\n");
}
return(0);
}
Just figured out what I was doing wrong, I should have realized SIGINT is sent to every process, and so the parent was simply being sent an unhandled SIGINT, causing it to exit. Thanks for all the help (my apologies on the sloppy coding, I really shouldn't wait until the program is completed to clean that up), the code's been edited above and works as intended.
Thanks again.

Resources