#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>

#define MAX_CHILD 10

int n;
int child_pids[MAX_CHILD];

void handler(int signo) {              // funzione da eseguire all'arrivo del segnale

    int i;

    for(i = 0; i < n; ++i) {

        printf("killing child process %d\n", child_pids[i]);
        kill(child_pids[i], SIGTERM);
    }

    exit(0);
}

int main(int argc,char *argv[])
{
    int pid,i,s;
    int sum;
    int pdchf[2];
    int numero;
    int arrivo;
    struct sigaction act;
    sigset_t sigmask, zeromask;

    if(argc !=2) {

        fprintf(stderr,"Use: %s N\n",argv[0]);
        exit(-1);
    }

    n = atoi(argv[1]);

    if(n < 1)
        n = 1;
    else if(n > MAX_CHILD)
        n = MAX_CHILD;

    act.sa_handler = handler;
    sigemptyset(&act.sa_mask);
    act.sa_flags= 0;
    sigaction(SIGUSR1, &act, NULL);

    // blocco il segnale SIGUSR1
    sigemptyset(&sigmask);
    sigaddset(&sigmask, SIGUSR1);
    sigprocmask(SIG_BLOCK, &sigmask, NULL);

    // apro la pipe per la comunicazione da padre a figlio
    if (pipe(pdchf) < 0) {

        perror("pipe() error");
        exit(1);
    }

    /* creo i figli  */
    for(i = 0; i < n ; i++) {

        if((pid=fork())<0) {  //controllo che non ci siano errori nel processo di creazione dei figli

          perror("fork() error");
          exit(-2);
        } else {

            if(pid == 0) { /* Processi figli */

                sum = 0;
                close(pdchf[1]);

                printf("CHILD %d created\n", getpid());

                do {

                    read(pdchf[0], &arrivo, sizeof(int));
                    printf("CHILD %d: read %d -> sum  = %d\n", getpid(), arrivo, sum + arrivo);
                    sum += arrivo;
                } while(sum <= 500);

                // ho un totale di numeri superiori a 500 quindi invio il segnale al padre
                kill(getppid(), SIGUSR1);
                printf("CHILD %d: sum = %d, sending SIGUSR1...\n",getpid(), sum);
                exit(0);
            } else {

                child_pids[i] = pid;
            }
        }
    }

    printf("Child process creation complete, starting to write...\n");

    close(pdchf[0]); //il padre sulla pipe deve solo scrivere cosa mandare al figlio
    srand(time(0));

    for(s = 0; s < 5; s++) {  //lo faccio entrare in un for dove manda 5 numeri e intanto è insensibile a SIGUSR1

        sleep(2);
        numero = rand() % 90 + 10;
        printf("sending %d\n", numero);
        write(pdchf[1], &numero, sizeof(int));
    }

    printf("Five iterations completed, unmasking SIGUSR1...\n");

    sigprocmask(SIG_UNBLOCK, &sigmask, NULL); //ora che ho inviato come minimo 5 segnali il padre diventa sensibile a SIGUSR1


    for(;;) {

        sleep(2);
        numero = rand() % 90 + 10;
        printf("sending %d\n", numero);
        write(pdchf[1], &numero, sizeof(int));
    }

    return 0;
}
