Voici le code de la commande :
#include <sys/times.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #define CLK_TCK sysconf(_SC_CLK_TCK) int main(int argc,char *argv[]) { struct tms temps; switch(fork()) { case -1: fprintf(stderr,"%s: cannot fork\n",argv[0]); exit(EXIT_FAILURE); case 0: argv++; execvp(*argv,argv); exit(EXIT_FAILURE); default: wait(NULL); times(&temps); printf("Temps utilisateur: %.2f s.\n",((float)temps.tms_cutime)/CLK_TCK); printf("Temps système : %.2f s.\n",((float)temps.tms_cstime)/CLK_TCK); exit(EXIT_SUCCESS); } }
Il y manque une gestion correcte des signaux d'interruption et du code de retour de la commande, mais l'essentiel est là.
sigaddset(&(action.sa_mask),SIGUSR2); sigaddset(&(action.sa_mask),SIGQUIT);
Pour SIGUSR2 ajouter :
sigaddset(&(action.sa_mask),SIGUSR1); sigaddset(&(action.sa_mask),SIGQUIT);
Pour SIGQUIT ajouter :
sigaddset(&(action.sa_mask),SIGUSR1); sigaddset(&(action.sa_mask),SIGUSR2);
Rappellons qu'un signal est bloqué lors de sa délivrance.
Le programme suivant est une solution possible :
#include <sys/types.h> #include <sys/wait.h> #include <stdlib.h> #include <unistd.h> #include <stdio.h> int main(int argc,char *argv[]) { int tube[2], somme, i, j, status; char *mot; char nombre[10]; if (argc<3) { fprintf(stderr,"usage: %s <mot> fichier [... fichier]\n",*argv); exit(EXIT_FAILURE); } mot = argv[1]; if (pipe(tube)==-1) { fprintf(stderr,"%s: impossible de créer un tube\n",*argv); exit(EXIT_FAILURE); } for (i=2; i<argc; i++) { /* un processus par fichier */ switch(fork()) { case -1: /* c'est raté on abandonne */ fprintf(stderr,"%s: fork() impossible\n",*argv); close(tube[0]); while (wait(NULL)!=-1); /* on supprime les zombis et attends la mort des fils existant */ exit(EXIT_FAILURE); case 0: close(tube[0]); close(STDOUT_FILENO); dup(tube[1]); close(tube[1]); execlp("grep","grep","-c",argv[1],argv[i],NULL); exit(3); /* grep renvoie 0: ok, 1: rien trouvé, 2: mauvais fichier */ default: break; } } close(tube[1]); somme = 0; for (i=2; i<argc; i++) { /* on collecte les résultats */ wait(&status); if (WIFEXITED(status)) { switch(WEXITSTATUS(status)) { case 0: /* grep a trouvé quelque chose, résultat dans le tube */ case 1: /* grep n'a rien trouvé mais envoie 0 dans le tube */ j = 0; do { if (read(tube[0],nombre+j,sizeof(char))!=sizeof(char)) { fprintf(stderr,"%s: fin de lecture prematurée\n"); while (wait(NULL)!=-1); /* zombis, fils...*/M close(tube[0]); exit(EXIT_FAILURE); } } while (nombre[j++]!='\n'); nombre[j-1] = '\0'; somme += atoi(nombre); break; case 2: /* mauvais fichier */ case 3: /* exec raté */ default: /* ??? */ break; } } } close(tube[0]); printf("Nombre de \"%s\" = %d\n",argv[1],somme); exit(EXIT_SUCCESS); }
Une autre méthode serait de capter le signal SIGCHLD afin d'effectuer les lectures des résultats au plus tôt, alors que dans la solution présentée les lectures ne peuvent se faire qu'après la création de tous les processus fils (ce qui peut se révéler assez long. Essayez comptemot int /usr/include/*.h)...
Voici une solution possible :
#if !defined(_XOPEN_SOURCE) && (!defined(_POSIX_C_SOURCE) || _POSIX_C_SOURCE<=2) #error compilez en mode POSIX.4 ou XPG4 #error XPG4: -D_XOPEN_SOURCE #error POSIX.4: -D_POSIX_C_SOURCE=199309L -lrt #endif #ifdef _XOPEN_SOURCE #include <sys/ipc.h> #include <sys/shm.h> #include <sys/sem.h> #endif #ifdef _POSIX_C_SOURCE #include <semaphore.h> #include <sys/mman.h> #endif #include <sys/types.h> #include <sys/wait.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <unistd.h> #include <stdio.h> #ifdef _XOPEN_SOURCE static int nsems, semdesc; #endif #ifdef _POSIX_C_SOURCE sem_t semdesc; #endif volatile int *table; int incr(int position) { #ifdef _XOPEN_SOURCE struct sembuf p, v; p.sem_num = position%nsems; p.sem_op = -1; p.sem_flg = 0; v.sem_num = position%nsems; v.sem_op = +1; v.sem_flg = 0; semop(semdesc,&p,1); #endif #ifdef _POSIX_C_SOURCE sem_wait(&semdesc); #endif table[position]++; #ifdef _XOPEN_SOURCE semop(semdesc,&v,1); #endif #ifdef _POSIX_C_SOURCE sem_post(&semdesc); #endif return 0; } int comptelettre(const char *fichier) { int d; char c; d = open(fichier,O_RDONLY); if (d==-1) return EXIT_FAILURE; while (read(d,&c,sizeof(char))==sizeof(char)) { if (c>='a' && c<='z') { incr(c-'a'); continue; } if (c>='A' && c<='Z') { incr(c-'A'); continue; } } close(d); return EXIT_SUCCESS; } #ifndef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) #endif int main(int argc,char *argv[]) { int memdesc; int i, status, retour; int valeur; if (argc<2) { fprintf(stderr,"usage: %s fichier [... fichier]\n",*argv); exit(EXIT_FAILURE); } #ifdef _XOPEN_SOURCE memdesc = shmget(IPC_PRIVATE,26*sizeof(int),IPC_CREAT|0600); if (memdesc==-1) { fprintf(stderr,"%s: impossible de créer un segment de mémoire\n",*argv); exit(EXIT_FAILURE); } table = shmat(memdesc,NULL,0); if (table==(int *)-1) { fprintf(stderr,"%s: impossible d'attacher le segment de mémoire\n",*argv); shmctl(memdesc,IPC_RMID,NULL); exit(EXIT_FAILURE); } nsems = 13; /* XPG4 défini comme valeur recommandée 25 !!! */ semdesc = semget(IPC_PRIVATE,nsems,IPC_CREAT|0600); if (semdesc==-1) { fprintf(stderr,"%s: impossible de créer les sémaphores\n",*argv); shmdt((void *)table); shmctl(memdesc,IPC_RMID,NULL); exit(EXIT_FAILURE); } valeur = 1; for (i=0; i<nsems; i++) { semctl(semdesc,i,SETVAL,&valeur); } #endif #ifdef _POSIX_C_SOURCE memdesc = shm_open("/shmmem",O_RDWR|O_CREAT,S_IRUSR|S_IWUSR); if (memdesc==-1) { perror("coucou"); fprintf(stderr,"%s: impossible de créer un segment de mémoire\n",*argv); exit(EXIT_FAILURE); } if (ftruncate(memdesc,26*sizeof(int))==-1) { fprintf(stderr,"%s: impossible de créer la mémoire à la taille voulue\n", *argv); close(memdesc); shm_unlink("/shmmem"); exit(EXIT_FAILURE); } table = mmap(NULL,26*sizeof(int),PROT_READ|PROT_WRITE, MAP_SHARED|MAP_NORESERVE,memdesc,0); if (table==MAP_FAILED) { fprintf(stderr,"%s: impossible d'attacher le segment de mémoire\n",*argv); close(memdesc); shm_unlink("/shmmem"); exit(EXIT_FAILURE); } if (sem_init(&semdesc,1,1)==-1) { fprintf(stderr,"%s: impossible d'obtenir un sémaphore\n",*argv); munmap((void *)table,26*sizeof(int)); close(memdesc); shm_unlink("/shmmem"); exit(EXIT_FAILURE); } #endif for (i=1; i<argc; i++) { switch(fork()) { case -1: fprintf(stderr,"%s: fork() impossible\n",*argv); #ifdef _XOPEN_SOURCE shmdt((void *)table); shmctl(memdesc,IPC_RMID,NULL); semctl(semdesc,IPC_RMID,NULL); #endif #ifdef _POSIX_C_SOURCE munmap((void *)table,26*sizeof(int)); close(memdesc); shm_unlink("/shmmem"); #endif while (wait(NULL)!=-1); exit(EXIT_FAILURE); case 0: retour = comptelettre(argv[i]); #ifdef _XOPEN_SOURCE shmdt((void *)table); #endif #ifdef _POSIX_C_SOURCE munmap((void *)table,26*sizeof(int)); close(memdesc); #endif exit(retour); default: break; } } for (i=1; i<argc; i++) { wait(&status); } for (i=0; i<26; i++) { printf("Lettre '%c' en nombre %d\n",i+'a',table[i]); } #ifdef _XOPEN_SOURCE shmdt((void *)table); shmctl(memdesc,IPC_RMID,NULL); semctl(semdesc,IPC_RMID,NULL); #endif #ifdef _POSIX_C_SOURCE munmap((void *)table,26*sizeof(int)); close(memdesc); shm_unlink("/shmmem"); sem_destroy(&semdesc); #endif exit(EXIT_SUCCESS); }L'auteur de cette page est : Jean-Baptiste Yunès