how to send a sigterm signal - c

In my following program i have two processes( the father and the child) both do the same thing but we want to figure out how will finish his task first. There is a randomized number of seconds both will sleep causing the challenge of who finishes first more random. Both are sending signals to the other process, when five signals have been recieved the process will then send a SIGTERM to the other process signaling that it has finished first. that other process will print that the opponent process has won. My problem is with sending that sigterm signal to the other process, ive tried kill function, singal function and dont know where is my mistake and what to try next. So any help would e=be appreciated below is my code:
//--------including--------------
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
//-------global----------------
int sig1_counter=0;
int sig2_counter=0;
//-------prototypes--------------
void catch_sigusr1(int sig_num) ;
void catch_sigusr2(int sig_num) ;
void do_son() ;
void do_dad() ;
//--------main------------------
int main (){
pid_t pid;
srand((unsigned)time(NULL));
signal(SIGUSR1, catch_sigusr1) ;
signal(SIGUSR2, catch_sigusr2) ;
pid = fork() ;
switch(pid) {
case -1 : perror("fork() failed") ;
exit(EXIT_FAILURE) ;
case 0 : do_son() ;
exit(EXIT_SUCCESS) ;
default: do_dad() ;
exit(EXIT_SUCCESS) ;
}
return EXIT_SUCCESS;
}
//-------functions-------------------
void do_son() {
int i ;
for (i=0;i<10;i++)
{
int sleep_time=rand()%4;
sleep(sleep_time);
int num=rand()%2;
if (num==0)
kill(getpid(), SIGUSR1) ;
else
kill(getpid(), SIGUSR2);
}
}
//---------------------------------
void do_dad() {
int i ;
for (i=0;i<10;i++)
{
int sleep_time=rand()%4;
sleep(sleep_time);
int num=rand()%2;
if (num==0)
kill(getpid(), SIGUSR1) ;
else
kill(getpid(), SIGUSR2);
}
}
//---------------------------------
void catch_sigusr1(int sig_num) {
signal(SIGUSR1, catch_sigusr1);
printf(" process %d got signal SIGUSR1\n", getpid()) ;
if (sig_num==SIGTERM)
{
printf("process %d win\n", getpid());
exit(EXIT_SUCCESS);
}
sig1_counter++;
if (sig1_counter==5)
{
printf(" process %d surrender\n", getpid()) ;
kill(getpid(),SIGTERM); // here we have a mistake
//signal(SIGTERM,catch_sigusr2); // !!!!!!!!!!!
exit(EXIT_SUCCESS);
}
}
//---------------------------------
void catch_sigusr2(int sig_num) {
signal(SIGUSR2, catch_sigusr2) ;
printf(" process %d got signal SIGUSR2\n", getpid()) ;
if (sig_num==SIGTERM)
{
printf("process %d win\n", getpid());
exit(EXIT_SUCCESS);
}
sig2_counter++;
if (sig2_counter==5)
{
printf(" process %d surrender\n", getpid()) ;
kill(getpid(),SIGTERM);
//signal (SIGTERM,catch_sigusr1);
exit(EXIT_SUCCESS);
}
}

Both your do_son() and do_dad() functions send signals to getpid(), which means they are signalling only themselves rather than each other.
In order to signal each other, you need:
do_dad() to send the signal to pid, the return value from fork() being the child PID; and
do_son() to send the signal to getppid(), the parent PID, noting the use of non-sexist terms in the system call :-)
In other words, something like this in your main function:
switch (pid = fork()) {
case -1:
perror("fork() failed");
break;
case 0:
do_both(getppid());
break;
default:
do_both(pid);
break;
}
The reason there's no distinct parent and child function any more is that the only difference is which PID gets signalled. Because you're passing that in as a parameter, you can combine the two functions:
void do_both(pid_t other) {
for (int i = 0; i < 10; i++) {
int sleep_time = rand() % 4;
sleep(sleep_time);
if ((rand() % 2) == 0)
kill(getpid(), SIGUSR1);
else
kill(getpid(), SIGUSR2);
}
}

Related

Can this program exit normally?

int ccount=0;
void child_handler(int sig){
int child_status;
pid_t pid = wait(&child_status);
ccount--;
}
void fork() {
pid_t pid[N];
int i, child_status;
ccount=N;
signal(SIGCHLD, child_handler);
for (i=0; i<N ; i++) {
if ((pid[i]=fork())==0) {
sleep(1); exit(0);
}
while (ccount>0) pause();
}
In this function, suppose that any one parent process receive the last SIGCHLD signal, Nth signal, between while and paust(). Then it cannot exit() because it cannot escape from while loop.
Then can I say that this program exits unnormally?

System call kill convert a child to be a zombie process

I wrote a code that creates a child with a fork(). The parent of this child should sent a SIGUSR1/2 to its CHILD and the child should answer with a SIGUSR2/1.
This is the code:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
void HDL_PSIGUSR(int sig) {
printf("Signal 0x%x received.\n\n", sig);
fflush(stdout);
}
void HDL_SSIGUSR(int sig) {
if (sig == SIGUSR1) {
printf("PID %d -> PID %d: 0x%x\n", getpid(), getppid(), SIGUSR2);
kill(getppid(), SIGUSR2);
} else if (sig == SIGUSR2) {
printf("PID %d -> PID %d: 0x%x\n", getpid(), getppid(), SIGUSR1);
kill(getppid(), SIGUSR1);
}
fflush(stdout);
}
void HDL_SSIGINT(int sig) {
kill(getppid(), SIGINT);
}
void son() {
signal(SIGUSR1, HDL_SSIGUSR);
signal(SIGUSR2, HDL_SSIGUSR);
signal(SIGINT, HDL_SSIGINT);
signal(SIGALRM, SIG_IGN);
signal(SIGCHLD, SIG_IGN);
while (true) {
pause();
}
}
int main() {
int* _buf, n, i, t, timer = 0;
pid_t pid;
char buff[1000];
printf("Number of signals to send: ");
scanf("%d", &n);
printf("Interval time: ");
scanf("%d", &t);
printf("Signals to send: ");
_buf = malloc(n * sizeof *_buf);
for (i = 0; i < n; i++) {
scanf("%d", &_buf[i]);
}
fflush(stdout);
if (pid = fork()) {
signal(SIGUSR1, HDL_PSIGUSR);
signal(SIGUSR2, HDL_PSIGUSR);
i = 0;
while (true) {
i %= n;
//sprintf(buff, "kill -USR1 %d", pid);
//system(buff);
kill(pid, SIGUSR1);
sleep(t);
}
} else {
son();
exit(0);
}
waitpid(pid, (int*)0, 0);
return 0;
}
The problem is that if I use the kill() system call, the child process become a zombie process. Instead, if I use the system() system call and calling from there the command kill on CHILD PID, it works! Why?
Thank you guys! The problem was as said by #Jonathan Leffler and #Shawn. It can be solved with a sleep(1); in the parent process before starting to send signals. I modified my code as shown here:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
bool startProg = false;
void HDL_PSIGUSR(int sig) {
if (!startProg) {
startProg = true;
return;
}
printf("Received signal 0x%x\n", sig);
fflush(stdout);
}
void HDL_SSIGUSR(int sig) {
kill(getppid(), (sig == SIGUSR1) ? SIGUSR2 : SIGUSR1);
}
void HDL_SSIGINT(int sig) {
kill(getppid(), SIGINT);
}
void son() {
signal(SIGUSR1, HDL_SSIGUSR);
signal(SIGUSR2, HDL_SSIGUSR);
signal(SIGINT, HDL_SSIGINT);
signal(SIGALRM, SIG_IGN);
signal(SIGCHLD, SIG_IGN);
kill(getppid(), SIGUSR1);
while (true) {
pause();
}
}
int main() {
int* _buf, n, i, t;
pid_t pid;
printf("Number of signals to send: ");
scanf("%d", &n);
printf("Interval time: ");
scanf("%d", &t);
printf("Signals to send: ");
_buf = malloc(n * sizeof *_buf);
for (i = 0; i < n; i++) {
scanf("%d", &_buf[i]);
}
fflush(stdout);
if (pid = fork()) {
signal(SIGUSR1, HDL_PSIGUSR);
signal(SIGUSR2, HDL_PSIGUSR);
while (!startProg) {
pause();
}
i = 0;
while (true) {
i %= n;
kill(pid, _buf[i++]);
pause();
sleep(t);
}
} else {
son();
exit(0);
}
waitpid(pid, (int*)0, 0);
return 0;
}

C synchronize processes using signal

Okay so I am trying to teach myself on how to do signalling, and I came across a hiccup and I can't figure out what I'm doing wrong. What is going on right now is: it is executing the parent then goes to child and then back to parent.. It's not doing what I want it to do which is execute the parent (which the user defines the amount of time it runs) then kills it then go to child and run itself at the same amount of time.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h> // for wait
#include <sys/wait.h> // for wait
void action(int);
void action(int dummy){
sleep(1);
printf("Switching\n");
}
int main(int argc, char *argv[]){
pid_t pid;
int m = atoi(argv[1]), i = 0, x = 0;
if((pid=fork())>0){//parent
sleep(1);
while(i < m){
printf("hello %d\n", x);
x++;
kill(pid, SIGUSR1);
signal(SIGUSR1, action);
pause();
i++;
}
}
else
while(i < m){//child
//waitpid(getppid(), &status, 0); // wait for parent
signal(SIGUSR1, action);
pause();
printf("hi%d\n", x);
x++;
kill(getppid(), SIGUSR1);
i++;
}
}
What I want it to do is:
hello 0
hello 1
hello 2
hello 3
hello 4
Switching
hi 0
hi 1
hi 2
hi 3
hi 4
Any help is much appreciated!
You've got most of the pieces, they just need to be reordered a little bit.
install the signal handler in both processes before using kill
the parent should finish printing before signaling the child
the child can signal back after its done printing
void action(int dummy)
{
sleep(1);
printf("Switching\n");
}
int main(int argc, char *argv[])
{
int m = 3;
if (argc == 2)
m = atoi(argv[1]);
pid_t pid = fork(); // create the child process
signal(SIGUSR1, action); // set up the signal handler for both parent and child
if ( pid > 0 ) // the parent
{
for ( int i = 0; i < m; i++ )
{
sleep(1);
printf("hello %d\n", i);
}
kill( pid, SIGUSR1 ); // signal the child
pause(); // wait for the child to signal back
printf("All done\n");
}
else // the child
{
pause(); // wait for the signal from the parent
for ( int i = 0; i < m; i++ )
{
sleep(1);
printf("hi %d\n", i);
}
kill(getppid(), SIGUSR1); // signal the parent
}
}

Trouble sending and handling signals with children processes in C

The parent process forks two children, each replace SIGUSR1 and SIGUSR2 signal respectively.
The parent process replace SIGINT signal, on catching it, send SIGUSR1 and SIGUSR2 to its children respectively.
The expected output when Ctrl-C is pressed should be:
Ctrl+C is pressed。
received SIGUSR1 signal
received SIGUSR2 signal
But on Ctrl-C I've got
Ctrl+C is pressed。
I have no idea why sig_handler_1 and sig_handler_2 are not excuted.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
void fun_ctrl_c(int);
void sig_handler_1(int);
void sig_handler_2(int);
pid_t pid1;
pid_t pid2;
int status;
int main() {
pid1 = fork();
if (pid1 == 0) { // child 1
// avoid to be killed
(void) signal(SIGINT, SIG_IGN);
// replace SIGUSR1
(void) signal(SIGUSR1, sig_handler_1);
raise(SIGSTOP);
} else {
pid2 = fork();
if (pid2 == 0) { // child 2
// avoid to be killed
(void) signal(SIGINT, SIG_IGN);
// replace SIGUSR2
(void) signal(SIGUSR2, sig_handler_2);
raise(SIGSTOP);
} else { // parent
(void) signal(SIGINT, fun_ctrl_c);
waitpid(-1, &status, 0);
}
}
return 0;
}
void fun_ctrl_c(int)
{
printf("Ctrl+C is pressed。\n");
kill(pid1 ,SIGUSR1);
kill(pid2 ,SIGUSR2);
(void) signal(SIGINT, SIG_DFL);
}
void sig_handler_1(int)
{
printf("received SIGUSR1 signal\n");
}
void sig_handler_2(int)
{
printf("received SIGUSR2 signal\n");
}
Your problem is that you do raise(SIGSTOP); in the child processes, so they're stopped and cannot respond to signals at all.
Replace that with pause(); — the code then works.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
void fun_ctrl_c(int);
void sig_handler_1(int);
void sig_handler_2(int);
pid_t pid1;
pid_t pid2;
int main(void)
{
pid1 = fork();
if (pid1 == 0)
{
(void) signal(SIGINT, SIG_IGN);
(void) signal(SIGUSR1, sig_handler_1);
pause();
printf("PID %d exiting\n", (int)getpid());
}
else if ((pid2 = fork()) == 0)
{
(void) signal(SIGINT, SIG_IGN);
(void) signal(SIGUSR2, sig_handler_2);
pause();
printf("PID %d exiting\n", (int)getpid());
}
else
{
(void) signal(SIGINT, fun_ctrl_c);
int status;
int pid;
printf("Interrupt me!\n");
while ((pid = waitpid(-1, &status, 0)) != -1)
printf("Child %d exited with status 0x%.4X\n", pid, status);
printf("Parent %d exiting\n", (int)getpid());
}
return 0;
}
void fun_ctrl_c(int signum)
{
printf("Ctrl+C is pressed。Received SIGINT (%d) signal\n", signum);
kill(pid1, SIGUSR1);
kill(pid2, SIGUSR2);
(void) signal(SIGINT, SIG_DFL);
}
void sig_handler_1(int signum)
{
printf("received SIGUSR1 (%d) signal\n", signum);
}
void sig_handler_2(int signum)
{
printf("received SIGUSR2 (%d) signal\n", signum);
}
Sample run (I called the program sigintusr12):
$ ./sigintusr12
Interrupt me!
^CCtrl+C is pressed。Received SIGINT (2) signal
received SIGUSR2 (31) signal
received SIGUSR1 (30) signal
PID 31184 exiting
PID 31183 exiting
Child 31184 exited with status 0x0000
Child 31183 exited with status 0x0000
Parent 31182 exiting
$
Note that you're not strictly supposed to use printf() (and many other functions, especially those that might need to allocate memory) inside a signal handler. It'll work OK here, but it is not good practice. See How to avoid using printf() in a signal handler? for more information.

how to not block parent with waitpid

I need to create a program that creates n number of processes and displays information. When each process ends, I am to print it's PID and the exit status. The way I am doing it, the parent program waits to create the next process until the current one ends. I need it so that it keeps creating the child processes and just displays the exit information when ever one process ends without blocking the parent from continuing. I can;t figure out where to put my wait to ensure this. Below is my code:
int main (int argc, char *argv[])
{
if (argc < 2)
{
printf("\n\nUsage: %s <enter a number (12 or less)>\n\n", argv[0]);
exit (-1);
}
else
{
int *processNum = (int *)malloc(sizeof(12));
int processNumTemp;
processNumTemp = atoi(argv[1]);
processNum = &processNumTemp;
if(*processNum > 12 || *processNum < 1)
{
printf("\n\nUsage: %s <enter a number (12 or lrss)>\n\n", argv[0]);
}
else
{
parentInfo(processNum);
createChildProcess(processNum);
}
}
return 0;
}
//Name: parentInfo
//Description: Displays information about the parent process
//Parameters: processNum - stores the number of child processes to create
// (entered at the command line).
//Return: none
void parentInfo(int *processNum)
{
printf("Parent process ID: %d\n", getppid());
printf("Number of processes to create: %d\n", *processNum);
}
//Name: createChildProcess
//Description: Creates n number of child processes.
// For each child process, it says its a child process and it
// displays its PID.
// After each child process closes, the parent displays info.
//Parameters: processNum - stores the number of child processes to create
// (entered at the command line).
//Return: none
void createChildProcess(int *processNum)
{
int i;
int childStatus;
pid_t childpid;
/*The for loop will create n number of processes based on the value of processNum.*/
for(i = 1; i <= *processNum; i++)
childpid = fork();
//Executes if fork didn't work
if(childpid < 0)
{
perror("fork");
exit(1);
}
//Executes if the fork worked
else if( childpid == 0)
{
int pid = getpid();
//Prints a message and the child processe's PID
printf("\nHello I am a child process.\n");
printf("My PID is %d. \n", getpid());
for(int x = 1; x <= pid; x ++);
exit(15);
}
}
//Executes after the child process has ended
//Checks the child process's exit status
waitpid(childpid, &childStatus, WUNTRACED);
printf("\nPID of the child process that was just created: %d.\n", childpid);
if(WIFEXITED(childStatus))
{
printf("PID %d exited normally. Exit number: %d\n", childpid, WEXITSTATUS(childStatus));
}
else if(WIFSTOPPED(childStatus))
{
printf("PID %d was stopped by %d\n", childpid, WSTOPSIG(childStatus));
}
else if(WIFSIGNALED(childStatus))
{
printf("PID %d exited due to signal %d\n.", childpid, WTERMSIG(childStatus));
}
else
{
perror("waitpid");
}
}
Before fork code
signal(SIGCHLD, childHandler);
In childHandler put your waitpid code.
void childHandler(int signum)
{
pid_t childpid;
int childstatus;
while ((childpid = waitpid( -1, &childstatus, WNOHANG)) > 0)
{
if (WIFEXITED(childStatus))
{
printf("PID %d exited normally. Exit number: %d\n", childpid, WEXITSTATUS(childStatus));
}
else
if (WIFSTOPPED(childStatus))
{
printf("PID %d was stopped by %d\n", childpid, WSTOPSIG(childStatus));
}
else
if (WIFSIGNALED(childStatus))
{
printf("PID %d exited due to signal %d\n.", childpid, WTERMSIG(childStatus));
}
else
{
perror("waitpid");
}
}
}
}
You should not use async-unsafe calls like printf inside a signal handler so alter your code to save the status in a global or heap allocated array - you know the size to create from processNum - and print the status info outside the handler.
Also, as currently structured, your parent could end before reaping all the children. Add a counter for the children so that you wait on all of them before the parent exits.
Look into signal SIGCHLD. If you have it blocked, you must unblock it or might instead explicitly check for it.
The purpose of wait is to, well, wait, so the way to solve your problem is to first create all the children, then start waiting for them to terminate.
Here is a program which does that:
// fork
#include <unistd.h>
// wait
#include <sys/types.h>
#include <sys/wait.h>
// exit
#include <stdlib.h>
//printf
#include <stdio.h>
void child( int id)
{
int seed= id;
int x= rand_r( &seed) % 10;
sleep( x);
exit( x);
}
int main( int argc, char *argv[])
{
const int n= 5;
int i;
printf( "creating %d children.\n", n);
for ( i= 0; i < n; ++i) {
pid_t pid= fork();
if ( !pid)
child( i); // does not return
else
printf( "child [0x%x] created.\n", pid);
}
// all the children are created now
// now we wait for them to terminate
printf( "waiting for children to terminate.\n", n);
for ( i= 0; i < n; ++i) {
int result;
pid_t pid= wait( &result);
printf( "child [0x%x] terminated with result [%u].\n", pid, WEXITSTATUS( result));
}
puts( "all children terminated.");
}

Resources