--- rpl/src/interruptions.c 2010/08/18 12:56:55 1.32 +++ rpl/src/interruptions.c 2010/08/22 16:38:36 1.33 @@ -1726,21 +1726,26 @@ deverrouillage_gestionnaire_signaux() #ifdef _BROKEN_SIGINFO +// Remplacer les mutexes par des sémaphores SysV + +#define longueur_queue 256 +#define nombre_queues 13 + static int *fifos; static int segment; -static int segment_mutexes; -static int longueur_queue; -static int nombre_queues; - -static pthread_mutex_t *mutexes; +static sem_t *semaphores[nombre_queues]; +static sem_t *semaphore_global; +#ifdef IPCS_SYSV static unsigned char *chemin = NULL; +#endif unsigned char * nom_segment(unsigned char *chemin, pid_t pid) { unsigned char *fichier; +# ifdef IPCS_SYSV if ((fichier = malloc((strlen(chemin) + 1 + 256 + 1) * sizeof(unsigned char))) == NULL) { @@ -1748,34 +1753,40 @@ nom_segment(unsigned char *chemin, pid_t } sprintf(fichier, "%s/RPL-SIGQUEUES-%d", chemin, (int) pid); +# else + if ((fichier = malloc((1 + 256 + 1) * + sizeof(unsigned char))) == NULL) + { + return(NULL); + } + + sprintf(fichier, "/RPL-SIGQUEUES-%d", (int) pid); +# endif return(fichier); } unsigned char * -nom_segment_mutexes(unsigned char *chemin, pid_t pid) +nom_semaphore(pid_t pid, int queue) { unsigned char *fichier; - if ((fichier = malloc((strlen(chemin) + 1 + 256 + 1) * - sizeof(unsigned char))) == NULL) + if ((fichier = malloc((256 + 1) * sizeof(unsigned char))) == NULL) { return(NULL); } - sprintf(fichier, "%s/RPL-SIGMUTEXES-%d", chemin, (int) pid); + sprintf(fichier, "/RPL-SIGESMAPHORES-%d-%d", (int) pid, queue); return(fichier); } -int +inline int queue_de_signal(int signal) { switch(signal) { case SIGINT: - BUG(1, uprintf("SIGINT is not queued as it does not " - "come from program itself !\n")); return(0); case SIGTSTP: return(1); @@ -1797,6 +1808,10 @@ queue_de_signal(int signal) return(9); case SIGFABORT: return(10); + case SIGSEGV: + return(11); + case SIGBUS: + return(12); } return(-1); @@ -1805,22 +1820,23 @@ queue_de_signal(int signal) void creation_fifos_signaux(struct_processus *s_etat_processus) { + /* + * Signaux utilisés + * SIGINT, SIGTSTP, SIGCONT, SIGURG, SIGPIPE, SIGALRM, SIGFSTOP, + * SIGSTART, SIGINJECT, SIGABORT, SIGFABORT + */ + +# ifndef IPCS_SYSV // POSIX +# else // SystemV + file *desc; int i; key_t clef; - pthread_mutexattr_t attributs_mutex; - unsigned char *nom; - /* - * Signaux utilisés - * SIGINT, SIGTSTP, SIGCONT, SIGURG, SIGPIPE, SIGALRM, SIGFSTOP, - * SIGSTART, SIGINJECT, SIGABORT, SIGFABORT - */ - // Création d'un segment de données associé au PID du processus courant chemin = (*s_etat_processus).chemin_fichiers_temporaires; @@ -1832,19 +1848,6 @@ creation_fifos_signaux(struct_processus return; } - /* - * Structure d'une queue - * 0 : pointeur en lecture sur le premier emplacement libre (int) - * 1 : pointeur en écriture sur le premier emplacement à lire (int) - * 2 : longueur de la queue (int) - * 3 : éléments restants (int) - * 4 à 4 + (2) : queue (int) - * 5 : mutex - */ - - nombre_queues = 11; - longueur_queue = 256; - if ((desc = fopen(nom, "w")) == NULL) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; @@ -1873,10 +1876,27 @@ creation_fifos_signaux(struct_processus if (((void *) fifos) == ((void *) -1)) { + if (shmctl(segment, IPC_RMID, 0) == -1) + { + (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; + return; + } + (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } +# endif + + /* + * Structure d'une queue + * 0 : pointeur en lecture sur le premier emplacement libre (int) + * 1 : pointeur en écriture sur le premier emplacement à lire (int) + * 2 : longueur de la queue (int) + * 3 : éléments restants (int) + * 4 à 4 + (2) : queue (int) + */ + for(i = 0; i < nombre_queues; i++) { fifos[(i * (longueur_queue + 4))] = 0; @@ -1885,75 +1905,74 @@ creation_fifos_signaux(struct_processus fifos[(i * (longueur_queue + 4)) + 3] = longueur_queue; } - if ((nom = nom_segment_mutexes((*s_etat_processus) - .chemin_fichiers_temporaires, getpid())) == NULL) - { - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; - return; - } + // Création des sémaphores : un sémaphore par signal et par queue + // plus un sémaphore global pour tous les threads. - if ((desc = fopen(nom, "w")) == NULL) + for(i = 0; i < nombre_queues; i++) { - (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; - return; - } + if ((nom = nom_semaphore(getpid(), i)) == NULL) + { + (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; + return; + } - fclose(desc); + // Le sémaphore est créé en écrasant si nécessaire un sémaphore + // préexistant. Comme le nom du sémaphore contient l'identifiant du + // processus, il est anormal d'avoir un sémaphore de même nom + // préexistant. - if ((clef = ftok(nom, 1)) == -1) - { - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; - return; + if ((semaphores[i] = sem_open(nom, O_CREAT, S_IRUSR | S_IWUSR, + 1)) == SEM_FAILED) + { + (*s_etat_processus).erreur_systeme = d_es_semaphore; + return; + } + + free(nom); } - free(nom); - if ((segment_mutexes = shmget(clef, - nombre_queues * sizeof(pthread_mutex_t), - IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR)) == -1) + if ((nom = nom_semaphore(getpid(), nombre_queues)) == NULL) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } - mutexes = shmat(segment_mutexes, NULL, 0); - - if (((void *) mutexes) == ((void *) -1)) + if ((semaphore_global = sem_open(nom, O_CREAT, S_IRUSR | S_IWUSR, + 1)) == SEM_FAILED) { - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; + (*s_etat_processus).erreur_systeme = d_es_semaphore; return; } - /* - * Création et initialisation d'un mutex par queue. Ce mutex n'est pas - * dans le premier segment parce qu'il peut y avoir des problèmes - * d'alignements sur certaines architectures. - */ - - pthread_mutexattr_init(&attributs_mutex); - pthread_mutexattr_settype(&attributs_mutex, PTHREAD_MUTEX_RECURSIVE); - - for(i = 0; i < nombre_queues; i++) - { - pthread_mutex_init(&(mutexes[i]), &attributs_mutex); - } + free(nom); - pthread_mutexattr_destroy(&attributs_mutex); return; } void liberation_fifos_signaux(struct_processus *s_etat_processus) { + int i; + if (shmdt(fifos) == -1) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } - if (shmdt(mutexes) == -1) + for(i = 0; i < nombre_queues; i++) { - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; + if (sem_close(semaphores[i]) != 0) + { + (*s_etat_processus).erreur_systeme = d_es_semaphore; + return; + } + } + + if (sem_close(semaphore_global) != 0) + { + (*s_etat_processus).erreur_systeme = d_es_semaphore; return; } @@ -1979,41 +1998,45 @@ destruction_fifos_signaux(struct_process return; } - for(i = 0; i < nombre_queues; i++) - { - pthread_mutex_destroy(&(mutexes[i])); - } - - if (shmdt(mutexes) == -1) + if ((nom = nom_segment((*s_etat_processus).chemin_fichiers_temporaires, + getpid())) == NULL) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } - if (shmctl(segment_mutexes, IPC_RMID, 0) == -1) + unlink(nom); + free(nom); + + for(i = 0; i < nombre_queues; i++) { - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; - return; + if ((nom = nom_semaphore(getpid(), i)) == NULL) + { + (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; + return; + } + + if (sem_unlink(nom) != 0) + { + (*s_etat_processus).erreur_systeme = d_es_semaphore; + return; + } + + free(nom); } - if ((nom = nom_segment_mutexes((*s_etat_processus) - .chemin_fichiers_temporaires, getpid())) == NULL) + if ((nom = nom_semaphore(getpid(), nombre_queues)) == NULL) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } - unlink(nom); - free(nom); - - if ((nom = nom_segment((*s_etat_processus).chemin_fichiers_temporaires, - getpid())) == NULL) + if (sem_unlink(nom) != 0) { - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; + (*s_etat_processus).erreur_systeme = d_es_semaphore; return; } - unlink(nom); free(nom); return; @@ -2022,6 +2045,12 @@ destruction_fifos_signaux(struct_process int queue_in(pid_t pid, int signal) { +#undef printf +// Transformer ce truc en POSIX ! On ne fait du SysV que si on n'a pas le choix + +# ifndef IPCS_SYSV +# else // Traitement à l'aide d'IPCS SystemV + int *base; int *buffer; int *projection_fifos; @@ -2030,7 +2059,9 @@ queue_in(pid_t pid, int signal) key_t clef; - pthread_mutex_t *projection_mutexes; + sem_t *semaphore; + + struct stat s_stat; unsigned char *nom; @@ -2043,72 +2074,99 @@ queue_in(pid_t pid, int signal) return(-1); } + // Dans le cas de SIGSTART, premier signal envoyé à un processus fils, + // il convient d'attendre que le fichier support soit effectivement + // accessible. Dans tous les autres cas, ce fichier doit exister. S'il + // n'existe plus, le processus associé n'existe plus. + + if (signal == SIGSTART) + { + // On attend que le fichier sois présent + + while(stat(nom, &s_stat) != 0); + } + if ((clef = ftok(nom, 1)) == -1) { - free(nom); return(-1); } free(nom); - while((identifiant = shmget(clef, - nombre_queues * (longueur_queue + 4) * sizeof(int), - S_IRUSR | S_IWUSR)) == -1); + if (signal == SIGSTART) + { + while((identifiant = shmget(clef, + nombre_queues * (longueur_queue + 4) * sizeof(int), + S_IRUSR | S_IWUSR)) == -1); + } + else + { + if ((identifiant = shmget(clef, + nombre_queues * (longueur_queue + 4) * sizeof(int), + S_IRUSR | S_IWUSR)) == -1) + { + return(-1); + } + } projection_fifos = shmat(identifiant, NULL, 0); - if ((nom = nom_segment_mutexes(chemin, pid)) == NULL) + if (((void *) projection_fifos) == ((void *) -1)) { return(-1); } - if ((clef = ftok(nom, 1)) == -1) + if ((nom = nom_semaphore(pid, queue)) == NULL) { - free(nom); + shmdt(projection_fifos); return(-1); } - free(nom); - - while((identifiant = shmget(clef, - nombre_queues * sizeof(pthread_mutex_t), - S_IRUSR | S_IWUSR)) == -1); + while((semaphore = sem_open(nom, 0)) == SEM_FAILED); - projection_mutexes = shmat(identifiant, NULL, 0); - - if (pthread_mutex_lock(&(projection_mutexes[queue])) != 0) + if (sem_wait(semaphore) != 0) { + shmdt(projection_fifos); return(-1); } + // Il ne faut pas empiler plusieurs SIGSTART car SIGSTART peut provenir + // de l'instruction SWI. Plusieurs threads peuvent interrompre de façon + // asynchrone le processus père durant une phase de signaux masqués. + base = &(projection_fifos[(longueur_queue + 4) * queue]); buffer = &(base[4]); - // base[1] contient le prochain élément à écrire - buffer[base[1]++] = (int) pid; - base[1] %= base[2]; + // base[3] contient le nombre d'éléments restants - // base[3] contient le nombre d'éléments non lus if (base[3] <= 0) { - pthread_mutex_unlock(&(projection_mutexes[queue])); - shmdt(projection_mutexes); + sem_post(semaphore); + sem_close(semaphore); shmdt(projection_fifos); return(-1); } base[3]--; - if (pthread_mutex_unlock(&(projection_mutexes[queue])) != 0) + // base[1] contient le prochain élément à écrire + buffer[base[1]++] = (int) pid; + base[1] %= base[2]; + + if (sem_post(semaphore) != 0) { - shmdt(projection_mutexes); shmdt(projection_fifos); + sem_close(semaphore); return(-1); } + sem_close(semaphore); + // Fermeture des projections - shmdt(projection_mutexes); shmdt(projection_fifos); + +# endif + return(0); } @@ -2125,25 +2183,42 @@ origine_signal(int signal) BUG(queue == -1, uprintf("[%d] Unknown signal %d in this context\n", (int) getpid(), signal)); - if (pthread_mutex_lock(&(mutexes[queue])) != 0) + if (sem_wait(semaphores[queue]) != 0) { return(-1); } - base = &(fifos[(longueur_queue + 4) * queue]); - buffer = &(base[4]); - pid = buffer[base[0]++]; - base[0] %= base[2]; - base[3]++; + // Le signal SIGCONT peut être envoyé de façon totalement asynchrone. + // Il peut y avoir plus de signaux envoyés que d'interruptions traitées. + // Il convient donc de rectifier la queue lors du traitement de + // l'interruption correspondante. Le gestionnaire étant installé sans + // l'option NODEFER, la queue reste cohérente. + + if (signal == SIGCONT) + { + base = &(fifos[(longueur_queue + 4) * queue]); + buffer = &(base[4]); + base[0] = (base[1] - 1) % base[2]; + pid = buffer[base[0]++]; + base[3] = base[2]; + } + else + { + base = &(fifos[(longueur_queue + 4) * queue]); + buffer = &(base[4]); + pid = buffer[base[0]++]; + base[0] %= base[2]; + base[3]++; + } if (base[3] > base[2]) { - pthread_mutex_unlock(&(mutexes[queue])); + sem_post(semaphores[queue]); return(-1); } - if (pthread_mutex_unlock(&(mutexes[queue])) != 0) + + if (sem_post(semaphores[queue]) != 0) { - perror("unlock"); return(-1); } @@ -2152,6 +2227,10 @@ origine_signal(int signal) #endif +#ifdef printf +# undef printf +#endif + void interruption1(SIGHANDLER_ARGS) { @@ -2883,37 +2962,107 @@ traitement_exceptions_gsl(const char *re #undef pthread_kill int -rpl_kill(pid_t pid, int signal) +kill_broken_siginfo(pid_t pid, int signal) { + int ios; + + sem_t *semaphore; + + unsigned char *nom; + /* * Lorsqu'on veut interrompre le processus pid, on ouvre le segment * correspondant au processus en question et ou ajoute le pid dans la * queue. + * + * Le sémaphore global à tous les threads d'un même processus sert + * à garantir que les signaux seront traités dans l'ordre de ce qui est + * effectivement mis dans la queue. */ + // Sémaphore acquis + + if ((nom = nom_semaphore(getpid(), nombre_queues)) == NULL) + { + return(-1); + } + + if ((semaphore = sem_open(nom, 0)) == SEM_FAILED) + { + free(nom); + return(-1); + } + + free(nom); + + if (sem_wait(semaphore) == -1) + { + return(-1); + } + if ((signal != 0) && (signal != SIGINT)) { if (queue_in(pid, signal) != 0) { + sem_post(semaphore); + sem_close(semaphore); return(-1); } } - return(kill(pid, signal)); + ios = kill(pid, signal); + + // Sémaphore relâché + + sem_post(semaphore); + sem_close(semaphore); + + return(ios); } int -rpl_pthread_kill(pthread_t tid, int signal) +pthread_kill_broken_siginfo(pthread_t tid, int signal) { + int ios; + + sem_t *semaphore; + + unsigned char *nom; + + if ((nom = nom_semaphore(getpid(), nombre_queues)) == NULL) + { + return(-1); + } + + if ((semaphore = sem_open(nom, 0)) == SEM_FAILED) + { + free(nom); + return(-1); + } + + free(nom); + + if (sem_wait(semaphore) == -1) + { + return(-1); + } + if ((signal != 0) && (signal != SIGINT)) { if (queue_in(getpid(), signal) != 0) { + sem_post(semaphore); + sem_close(semaphore); return(-1); } } - return(pthread_kill(tid, signal)); + ios = pthread_kill(tid, signal); + + sem_post(semaphore); + sem_close(semaphore); + + return(ios); } #endif