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.
Related
I have a problem with my code,
I want all the children stop when the program start.
and after that I want just the child with the index of i to continue executing and others to be stopped .
I want to execute them in this order p0 ,p1,p2,p3,p4,p0,p1....
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#define N 5
void handler(int i)
{
if (i == SIGCONT)
{
printf("signal cont\n");
}
}
int main()
{
int pid[N];
for (int i = 0; i < N; i++)
{
if ((pid[i] = fork()) == 0)
{
/* code */
while (1)
{
printf("ici fils %d\n", i);
usleep(50000);
}
}
else
{
kill(pid[i], SIGSTOP);
// kill(pid[i], SIGSTOP);
if (i == N - 1)
{
kill(pid[i], SIGCONT);
sleep(2);
kill(pid[i], SIGSTOP);
kill(pid[0], SIGCONT);
}
else
{
kill(pid[i], SIGCONT);
sleep(2);
kill(pid[i], SIGSTOP);
kill(pid[i + 1], SIGCONT);
}
// kill(pid[i], SIGKILL);
waitpid(pid[i], NULL, 0);
}
signal(SIGCONT, &handler);
}
}
There are several issues with your code, among them:
Any processes to be stopped via SIGSTOP must not have a handler registered for that signal. Registering a handler causes the handler's behavior to replace the default behavior of stopping the process.
It's usually a bad idea to register a handler for SIGCONT. Doing so will not prevent a SIGCONT from continuing the process, which is a special characteristic of SIGCONT that can be surprising, but also the handler will fire whenever a SIGCONT is delivered, even if the process was not stopped, which is often a different kind of surprise.
You register your signal handlers only in the parent, after the first fork. The subsequently forked children will inherit those, but the first one will not. Among other things, this will prevent the first child's pause() from being unblocked by the signals the parent sends to it. You can make each child register any needed handlers for itself, or you can register them in the parent, before the first fork.
There is a race between each child's pause() and the parent's first kill() targeting that child. It is possible for the child to receive the SIGCONT before it calls pause(), in which case it will wait for the next signal. You can prevent that by blocking SIGCONT in the parent before forking, and using sigsuspend() in the child, with an appropriate mask, instead of the initial pause(). In that case, you probably want to unblock SIGCONT after returning from that initial sigsuspend().
The parent attempts to send signals to processes that it has not forked yet (kill(pid[i + 1], SIGCONT);).
It's not clear what the full behavior you are trying to achieve is, but you may want to fork all the children first, and only then start sending signals.
Update
With respect to the update to the question,
You apparently want to cycle repeatedly through the child processes, but your code runs through them only once. This is a good reason to implement what I already suggested above: fork all the children first, then, separately, do all the signalling.
In the child processes, instead of using pause(2), use raise(3) to signal the calling process to stop with SIGSTOP. There is no real need to register signal handlers.
In the parent process, after creating a child process, wait for it to stop (or terminate) by using waitpid(2) with the WUNTRACED flag set. The WIFSTOPPED(...) macro can be used to specifically determine the status of the child. The WCONTINUE flag can be used to wait for a child process to continue, and like before there is the WIFCONTINUED(...) macro.
Here is a cursory example, with no meaningful error handling. Note that concurrent sleeps, while simple, are not technically a consistent way to schedule things. The output of this program may differ slightly between executions.
#define _POSIX_C_SOURCE 200809L
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#define CHILDCOUNT 5
sig_atomic_t looping = 1;
void handler(int sig) {
(void) sig;
looping = 0;
}
pid_t create_child(void) {
pid_t pid = fork();
if (!pid) {
/* child */
raise(SIGSTOP);
pid_t self = getpid();
printf("SIGCONT in %d\n", self);
while (1) {
printf("RUNNING in %d\n", self);
sleep(1);
}
/* bug net */
exit(EXIT_SUCCESS);
}
return pid;
}
void killwait(pid_t pid, int sig) {
kill(pid, sig);
int status;
waitpid(pid, &status, WUNTRACED | WCONTINUED);
if (WIFSTOPPED(status))
printf("P: C(%d) STOPPED!\n", pid);
if (WIFCONTINUED(status))
printf("P: C(%d) CONTINUED!\n", pid);
if (WIFSIGNALED(status) && SIGKILL == WTERMSIG(status))
printf("P: C(%d) SUCCESSFULLY KILLED!\n", pid);
}
int main(void) {
pid_t pids[CHILDCOUNT];
/* tentative: catch this in all processes so the parent may reap manually */
signal(SIGINT, handler);
for (size_t i = 0; i < CHILDCOUNT; i++) {
pid_t current = pids[i] = create_child();
printf("Parent now has child (%d) [#%zu].\n", current, i);
killwait(current, 0);
}
for (size_t i = 0; looping; i = (i + 1) % CHILDCOUNT) {
pid_t current = pids[i];
printf("P: C(%d) STARTING [#%zu].\n", current, i);
killwait(current, SIGCONT);
sleep(2);
killwait(current, SIGSTOP);
}
for (size_t i = 0; i < CHILDCOUNT; i++)
killwait(pids[i], SIGKILL);
}
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.
I'm trying to create a program where a process forks, creating a child process, and the parent must always finish printing to the screen before the child is finished printing to the screen, no matter what. I also wish to accomplish this using signals instead of pipelining.
It is a similar problem to the question asked here: Explanation of sigsuspend needed
I understand that kill(pid,signal); is to send a signal to that pid and tell it to finish executing and terminate.
The problem is, when it executes, the child doesn't print after the suspend. Heres the code:
int main(void){
pid_t pid;
int i;
pid = fork();
if(pid==0){
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask,SIGUSR1);
printf("This is the child Process id = %d \n",getpid());
sigsuspend(&mask);
printf("The child is now complete \n");
}
else{
printf("This is the parentProcess id = %d \n",getpid());
printf("The parentProcess is complete\n");
sleep(1);
int j = kill(pid,SIGUSR1);
if (j!=0)
{
perror(NULL);
}
exit(0);
}
}
I have managed to accomplish my task (printing the parent before the child) by using a global variable int x = 0; and a signal handler method void handle1(int s){x = 1;}before the main. In the main I added signal(SIGUSR1,handle1); In the child I removed all the sigset and sigsuspend lines and instead wrote while(x==0){/*do_nothing*/} 1 line before the printf statement. So when the parent executes kill(pid,SIGUSR1) the signal handler which is inherited by the child process also gets executed and sets x=1. So the child now leaves the while loop and can print it's statement.
However I believe it would be helpful to know how to accomplish this task using sigmask_t and sigsuspend() but i cant get it to work that way.
There are 3 problems in your code:
SIGUSR1 is the signal you want to deliver to the child. You can't use sigaddset(&mask,SIGUSR1);, it does exactly the opposite of your intention.
According to POSIX standard sigsuspend() below, you should install a signal handler for SIGUSR1 to make sigsuspend() continue the following code, since the default behavior of SIGUSR1 is termination.
The sigsuspend() function shall replace the current signal mask of the calling thread with the set of signals pointed to by sigmask and then suspend the thread until delivery of a signal whose action is either to execute a signal-catching function or to terminate the process.
It would be better if you collect the child from the parent, otherwise there is a race condition.
The code below will work:
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
void handler(int sig) {}
int main(void){
pid_t pid;
int i;
pid = fork();
signal(SIGUSR1, handler);
if(pid==0){
sigset_t mask;
sigemptyset(&mask);
//sigaddset(&mask,SIGUSR1);
printf("This is the child Process id = %d \n",getpid());
sigsuspend(&mask);
printf("The child is now complete \n");
}
else{
printf("This is the parentProcess id = %d \n",getpid());
printf("The parentProcess is complete\n");
sleep(1);
int j = kill(pid,SIGUSR1);
if (j!=0)
{
perror(NULL);
}
wait(NULL);
exit(0);
}
}
You have a few issues.
Your parent process should wait for the child to complete. This allows for diagnostics (such as properly waiting for the child to print), but is otherwise a bookkeeping task that is a good habit even when the waiting process will just exit:
printf("This is the parentProcess id = %d \n",getpid());
printf("The parentProcess is complete\n");
sleep(1);
int j = kill(pid,SIGUSR1);
if (j!=0)
{
perror(NULL);
exit(0);
}
waitpid(pid, NULL, 0);
exit(0);
Now, you have set SIGUSR1 in your mask to sigsuspend(), which causes the signal to be ignored. This is now more obvious once the parent is made to wait, because the parent will never exit. So, remove the line of code that sets SIGUSR1.
Finally, the default handler for SIGUSR1 will simply cause the process to exit, and so the printf will not get a chance to print. If you want it to print, you should add a signal handler for SIGUSR1. It doesn't have to do anything.
void h (int s) {}
...
sigset_t mask;
sigemptyset(&mask);
//sigaddset(&mask,SIGUSR1);
printf("This is the child Process id = %d \n",getpid());
struct sigaction sa = { .sa_handler = h };
sigaction(SIGUSR1, &sa, NULL);
sigsuspend(&mask);
printf("The child is now complete \n");
I am trying to use signal to sync N processes then print out something.
Each child process register a handler which print "yo" and "hihi" when catching SIGUSR1.
I use kill(0, SIGUSR1) to trigger every process. Since the default action for catching SIGUSR1 is being killed, I set a do-nothing handler for the main process so that it will wait all child died.
The fork and send signal program will repeat for k times, I expect it will show out N*k times "yo" and "hihi". However, it doesn't show enough "yo" and "hihi" as I expect. The number of "yo" is different every execution.
Here is my code, and thanks for your help!
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <time.h>
#include <signal.h>
#include <sys/time.h>
#include <string.h>
#define N 3
int pid_id[N];
void handler2 (int signum)
{
printf("hihi\n");
}
void handler (int signum)
{
signal(SIGUSR2, handler2);
printf("yo\n");
raise(SIGUSR2);
}
void handler_do_nothing (int signum)
{
;
}
void child(int process_index)
{
struct sigaction sa;
/* Register */
memset(&sa, 0, sizeof(sa));
sa.sa_handler = handler;
sigaction(SIGUSR1, &sa, NULL);
printf("I am %d.\n", getpid());
pid_id[process_index] = getpid();
sleep(1);
exit(0);
}
int main()
{
int i, k, status;
pid_t pid[N];
pid_t pid_wait;
struct sigaction sa_main;
/* Register */ /* Main process will terminate if catch SIGUSR1 by default setting*/
memset(&sa_main, 0, sizeof(sa_main));
sa_main.sa_handler = handler_do_nothing;
sigaction(SIGUSR1, &sa_main, NULL);
/* Race k times */
for (k=0;k<3;k++)
{
for (i=0;i<N;i++)
{
pid[i] = fork();
if (pid[i]==0)
{
child(i);
}
}
// sleep();
kill(0, SIGUSR1);
for (i=0;i<N;i++)
{
do
{
pid_wait = waitpid(pid[i], &status, WNOHANG);
printf("I am waiting..\n");
sleep(1);
}while(pid_wait != pid[i]);
}
}
printf("all done\n");
return 0;
}
Your child processes are being signalled before they have had time (i.e. execution resource scheduled) to install the new signal handler.
This means that when the main program sends SIGUSR1, some subset of the child processes will still have handler_do_nothing installed.
If you want to wait until the child processes have all finished setting up, you will need to add some interprocess communication mechanism - e.g. the children could signal the parent process when they are ready.
#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.