0

In the main function I created a "sigaction sigact" which connects to a handler, and I removed the SIGUSR1 signal from the blocked sigact.sa_mask set. The SIGUSR1 is the signal I want to get twice from TWO children before going further. How do I wait for both the children process to get the SIGUSR1 signals from?

void handler(...){...}

int main()
{
    int pipe1[2];
    int pipe2[2];
    
    char buf;

    struct sigaction sigact;
    sigact.sa_handler = handler;
    sigfillset(&sigact.sa_mask);
    sigact.sa_flags = 0;
    sigdelset(&sigact.sa_mask,SIGUSR1);
    sigaction(SIGUSR1,&sigact,NULL);

    pid = fork();

    if(pid == 0){
       
       ...
       sleep(3);                                     // the sleep is just a must-have of the homework
       kill(getppid(),SIGUSR1);                      // CHILD1
       ...                         

    }else{
          pid1 = fork();

          if(pid1 == 0){

                ...
                sleep(3);
                kill(getppid(),SIGUSR1);             // CHILD2
                ...               
         
          }else{

               ...
               sigsuspend(&sigact.sa_mask);                    // PARENT
               sigsuspend(&sigact.sa_mask);                    // WAIT FOR SIGUSR1 FROM CHILD1 AND
               ...                                             // CHILD2 BEFORE GOING FURTHER
               ...                                             // (The two sigsuspends were my best idea, 
               ...                                             //  doesn't work)
               // DO OTHER THINGS AFTER TWO SIGNALS CAME 
               // (e.g. sending children data with pipes, 
               // just homework stuff...)

          }
    }
    return 0;
}

As You can see I'm trying with two sigsuspends but they won't work, it waits forever. It would work by using only one sigsuspend but I need feedback from both children.

How do you wait for 2 signals?

PizzaPeet
  • 75
  • 6
  • I don't think there's a way to do this. Consider using pipes to receive from the children. – Joshua Dec 06 '20 at 03:23
  • I just can't because that's the homework at the university xD but thanks @Joshua – PizzaPeet Dec 06 '20 at 03:28
  • To allow SIGUSR1 to interrupt an already running SIGUSR1 handler, you must clear SIGUSR1 from the handler's `sa.sa_mask` (as you've done) _and_ also [set the `SA_NODEFER` flag](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigaction.html#tag_16_540_03). – pilcrow Dec 08 '20 at 15:50
  • As the [Linux man pages notes](https://man7.org/linux/man-pages/man2/sigsuspend.2.html#NOTES), `sigsuspend` is normally used in conjunction with `sigprocmask` to temporarily unmask otherwise blocked signals. Imagine that you did not have the `sleep(3)` in the children, but still wanted the parent to be interrupted _only_ in a call to `sigsuspend`. – pilcrow Dec 08 '20 at 15:55

1 Answers1

0

This cannot be done reliably with the constraints you have. Push back on this homework.

If two SIGUSR1 signals arrive "at the same time," one will be lost, because ordinary UNIX signals of the same type do not queue. You do not control this timing — the OS scheduler does.

So, do something else. Use realtime signals which can queue at least 32 (_POSIX_SIGQUEUE_MAX) pending signals. Use pipes between children and parent to communicate. Use different ordinary signals (e.g., SIGUSR1 and SIGUSR2) per process. Etc.

pilcrow
  • 56,591
  • 13
  • 94
  • 135