/*TESTO
Scrv un prog che:

- Se invocato senza parametri sulla riga di comando
entra in un ciclo infinito in cui visualizza un carattere punto ogni
2 secondi.


- Se invocato con un solo parametro, invia  un segnale SIGUSR1 al processo
  il cui pid è specificato come parametro, affinche' esso riduca di 200 millisecondi il periodo di
  visualizzazione del carattere punto.


  - Se invocato con due parametri, invia un segnale SIGUSR2 al processo
  il cui pid è specificato come primo parametro, attende un
  numero di secondi pari al valore del secondo parametro, per poi inviare un
  segnale SIGUSR1 al processo con il pid specificato ; il processo che
  ha ricevuto un segnale SIGUSR2 deve porsi esplicitamente in attesa di
  un nuovo segnale SIGUSR1 prima di poter proseguire con la
  visualizzazione del carattere punto.
*/

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


unsigned long attendiMicro=2000000; //2 secondi in microsecondi
unsigned long decrementaMicro=200000; //200ms in microsecondi (provare a metterlo anche a 500ms, o 1 secondo, per rendere piu' visibile l'effetto...)

//Funzione di gestione segnali
void handler(int signo)
{
  sigset_t s;

  switch(signo)
    {
    case SIGUSR1 :
      printf("\nProcesso %d ha ricevuto un SIGUSR1\n",getpid());
      fflush(NULL);

      //decremento il numero di microsecondi che devo attendere
      attendiMicro=(attendiMicro-decrementaMicro)>0 ? (attendiMicro-decrementaMicro) : attendiMicro;

      break;

    case SIGUSR2:
      printf("\nProcesso %d ha ricevuto un SIGUSR2... attendo SIGUSR1\n",getpid());
      fflush(NULL);

      //blocco tutti i segnali, eccetto SIGUSR1 e i non bloccabili (SIGKILL e SIGSTOP)
      //
      //non e' strettamente necessario, andava bene anche con tutti i segnali abilitati, tramite una semplice
      //sigemptyset(&s). Diciamo che in questo modo impedisco ad altri segnali non gestiti di interrompere il processo,
      //ma soprattutto ad un eventuale SIGUSR2 di interferire
      sigfillset(&s);
      sigdelset(&s,SIGUSR1);
      //attendo esplicitamente il segnale SIGUSR1 prima di proseguire...
      sigsuspend(&s);

      break;
    }
}



int main(int argc, char *argv[])
{
  struct sigaction sig;
  int N1,N2;


  //se argc==1 vuole dire che non avevamo nessun argomento da linea di comando
  if(argc==1)
    {
      //installo il gestore per SIGUSR1 e SIGUSR2
      sig.sa_handler = handler;
      sigemptyset(&sig.sa_mask);

      //blocco il SIGUSR2 durante l'esecuzione dell'handler SIGUSR1, per sicurezza. Non era richiesto.
      sigaddset(&sig.sa_mask,SIGUSR2);
      //come sopra, blocco il SIGUSR1 durante l'esecuzione dell'handler SIGUSR2, anche questo non richiesto. 
      //Domanda: perche' funziona lo stesso?
      sigaddset(&sig.sa_mask,SIGUSR1);

      sig.sa_flags=0;
      sigaction(SIGUSR1,&sig,NULL);
      sigaction(SIGUSR2,&sig,NULL);

      printf("Processo %d attende indefinitamente",getpid());
      fflush(NULL); //altrimenti non vedete nulla...
      while(1) 
	{
	  printf(".");
	  fflush(NULL);//altrimenti non vedete nulla...

	  //uso una usleep per poter apprezare i millisecondi, e poter effettuale il decremento richiesto quando arriva il SIGUSR1
	  //la sleep non poteva andare bene, in quando accetta solo secondi interi
	  usleep(attendiMicro);
	}
    }

  //se ho almeno un argomento da linea di comando...
  if(argc>=2)
    {
      //leggo il pid a cui dovro' mandare i segnali
      N1=atoi(argv[1]);
      if(N1<=0)
	{
	printf("ERRORE negli argomenti\nUso: programma <N1> <N2>\nN1 e N2 parametri facoltativi. N1 deve essere un pid valido, N2 un numero intero maggiore di zero.\n");
	exit(-1);
	}
 
      //ho 2 (o piu')  argomenti?
      if(argc>=3)
	{
	  //leggo i secondi che dovro' attendere
	  N2=atoi(argv[2]);
	  if(N2<=0)
	    {
	      printf("ERRORE negli argomenti\nUso: programma <N1> <N2>\nN1 e N2 parametri facoltativi. N1 deve essere un pid valido, N2 un numero intero maggiore di zero.\n");
	      exit(-1);
	    }
	  printf("Processo %d manda un SIGUSR2 a %d...",getpid(),N1);
	  kill(N1,SIGUSR2);

	  printf("e attende %d secondi...\n",N2);
	  fflush(NULL);//altrimenti non vedete nulla...
	  sleep(N2);
	}

     printf("Processo %d manda un SIGUSR1 a %d\n",getpid(),N1);
     kill(N1,SIGUSR1);
    }
  return 0;
}
 

/*
---IF aritmentico---

variabile = (condizione) ? valore1 : valore2; 

Questo e' equivalente a:

if(condizione)
  variabile=valore1:
else
  variabile=valore2;

*/


