I'm studying about processes in Linux programming, there is this code that I cannot understand. As far as I know when a process is suspended, it does not receive signals (except the one that wakes it), but in this code, when the parent process is running, it calls wait, but it still print out counter, which means it received SIGUSR1. Can anyone explain this?
I already know the order or running is arbitrary, if the child process runs first then there is no problem, but what if the parent runs first?
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
pid_t pid;
int counter = 0;
int status;
void handler1(int sig){counter ++;
printf("counter = %d\n", counter);
fflush(stdout);
kill(pid, SIGUSR1);
}void handler2(int sig){counter += 3;
printf("counter = %d\n", counter);
exit(0);
}
int main() {
signal(SIGUSR1, handler1);
if ((pid = fork()) != 0) {
pid_t p;
if ((p = wait(&status)) > 0) {
counter += 2;
printf("counter = %d\n", counter);
}
} else {
signal(SIGUSR1, handler2);
kill(getppid(), SIGUSR1);
while(1) {};
}
}
I expect the program will be suspended, but it runs well every time.
Processes always receive signals if they don't ignore them (signal(SIGnum, SIG_IGN);).
Unignored signals can be deferred by setting a signal mask (e.g., with sigprocmask, unmasking them then causes the pending signals to be delivered) or they're deferred if the process is stopped (with SIGSTOP/SIGTSTOP; sending SIGCONT to the processes causes the pending signals to be delivered). (Note that non-realtime signals may be coalesced. You may, for example, receive a signal only once when it was sent 3 times.)
Blocking calls like wait block/suspend the process until they're finished or until a signal delivery interrupts them.
Masking a signal (e.g., with sigprocmask) is sometimes called blocking the signal (from being deliverable), but that's different from a blocking syscall that blocks/sleeps/suspends the process (blocks it from running on a CPU).
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);
}
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");
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.
I forked a child and I am trying to synchronize them so they print
child 0
parent 0
child 1
parent 1
I have to use sigsuspend though, this is my code for the moment and all I get is parent suspend. There is no trace of the child.
int c=0, receivedP=0, receivedC=0;
sigset_t setParent, setChild;
void handler(int s){
if(s==SIGUSR1){
receivedC=1;
printf("parent --sig1--> child\n");
c++;
}
else{
receivedP=1;
printf("child --sig2--> parent\n");
}
}
void child(){
sigfillset(&setChild);
sigdelset(&setChild,SIGUSR1);
sigdelset(&setChild,SIGINT); //this makes me able to terminate the program at any time
while(1){
if(receivedC==0){
printf("child suspend\n");
sigsuspend(&setChild);
}
receivedC=0;
printf("child %d\n",c);
kill(getppid(),SIGUSR2);
}
}
void parent(pid_t pf){
sigfillset(&setParent);
sigdelset(&setParent,SIGUSR2);
sigdelset(&setParent,SIGINT); //this makes me able to terminate the program at any time
kill(pf,SIGUSR1);
while(1){
if(receivedP==0){
printf("parent suspend\n");
sigsuspend(&setParent);
}
receivedP=0;
printf("parent %d\n",c);
kill(pf,SIGUSR1);
}
}
int main(){
signal(SIGUSR1,handler);
signal(SIGUSR2,handler);
pid_t p;
p= fork();
if(!p)child();
else parent(p);
return 0;
}
Anybody knows what's causing this?
I think you are running foul of one of the classic problems with signals.
while(1){
if(receivedP==0){
printf("parent suspend\n");
sigsuspend(&setParent);
}
receivedP=0;
printf("parent %d\n",c);
kill(pf,SIGUSR1);
}
Imagine what happens if the signal from the child arrives in between the instructions for if(receivedP==0) and sigsuspend(&setParent). The handler will execute, and will set receivedP to one, but the main loop won't check it again; it will go into sigsuspend and never come out.
In order to use sigsuspend safely, you need to have the signals you care about be blocked at all times when the program is not calling sigsuspend. You do that with sigprocmask. It's also necessary to ensure that the signals are blocked during the execution of the handler, which requires you to use sigaction instead of signal (but you should do that anyway, as signal is severely underspecified and system-to-system variations will bite you in the ass).
Once you ensure that the signal can only be delivered during a sigsuspend, you no longer need the receivedP and receivedC variables; you know that the signal happened, or sigsuspend would not have returned. (This would not be true if your program was waiting for more than a single signal in each process, but at that point things get much more complicated; don't worry about it till it comes up.)
In fact, once you ensure that, you don't need to do anything in the signal handler. Your counter variable can be local to parent and child. It's always best to do as little in a signal handler as possible; the letter of the C standard allows you to do almost nothing without risking undefined behavior, and POSIX only opens it up a little bit more. (Exercise for you: change this program to use sigwaitinfo so that it doesn't need handler functions at all.)
This modification of your program works reliably for me. I also corrected a number of other style problems and minor errors: note the loops in parent and child doing things in different orders, the error checking in main, and that I am only blocking SIGUSR1 and SIGUSR2, because there are several other signals that should be allowed to terminate the process (SIGTERM, SIGHUP, SIGQUIT, SIGSEGV, …) and you don't want to have to maintain a list. It is sufficient to block the signals that the program has installed handlers for.
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
static void handler(int unused)
{
}
static void child(sigset_t *ss)
{
unsigned int c = 0;
pid_t parent_pid = getppid();
sigdelset(ss, SIGUSR1);
for (;;) {
sigsuspend(ss);
printf("child %u\n", c++);
kill(parent_pid, SIGUSR2);
}
}
static void parent(sigset_t *ss, pid_t child_pid)
{
unsigned int c = 0;
sigdelset(ss, SIGUSR2);
for (;;) {
printf("parent %u\n", c++);
kill(child_pid, SIGUSR1);
sigsuspend(ss);
}
}
int main(void)
{
// Ensure line-buffered stdout.
if (setvbuf(stdout, 0, _IOLBF, 0)) {
perror("setvbuf");
return 1;
}
// This signal mask is in effect at all times _except_ when sleeping
// in sigsuspend(). Note that _only_ the signals used for IPC are
// blocked. After forking, each process will modify it appropriately
// for its own use of sigsuspend(); this does not affect the kernel-side
// copy made by sigprocmask().
sigset_t ss;
sigemptyset(&ss);
sigaddset(&ss, SIGUSR1);
sigaddset(&ss, SIGUSR2);
if (sigprocmask(SIG_BLOCK, &ss, 0)) {
perror("sigprocmask");
return 1;
}
// Always use sigaction(), not signal(); signal() is underspecified.
// The mask here is the signal mask to use _while the handler is
// executing_; it should also block both IPC signals.
struct sigaction sa;
sa.sa_handler = handler;
sa.sa_mask = ss;
sa.sa_flags = SA_RESTART;
if (sigaction(SIGUSR1, &sa, 0) || sigaction(SIGUSR2, &sa, 0)) {
perror("sigaction");
return 1;
}
pid_t child_pid = fork();
if (child_pid < 0) {
perror("fork");
return 1;
}
if (child_pid == 0)
child(&ss);
else
parent(&ss, child_pid);
// we never get here but the compiler might not know that
return 0;
}
I recommend you read the GNU C Library Manual's section on signal handling all the way through; it contains several other bits of helpful advice on using signals safely.
#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.