#include #include #include #include #include #include #include // pour les msg d'erreur uniquement #include // C norme 2011 #include #include #include #include #define CODE_ERREUR 255 #define BUFFER_SIZE 2048 int dflag = 0; int vflag = 0; /****************************************************************************** * Gestion des erreurs */ char *prog; // nom du programme pour les erreurs noreturn void raler (int syserr, const char *fmt, ...) { va_list ap; va_start (ap, fmt); fprintf (stderr, "%s: ", prog); vfprintf (stderr, fmt, ap); fprintf (stderr, "\n"); va_end (ap); if (syserr) perror (""); exit (CODE_ERREUR); } noreturn void usage (void) { fprintf (stderr, "usage: %s [-d|-v] [fichier-spec]\n", prog); exit (1); } /****************************************************************************** * Transformation de la spécification en structure d'arbre * => utiliser la fonction analyser_spec() */ struct sommet { int val; // étiquette du sommet struct sommet *frere_suivant; // liste des frères struct sommet *premier_fils; // premier des fils /* * Ce dernier champ (dernier_fils) n'est utilisé que pendant la * construction de l'arbre, pour insérer en queue et ainsi * respecter l'ordre des processus dans la spécification. */ struct sommet *dernier_fils; // pour insertion en queue }; /* * Fonction interne pour l'analyse de la spécification : analyse une * ligne de la spécification (la ligne pointée par *spec), et * retourne la profondeur, la valeur, et la position suivante (via * *spec) et un code pour dire si on a rencontré une erreur, une fin * de spéc ou si tout baigne. */ enum ret_al { AL_ERR, AL_FIN, AL_OK }; // retour de analyser_ligne enum ret_al analyser_ligne (char **spec, int *prof, int *val) { *prof = *val = 0; // mettre les compteurs à 0 if (**spec == '\0') // spec terminée return AL_FIN; /* * Compter les espaces pour avoir la profondeur */ while (**spec == ' ') { (*spec)++; (*prof)++; } /* * Récupérer la valeur */ char *debut = *spec; // vérifier au moins un chiffre while (isdigit (**spec)) { *val = *val * 10 + (**spec - '0'); (*spec)++; } if (debut == *spec) // on n'a pas avancé => pb return AL_ERR; /* * Vérifier qu'on est bien à la fin d'une ligne */ if (**spec != '\n') return AL_ERR; (*spec)++; // passer au sommet suivant return AL_OK; } struct sommet *creer_sommet (int val) { struct sommet *s; s = malloc (sizeof *s); if (s == NULL) raler(1, "cannot malloc %d bytes", sizeof *s); s->frere_suivant = NULL; s->premier_fils = NULL; s->dernier_fils = NULL; s->val = val; return s; } struct sommet *analyser_spec_profondeur(int *numl, char **spec, int prof) { char *nspec; int nprof, val; struct sommet *s; enum ret_al r; /* * Analyser la racine du sous-arbre */ nspec = *spec; r = analyser_ligne(&nspec, &nprof, &val); switch (r) { case AL_ERR : raler (0, "cannot parse spec at line %d", *numl); case AL_FIN : return NULL; case AL_OK : // on continue en séquence break; default : // programmation défensive raler (0, "internal error at line %d", *numl); } if (nprof != prof) raler (0, "unexpected depth (%d) at line %d", nprof, *numl); s = creer_sommet (val); *spec = nspec; (*numl)++; /* * Chercher les fils directs de la racine */ while ((r= analyser_ligne(&nspec, &nprof, &val)) == AL_OK && nprof > prof) { struct sommet *f; // sous-arbre fils trouvé nspec = *spec; f = analyser_spec_profondeur (numl, &nspec, prof + 1); // Est-ce le premier fils ou bien y-a-t'il déjà au moins un ? if (s->dernier_fils == NULL) { s->premier_fils = s->dernier_fils = f; } else { s->dernier_fils->frere_suivant = f; s->dernier_fils = f; } *spec = nspec; } if (r == AL_ERR) raler(0, "cannot parse spec at line %d", *numl); return s; } struct sommet *analyser_spec (char *spec) { struct sommet *s; // arbre obtenu int numl; // numéro de ligne pour msg err numl = 1; s = analyser_spec_profondeur (&numl, &spec, 0); if (*spec != '\0') // est-on bien à la fin ? raler (0, "invalid spec at line %d", numl); return s; } void readfile(int fd, char* buff) { int nb_car; int count = 0; printf("yo %d \n", getpid()); while ((nb_car = read(fd, &buff[count], 2048)) != 0 && ) { if (nb_car == -1) raler (1, "cannot read file"); count += nb_car; if (realloc(buff, sizeof(buff) + 2048) == NULL) raler (1, "cannot realloc"); } } int cfork (struct sommet* s) { pid_t f; unsigned int count = 0; int w, status, exits = 0; struct sommet* current; unsigned int i; if (s == NULL) return 255; current = s->premier_fils; while (current != NULL) { f = fork(); switch(f) { case -1: { fprintf(stderr, "buggggggg"); exit(255); break; } case 0: { exit(cfork(current)); break; } default: { if (vflag) printf("pid %d -> %d\n", getpid(), f); break; } } current = current->frere_suivant; count++; } if (vflag) printf("pid %d : attente %d ms\n", getpid(), s->val); usleep(1000 * s->val); for (i = 0; i < count; i++) { if (wait(&status) == -1) raler(0, "wait fail"); if (WIFEXITED(status) && (w = WEXITSTATUS(status)) < 255) { exits += 1 + w; } else { exit(255); } } if (vflag) printf("pid %d <- %d processus\n", getpid(), exits); free(s); return exits; } int main(int argc, char** argv) { int fd; char* buff; char c; struct sommet* debut; while ((c = getopt (argc, argv, "dv")) != -1) { switch (c) { case 'd': dflag = 1; break; case 'v': vflag = 1; break; default: usage(); } } buff = malloc(2048); if (argc-optind>1 || optind>3){ usage(); } else if (argc==optind){ fd = 0; } else { fd = open(argv[optind], O_RDONLY); } if (fd == -1) raler (1, "cannot open"); readfile(fd, buff); if (close (fd) == -1) raler (1, "cannot close %s", "plop"); if (dflag) printf("%s", buff); debut = analyser_spec(buff); free(buff); exit(cfork(debut) + 1); return EXIT_SUCCESS; }