0

I want to write a program which will create N children, using fork() function. Each child will wait from 0 to 3 seconds and then it'll send it's parent exactly one signal SIGUSR1. Parent handles all of these signals.

The problem is that my program is not always handling all signals from it's children. How to repair it?

Second question: I know that I shouldn't use printf inside handler because something bad might happen. How can I replace this instruction?

main.c

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

void error(char *s){
    printf("%s\n",s);
    perror("Program execution failed.");
    exit(EXIT_FAILURE);
}

volatile int N=8; //final number of children
volatile int k=0; //number of received SIGUSR1 signals

void childRequestHandler(int signo, siginfo_t* info, void* context){
    k++;
    printf("%d,Father received request from child: %d\n",k,info->si_pid);

}

int main() {
    struct sigaction act;
    sigemptyset(&act.sa_mask);
    act.sa_flags = SA_SIGINFO;
    act.sa_sigaction = childRequestHandler;
    if(sigaction(SIGUSR1,&act,NULL) == -1) printf("ERROR OCCURED");

    for(int i=0;i<N;i++){
        pid_t pid = fork();
        if(pid == 0) {
            execl("./child", "./child", NULL);
            error("Fork error happened\n");
        }
    }

    while (1){
        sleep(1);
    }

}

child.c

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <time.h>



int main() {
    time_t t;
    srand((unsigned int) getpid()+ time(NULL));


    int length_of_sleeping = rand() % 4 ;
    printf("I live: %d, sleeps %ds \n",getpid(),length_of_sleeping);
    sleep(length_of_sleeping);
    kill(getppid(),SIGUSR1);

    while(1){

    }

}

output:

I live: 4195, sleeps 3s 
I live: 4196, sleeps 3s 
I live: 4197, sleeps 1s 
I live: 4202, sleeps 3s 
I live: 4198, sleeps 0s 
I live: 4201, sleeps 2s 
I live: 4199, sleeps 0s 
I live: 4200, sleeps 3s 
1,Father received request from child: 4198
2,Father received request from child: 4197
3,Father received request from child: 4201
4,Father received request from child: 4195
grzegorzs
  • 486
  • 5
  • 11

1 Answers1

1

When the signal handler is executing, the signal is blocked. All SIGUSR1 signals received during that time will not be noticed.

You could use the SA_NODEFER flag when establishing the signal, see the sigaction manual page for information about the flag.

However, if you use SA_NODEFER, don't use printf! It's not an async-signal-safe function. See e.g. this manual page about signal safety for more information.


From the POSIX sigaction reference:

When a signal is caught by a signal-catching function installed by sigaction(), a new signal mask is calculated and installed for the duration of the signal-catching function.... This mask is formed by taking the union of the current signal mask and the value of the sa_mask for the signal being delivered, and unless SA_NODEFER or SA_RESETHAND is set, then including the signal being delivered. If and when the user's signal handler returns normally, the original signal mask is restored.

[Emphasis mine]

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • POSIX [Signal Concepts](http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04) indicates that blocked signals remain pending until they can be delivered, so that the signalling is reliable. Or what am I misreading? – Jonathan Leffler Apr 07 '18 at 19:17
  • @JonathanLeffler I'd say that's about *other* signals, not the *current* signal which will be masked (see quote in my edit). – Some programmer dude Apr 08 '18 at 04:44
  • 2
    Current and other signals shouldn't be treated differently in this case. However, if a signal is generated again while it is already pending (as can happen in the OPs program since multiple children could generate the signal before any of them have been delivered to the parent) then it's implementation-defined as to whether or not that signal is delivered more than once. Most Unix systems do not, in fact, queue them unless they support the real-time extensions. – Crowman Apr 08 '18 at 06:14
  • In the POSIX [Signal Concepts](http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04) reference, it documents what Paul says: _If a subsequent occurrence of a pending signal is generated, it is implementation-defined as to whether the signal is delivered or accepted more than once in circumstances other than those in which queuing is required. The order in which multiple, simultaneously pending signals outside the range SIGRTMIN to SIGRTMAX are delivered to or accepted by a process is unspecified._ It doesn't note that most Unix systems do not do the queueing. – Jonathan Leffler Apr 12 '18 at 04:16