How to fork the youngest process - c

Let's say that whenever main program receives SIGINT signal, the youngest (i.e. the lastly forked) process is forked. In other words:
p1 SIGINT
p1->p2 SIGINT
p1->p2->p3
and so on
My problem is that I don't know how to tell the grand-grand-...-children to fork.

My problem is that I don't know how to tell the
grand-grand-...-children to fork.
Parent should install SIGINT handler using SA_SIGINFO flag.
When a grandchild is created it should send signal to parent(p1).
P1 through its signal handler(si_pid field of handler's siginfo_t argument) reads pid of grandchild.
When Parent receives SIGINT then it send signal to grand child.
When grand child receives signal it should fork a new child.
Repeat from 2-5 for newly created child.
One more approach:
Let parent poll for SIGINT signal.
When SIGINT received by parent, create child.
Mask SIGINT in parents context and wait for SIGINT in child context.
repeat step 1 to 3 in childs context.
Example:
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#define CHILD_NEEDED 10
static volatile sig_atomic_t got_sigint;
static volatile sig_atomic_t child_created;
void sigint_handler(int sig, siginfo_t *f, void *main_context) {
ucontext_t *uc = main_context;
// to mask SIGINT while returning from handler.
sigaddset(&uc->uc_sigmask, SIGINT);
++child_created;
got_sigint = 1;
}
void create_child(void)
{
pid_t pid = fork();
sigset_t set;
sigemptyset(&set);
if (-1 == pid) {
perror("Fork failed\n");
exit(1);
} else if (0 == pid) {
// Exit if expected child are created
if (child_created == CHILD_NEEDED) {
printf("New Child\nTotal Child: %d\n", child_created);
exit(0);
}
got_sigint = 0;
// As parent mask is copied to child so clear child mask set.
sigprocmask(SIG_SETMASK, &set, NULL);
printf("New Child\n Please send signal to create child\n");
while (!got_sigint);
create_child();
}
}
int main(int argc, const char *argv[]) {
struct sigaction act = {.sa_sigaction = sigint_handler, .sa_mask = 0, .sa_flags = SA_SIGINFO};
sigset_t mask;
int status;
parent = getpid();
sigaction(SIGINT, &act, NULL);
printf("parent\n Please send signal to create child\n");
while (!got_sigint);
// As we have returned from signal so SIGINT will be mask for parent.
create_child();
// parent will wait here.
wait(&status);
exit(0);
}

All your processes will receive the SIGINT signal, so the main process doesn't need to tell the youngest process to fork; just let the process that hasn't forked yet fork, and all other processes do nothing.

Related

Processes synchronization using signals in c

I`m writing the program in which parent and child processes synchronize their actions with signals.
So, as result, I need a repeated cycle:
The parent process should send signal SIGUSR1 to a group of the child processes.
After getting the signal from the parent, the child processes should send signal SIGUSR2 to the parent.
After getting the signals from all child processes, the parent process should sleep for 1 s. But if the parent process gets signal SIGTERM from the child, the parent should send SIGTERM to all child processes and they should stop working.
I`ve already written how to create the group of child processes and send to them signal SIGUSR1. But I don't know how to send signal SIGUSR2 from child processes to the parent process and verify if all child processes sent a signal and if the sent signals contain SIGTERM signal.
Please, help me!
##include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
static volatile sig_atomic_t got_signal;
void sig_child(int signo){
printf("Signal caught.");
}
void handler(int sig)
{
printf("caught signal: %d\n", getpid());
got_signal = 1;
signal(SIGUSR2, sig_child);
printf("sent signal: %d\n", getpid());
kill(getppid(), SIGUSR2);
}
int main() {
pid_t child;
pid_t children[3];
int status;
int i = 0;
signal(SIGUSR1, handler);
for (; i < 3; i++) {
switch (child = fork()) {
case -1:
perror("could not create child: ");
break;
case 0:
printf("child: %d\n", getpid());
while (!got_signal);
_exit(0);
default:
children[i] = child;
/*put all children in process group of eldest child*/
setpgid(child, children[0]);
}
}
sleep(1);
/* send signal to all child by sending signal to process group of eldest child */
kill(-children[0], SIGUSR1);
int n = 0;
while (n < 3) {
waitpid(children[n], &status, 0);
n++;
}
exit(0);
}

C Signal Handler professor example explanation

My QNX class notes has this example, I cant seem to figure out how my prof came up with that output. Can anyone explain this to me thoroughly?
When this program runs the parent process has a PID of 1234 and the child process has 5678.
Output
5678: counter = 0
1234: counter = 10
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
/*
* getpid() - returns the current processes pid.
* getppid() - returns the parent processes pid.
*/
int counter = 0;
void signal_handler(int signo)
{
counter++;
}
int main(int argc, char *argv[]) {
int i = 0;
int rv;
struct sigaction sa;
sa.sa_handler = signal_handler;
//queue signals.
sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);
sigaction(SIGUSR1, &sa, NULL);
switch(fork())
{
case 0:
for(i = 0; i < 10; i++)
{
kill(getppid(), SIGUSR1);
}
break;
default:
wait(&rv);
break;
}
printf("%d: counter = %d\n", getpid(), counter);
return 0;
}
The fork creates a child process with its own copy of counter.
The kill, called by the child process, is sending a SIGUSR1 to the parent process because it is using getppid() to get the pid.
The parent process is either blocked in the wait, or somewhere between the fork and the wait. For each SIGUSR1 sent by the child, the parent will jump into the signal handler, increment its copy of counter, and return to whatever it was doing.
In general, wait can return with an EINTR error if a signal is handled while it is waiting. Setting SA_RESTART in sa.sa_flags ensures that system call will be restarted, but here it assumes that the wait will not be interrupted by the signal (does QNX guarantee this?).
The child's copy of counter is not affected. The wait causes the parent to block until the child has exited. The child thus prints its value of counter, which is 0, and exits, the parent wakes from the wait and prints its value of counter, which is 10.

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.

multi threaded program not behaving as expected for signal handling

I have written C code to have understanding of how pthreads behave in face of receiving a signal. For this, I have setup a signal handler using sigaction, done fork to create child process, setup number of pthreads from child process, and sent a signal from parent process to child process. I am printing id of thread from signal handler.
I had read that when a process has number of threads, then the signal will be handled by any of the threads and the behaviour is undefined (that is not sure of which thread will handle the signal). But what I have observed in my program is that every time the signal handler is printing id of only one thread and this seems to be id of parent thread. I was expecting that random id of any of the threads will be printed every time the signal is sent, but this is not happening. Can someone please throw some light on this?
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <errno.h>
pthread_t tid[5];
void* doSomeThing2(void *arg)
{
int i;
printf("In thread handler.my pid is %x\n",pthread_self());
i=5;
while(i--)
{
sleep(1);
}
return NULL;
}
static void my_completion_handler( int signo, siginfo_t *info, void *context )
{
int ret;
printf("In completion handler.my pid is %x\n",pthread_self());
return;
}
int main()
{
int ret,err;
struct sigaction sig_act;
pid_t mypid;
int i,j;
/* Setup the signal handler */
sigemptyset(&sig_act.sa_mask);
sig_act.sa_flags = SA_SIGINFO;
sig_act.sa_sigaction = my_completion_handler;
/* Map the Signal to the Signal Handler */
ret = sigaction( SIGTERM, &sig_act, NULL );
mypid=fork();
switch(mypid) {
case -1:
printf("fork failed\n");
return -1;
case 0:
/* child process */
printf("In child process,my pid is %x\n",pthread_self());
for(j=0;j<5;j++) {
err = pthread_create(&(tid[j]), NULL, &doSomeThing2, NULL);
if (err != 0)
printf("\ncan't create thread :[%s]", strerror(err));
}
for(j=0;j<5;j++)
{
pthread_join(tid[j], NULL);
}
exit(0);
default:
/* parent process */
printf("Got child pid of %d\n",mypid);
i=5;
while(i--)
{
sleep(1);
printf("Parent sending signal to child \n");
kill(mypid,SIGTERM);
}
break;
}
return 0;
}
When I executed this program, I got below results:
root#sri-ThinkCentre-M72e:/home/sri/Downloads# ./signal-fork
Got child pid of 10049
In child process,my pid is b7573700
In thread handler.my pid is b6d71b40
In thread handler.my pid is b6570b40
In thread handler.my pid is b5d6fb40
In thread handler.my pid is b7572b40
In thread handler.my pid is b556eb40
Parent sending signal to child
In completion handler.my pid is b7573700
Parent sending signal to child
In completion handler.my pid is b7573700
Parent sending signal to child
In completion handler.my pid is b7573700
Parent sending signal to child
In completion handler.my pid is b7573700
Parent sending signal to child
In completion handler.my pid is b7573700

Passing signals between parent and child process in C

I am trying to use signals to pass between a parent and child process, but after the first 2 statements are printed
for example in mine it shows:
CHILD 4225: Running, parent is 4224
PARENT 4224: Telling the Child Process 4225 to start
it just gets stuck running forever! I'm not sure where I am going wrong on this...
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<stdlib.h>
#include<errno.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
void p_sig_usr(int signo){
if(signo == SIGUSR1){
printf("*** Parent SIGUSR1 handler - Received 'task started' signal from child ***\n");
}
if(signo == SIGUSR2){
printf("*** Parent SIGUSR2 handler - Received 'task completed' signal from child ***\n");
}
else
printf("unexpected signal received");
return;
}
void c_sig_usr(int signo){
if(signo == SIGUSR1){
printf("*** Child SIGUSR1 handler - Received 'task start' signal from parent ***\n");
}
if(signo == SIGUSR2){
printf("*** Child SIGUSR2 handler - Received 'task complete verification' signal from parent ***\n");
}
else
printf("unexpected signal received");
return;
}
int main(void)
{
pid_t child_pid, parent_pid;
parent_pid = getpid();
struct sigaction p_sig;
sigemptyset(&p_sig.sa_mask);
p_sig.sa_flags = 0;
p_sig.sa_handler = p_sig_usr;
child_pid = fork();
if ( child_pid == -1){
perror("failed to fork a new process");
return 1;
}
if (child_pid == 0){
struct sigaction c_sig;
sigset_t c_myset;
sigemptyset(&c_sig.sa_mask);
c_sig.sa_flags = 0;
c_sig.sa_handler = c_sig_usr;
child_pid = getpid();
printf("CHILD %d: Running, parent is %d\n",child_pid, parent_pid);
sigfillset(&c_myset);
sigdelset(&c_myset, SIGUSR1);
sigsuspend(&c_myset);//suspend until get SIGUSR1
printf("CHILD: Telling parent that I'm starting task.\n");
sleep(3);
kill(parent_pid, SIGUSR1);
printf("CHILD: Performing task\n");
sigfillset(&c_myset);
sigdelset(&c_myset, SIGUSR2);
sigsuspend(&c_myset);//suspend and wait for SIGUSR2
printf("CHILD: Telling parent that work is done.\n");
kill(parent_pid, SIGUSR2);
printf("CHILD %d: Finished\n", child_pid);
}
else{
struct sigaction p_sig;
sigset_t p_myset;
sigemptyset(&p_myset);
sleep(3);//parent now sleeping to let child set up handlers
printf("PARENT %d: Telling the Child Process %d to start\n", parent_pid, child_pid);
kill(child_pid, SIGUSR1);
sigfillset(&p_myset);
sigdelset(&p_myset, SIGUSR1);
sigsuspend(&p_myset);//suspend until get SIGUSR1
sleep(3);
kill(child_pid,SIGUSR2);
printf("PARENT: Told child to notify of task completion.\n");
sigfillset(&p_myset);
sigdelset(&p_myset, SIGUSR2);//suspend until get SIGUSR2
printf("PARENT %d: Finished.", parent_pid);
}
return 0;
}
Thank you in advance for the help!
I'm just referring to the documentation for these functions—I have no experience using them.
It appears what sigfillset() is going to do is load the process signal mask into your sigset_t. This means that your sigset_t is going to contain the set of signals that are currently blocked by your process. I assume the default is nothing is blocked, so the set would be empty.
You might want to test this by printing out the contents of the set, or just looking at it in a debugger.
Now from the docs I understand what sigdelset(&p_myset, SIGUSR1) will do is remove the signal SIGUSR1 from the set you just filled. This set is by assumption already empty so it's unlikely this call does anything. Again, verify by looking at it in a debugger.
So now what sigsuspend() is going to do is replace your process signal mask with your new mask, which by assumption isn't any different than the default mask (again, check this in a debugger). Then on the child side will wait until the process receives SIGUSR1 and processes it via a signal handler. So your child will process SIGUSR1 but only because that's the default behaviour.
Your example code doesn't seem to have installed any signal handlers. I think you would have to call the sigaction() function to do that. Therefore very likely the default signal handler will run to process SIGUSR1.
According to this page, the default signal handling for SIGUSR1 is
(i) ... Abnormal termination of the process. The process is terminated with all the consequences of _exit() except that the status made available to wait() and waitpid() indicates abnormal termination by the specified signal.
So I'm guessing the child dies when the parent does kill(child_pid, SIGUSR1). This would mean the child isn't around to signal the parent back.
This is mainly guesswork on my part. What I recommend for you is learning how to use gdb or some other debugger so you can set some breakpoints and step through and learn what the program is actually doing.
You forgot to call sigaction after defining the struct sigaction on both the parent and child. Also, beware that the struct sigaction p_sig is redefined in the parent process.
So, I guess if you change your program to something like listed below, it should work.
--- foo.c 2014-06-16 16:37:10.918932118 -0300
+++ bar.c 2014-06-16 16:37:48.710228467 -0300
## -36,10 +36,6 ##
{
pid_t child_pid, parent_pid;
parent_pid = getpid();
- struct sigaction p_sig;
- sigemptyset(&p_sig.sa_mask);
- p_sig.sa_flags = 0;
- p_sig.sa_handler = p_sig_usr;
child_pid = fork();
if ( child_pid == -1){
perror("failed to fork a new process");
## -51,6 +47,7 ##
sigemptyset(&c_sig.sa_mask);
c_sig.sa_flags = 0;
c_sig.sa_handler = c_sig_usr;
+ sigaction(SIGUSR1, &c_sig, NULL);
child_pid = getpid();
printf("CHILD %d: Running, parent is %d\n",child_pid, parent_pid);
sigfillset(&c_myset);
## -69,6 +66,10 ##
}
else{
struct sigaction p_sig;
+ sigemptyset(&p_sig.sa_mask);
+ p_sig.sa_flags = 0;
+ p_sig.sa_handler = p_sig_usr;
+ sigaction(SIGUSR1, &p_sig, NULL);
sigset_t p_myset;
sigemptyset(&p_myset);
sleep(3);//parent now sleeping to let child set up handlers

Resources