/* * Horloge a quatre processus: * C -- affichage principal * H, M et S qui comptent les heures, minutes * et secondes et se signalent * mutuellement * C <===> H avec deux pipes * C - -SIGUSR1- -> H pour demander l'heure * S - -SIGUSR1- -> M pour 60 secs * M - -SIGUSR2- -> H pour 60 min * S - -SIGALRM- -> S appel alarme() ou raise (SIGALRM) * pour incrementer les secs * note: C n'est pas cense recevoir de signal */ #include #include #include "CExc.h" #include "nsSysteme.h" // Fork(), Signal() using namespace std; using namespace nsSysteme; // Fork(), Signal() namespace { volatile sig_atomic_t qAffiche = 0; // - - - proc C - - - - - void DeroutFinFils(const int sig) { if(sig == SIGCHLD) { cerr << getpid() << " chld C\n"; int status; while(waitpid(-1,&status,WNOHANG) > 0); } } void DeroutQUIT (const int sig) { if(sig == SIGQUIT) { cerr << getpid() << " q C\n"; qAffiche = 1; } } // - - - proc S - - - - - volatile sig_atomic_t secondes = 0; void DeroutALRMS (const int sig) { if(sig == SIGALRM) { secondes ++; } } // - - - proc M - - - - - volatile sig_atomic_t minutes = 0; void DeroutUSR1M (const int sig) { if(sig == SIGUSR1) { cerr << getpid() << " usr1 M\n"; minutes ++; } } // - - - proc H - - - - - volatile sig_atomic_t heures = 0; void DeroutUSR2H (const int sig) { if(sig == SIGUSR2) { cerr << getpid() << " usr2 H\n"; heures ++; } } void DeroutUSR1H (const int sig) { if(sig == SIGUSR1) { cerr << getpid() << " usr1 H\n"; qAffiche = 1; } } } int main(int argc, char * argv []) { try { if (1 != argc) { throw CExc("main()",string ("Usage : ") + argv [0]); } sigset_t MasqueUSR12, MasqueUSR1, MasqueALRM, MasqueVide; ::sigemptyset (&MasqueVide); ::sigemptyset (&MasqueUSR1); ::sigemptyset (&MasqueALRM); ::sigaddset (&MasqueUSR1, SIGUSR1); ::sigaddset (&MasqueALRM, SIGALRM); // on bloquera les SIGUSR par precaution, // car apres le fork() on ne peut plus // savoir qui fait quoi **en**premier**, donc pour ne // pas perdre de signal ::sigemptyset (&MasqueUSR12); ::sigaddset (&MasqueUSR12, SIGUSR1); ::sigaddset (&MasqueUSR12, SIGUSR2); Sigprocmask (SIG_BLOCK, &MasqueUSR12, 0); Signal(SIGQUIT, SIG_IGN); // car seulement C en aura besoin, // et l'envoi du clavier le fait a "tout le monde" Signal(SIGCHLD, DeroutFinFils); // pour ne pas creer de zombies int pipeCaH [2]; // C ==> H comment afficher l'heure int pipeHaC [2]; // H ==> C l'heure proprement dite Pipe (pipeCaH); Pipe (pipeHaC); ::pid_t procHpid, procMpid, procSpid; // l'ordre dans lequel on fork()e pour creer H, M et S // compte, car ainsi S connaitra procMpid et M procHpid // pour l'envoi des signaux requis if((procHpid = Fork())) { if((procMpid = Fork())) { if((procSpid = Fork())) { // - - - - proc C - - - - cerr << "Processus C avec fils H(" << procHpid << "), M(" << procMpid << ") et S(" << procSpid << ")\n"; Signal(SIGQUIT, DeroutQUIT); Close(pipeCaH[0]); Close(pipeHaC[1]); while(true) { ::sigsuspend(&MasqueVide); if(qAffiche) { qAffiche = 0; int afficheChoix(1); cout << "Choix ? "; cin >> afficheChoix; Write(pipeCaH[1],&afficheChoix,sizeof(int)); Kill(procHpid,SIGUSR1); switch(afficheChoix) { case 1: { int heure; Read(pipeHaC[0],&heure,sizeof(int)); cout << "Il est " << heure << " heures.\n"; break; } case 2: { int taille; Read(pipeHaC[0],&taille,sizeof(int)); char buff[taille+1]; buff[Read(pipeHaC[0],buff,taille)] = '\0'; cout << "Il est " << buff << " heures.\n"; break; } default: cerr << "Processus S " << getpid() << "Valeur incorrecte du choix " << afficheChoix << "\n"; } } } return(0); } // - - - - fin proc C - - - - else { // - - - - proc S - - - - Sigprocmask(SIG_BLOCK, &MasqueALRM, 0); Signal(SIGALRM, DeroutALRMS); while(true) { alarm(1); //cerr << "Processus S " << getpid() << ": " << secondes << "\n"; ::sigsuspend(&MasqueVide); if(secondes > 59) { secondes = 0; Kill(procMpid,SIGUSR1); } } return(0); } // - - - - fin proc S - - - - } else { // - - - - proc M - - - - Signal(SIGUSR1, DeroutUSR1M); while(true) { cerr << "Processus M " << getpid() << ": " << minutes << "\n"; ::sigsuspend(&MasqueVide); if(minutes > 59) { minutes = 0; Kill(procHpid,SIGUSR2); } } return(0); } // - - - - fin proc M - - - - } else { // - - - - proc H - - - - Signal(SIGUSR2, DeroutUSR2H); Signal(SIGUSR1, DeroutUSR1H); Close(pipeCaH[1]); Close(pipeHaC[0]); while(true) { cerr << "Processus H " << getpid() << ": " << heures << "\n"; ::sigsuspend(&MasqueVide); if(heures > 23) { heures = 0; } if(qAffiche) { qAffiche = 0; // remise a zero pour une prochaine requete int commentAfficher (0); cerr << "Processus H " << getpid() << ": reception requete affichage.\n"; if(sizeof(int) != Read(pipeCaH[0],&commentAfficher,sizeof(int))) { cerr << "Processus H requete de C mal comprise, sera ignoree.\n"; } cerr << "Processus H " << getpid() << ": affichage" << commentAfficher << ".\n"; switch(commentAfficher) { case 1: { // entier int heure(heures); Write(pipeHaC[1],&heure,sizeof(int)); break; } case 2: { // caracteres ostringstream buffStr; buffStr << heures; const int taille (buffStr . str() . size()); Write(pipeHaC[1], &taille, sizeof(int)); Write(pipeHaC[1], buffStr . str() . c_str(), taille); } break; default: cerr << "Processus H requete de C mal comprise (" << commentAfficher << "), sera ignoree.\n"; } } } return(0); } // - - - - fin proc H - - - - return 0; } catch (const CExc & Exc) { cerr <