/* 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 #include #include #include #include #include #include #include #include #include #include #include //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; }