/* TESTO
Si realizzi un programma in C che abbia il seguente comportamento:
- il processo genera due processi figli;
- il primo processo figlio entra in un ciclo infinito durante il quale visualizza a video un carattere asterisco (*) al secondo;
- il secondo processo figlio entra in un ciclo infinito durante il quale visualizza a video un carattere punto (.) al secondo;
- il processo padre attende indefinitamente: all’arrivo di un segnale SIGUSR1, termina i figli e termina anch’esso.
- a fronte della ricezione di un segnale SIGUSR1 da parte di uno qualunque dei due figli, ENTRAMBE le visualizzazioni dei 
  caratteri da parte dei processi devono arrestarsi. La ricezione da parte di uno qualunque dei due figli di un segnale SIGUSR2 
  deve riavviare ENTRAMBE le visualizzazioni.

Devono essere utilizzate le primitive per la gestione affidabile dei segnali.

*/




#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <signal.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
#include <arpa/inet.h>



//flag che abilita la scrittura
int abilitaScrittura=1;

//vettore dei pid
int pid[2];

//pid dell'altro processo
int altroPid=0;

//Funzione di gestione segnali SIGUSR1 e SIGUSR2
//
//ATTENZIONE
//
//L'idea e' questa: quando un processo (es. P1) riceve un segnale, modofica il PROPRIO flag di abilitazione
//scrittua e inoltra lo stesso segnale all'altro figlio (es. P2), in modo che possa a sua volta modificare
//il proprio flag. Bisogna fare attenzione che, quando l'altro figlio (es. P2)riceve il segnale inoltrato, oltre che 
//modificare il proprio flag, vorra a volta inoltrare il segnale, in quanto non sa se gli e' arrivato
//dall'esterno (utente) o dall'altro figlio (es. P1). Ci sono due modi per fare questo:
//1) usare il flag SA_SIGINFO. In questo modo handler viene chiamato con 3 parametri, di cui uno e' uno struct che
//   contiene il pid del processo che ha mandato il segnale (vedi "man sigaction" e flag SA_SIGINFO
//2) controllando il proprio flag, meno elegante e sicuro, ma piu' semplice
//
//In questa soluzione usiamo il metodo 2
//
void handler(int signo)
{
  printf("Ricevuto segnale\n");

  if(!pid[0] || !pid[1]) //se non sono il padre
    {
      if(signo == SIGUSR1)
	{
	  if(abilitaScrittura)
	    {
	      abilitaScrittura=0;
	      kill(altroPid,SIGUSR1);
	    }
	}
      else
	{
	  if(!abilitaScrittura)
	    {
	      abilitaScrittura=1;
	      kill(altroPid,SIGUSR2);
	    }
	}
    }
  else //sono il padre
    {
      //uccido i figli
      kill(pid[0],SIGKILL);
      kill(pid[1],SIGKILL);

      //attendo i figli
      wait();
    }
}




int main()
{
  struct sigaction sig;
  sigset_t mask;
  int i=0,p[2];

  ////////////////////////////////////////////
  //SEGNALI
  sig.sa_handler=handler; //gestore del segnale
  sig.sa_flags=SA_RESTART;
  sigemptyset(&sig.sa_mask);
  sigaddset(&sig.sa_mask,SIGUSR2); //blocco SIGUSR2 durante l'esecuzione dell'handler

  sigaction(SIGUSR1,&sig,NULL);

  sigemptyset(&sig.sa_mask);
  sigaddset(&sig.sa_mask,SIGUSR1); //blocco SIGUSR1 durante l'esecuzione dell'handler

  sigaction(SIGUSR2,&sig,NULL);
  //////////////////////////////////////////

  //creo la pipe
  if(pipe(p)<0)
    perror("pipe");

  printf("Padre con pid %d\n",getpid());

  for(i=0;i<2;i++)
    {
      if((pid[i]=fork())<0)  //creo il figlio che gestira' la connessione
	{
	  perror("fork figlio");
	  exit(-1);
	}
      if(pid[i]==0) //sono il figlio?
	{
	  /////////////////////////////
	  //CODICE FIGLIO i-esimo

	  printf("Figlio %d con pid %d\n",i,getpid());

	  //leggo l'altro pid
	  if(read(p[0],&altroPid,sizeof(altroPid))<0)
	    perror("read altro pid");

	  //ciclo di scrittura
	  while(1)
	    {
	      //sono abilitato?
	      if(abilitaScrittura)
		printf("%c",i==0 ? '*' : '.');
	      fflush(NULL);

	      //attendo un secondo
	      sleep(1);
	    }
	  ////////////////////////////
	}
    }

  //scrivo al primo figlio il pid del secondo
  if(write(p[1],&pid[1],sizeof(pid[1]))<0)
    perror("write secondo pid");
  //scrivo al secondo figlio il pid del primo
  if(write(p[1],&pid[0],sizeof(pid[0]))<0)
    perror("write primo pid");

  //attendo solo SIGUSR1
  sigfillset(&mask);
  sigdelset(&mask,SIGUSR1);
  sigsuspend(&mask);

  printf("Padre esce.\n");

  return 0;
}
