--- rpl/src/interruptions.c 2010/08/17 14:15:20 1.31 +++ rpl/src/interruptions.c 2011/09/10 20:45:06 1.66 @@ -1,7 +1,7 @@ /* ================================================================================ - RPL/2 (R) version 4.0.18 - Copyright (C) 1989-2010 Dr. BERTRAND Joël + RPL/2 (R) version 4.1.3 + Copyright (C) 1989-2011 Dr. BERTRAND Joël This file is part of RPL/2. @@ -183,9 +183,9 @@ insertion_thread_surveillance(struct_pro } } - pthread_mutex_lock(&((*s_argument_thread).mutex)); + pthread_mutex_lock(&((*s_argument_thread).mutex_nombre_references)); (*s_argument_thread).nombre_references++; - pthread_mutex_unlock(&((*s_argument_thread).mutex)); + pthread_mutex_unlock(&((*s_argument_thread).mutex_nombre_references)); (*l_nouvel_objet).suivant = liste_threads_surveillance; (*l_nouvel_objet).donnee = (void *) s_argument_thread; @@ -378,7 +378,8 @@ retrait_thread_surveillance(struct_proce (*l_element_precedent).suivant = (*l_element_courant).suivant; } - if (pthread_mutex_lock(&((*s_argument_thread).mutex)) != 0) + if (pthread_mutex_lock(&((*s_argument_thread).mutex_nombre_references)) + != 0) { # ifndef SEMAPHORES_NOMMES sem_post(&semaphore_liste_threads); @@ -400,7 +401,8 @@ retrait_thread_surveillance(struct_proce if ((*s_argument_thread).nombre_references == 0) { - if (pthread_mutex_unlock(&((*s_argument_thread).mutex)) != 0) + if (pthread_mutex_unlock(&((*s_argument_thread) + .mutex_nombre_references)) != 0) { # ifndef SEMAPHORES_NOMMES sem_post(&semaphore_liste_threads); @@ -415,11 +417,13 @@ retrait_thread_surveillance(struct_proce } pthread_mutex_destroy(&((*s_argument_thread).mutex)); + pthread_mutex_destroy(&((*s_argument_thread).mutex_nombre_references)); free(s_argument_thread); } else { - if (pthread_mutex_unlock(&((*s_argument_thread).mutex)) != 0) + if (pthread_mutex_unlock(&((*s_argument_thread) + .mutex_nombre_references)) != 0) { # ifndef SEMAPHORES_NOMMES sem_post(&semaphore_liste_threads); @@ -676,7 +680,8 @@ liberation_threads(struct_processus *s_e s_argument_thread = (struct_descripteur_thread *) (*((struct_liste_chainee *) element_courant)).donnee; - if (pthread_mutex_lock(&((*s_argument_thread).mutex)) != 0) + if (pthread_mutex_lock(&((*s_argument_thread) + .mutex_nombre_references)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; sem_post(&semaphore_liste_threads); @@ -700,8 +705,8 @@ liberation_threads(struct_processus *s_e close((*s_argument_thread) .pipe_nombre_interruptions_attente[0]); - if (pthread_mutex_unlock(&((*s_argument_thread).mutex)) - != 0) + if (pthread_mutex_unlock(&((*s_argument_thread) + .mutex_nombre_references)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; sem_post(&semaphore_liste_threads); @@ -709,6 +714,8 @@ liberation_threads(struct_processus *s_e } pthread_mutex_destroy(&((*s_argument_thread).mutex)); + pthread_mutex_destroy(&((*s_argument_thread) + .mutex_nombre_references)); if ((*s_argument_thread).processus_detache == d_faux) { @@ -723,8 +730,8 @@ liberation_threads(struct_processus *s_e } else { - if (pthread_mutex_unlock(&((*s_argument_thread).mutex)) - != 0) + if (pthread_mutex_unlock(&((*s_argument_thread) + .mutex_nombre_references)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; sem_post(&semaphore_liste_threads); @@ -796,25 +803,8 @@ liberation_threads(struct_processus *s_e } } - for(i = 0; i < (*s_etat_processus).nombre_variables; i++) - { - pthread_mutex_trylock(&((*(*s_etat_processus) - .s_liste_variables[i].objet).mutex)); - pthread_mutex_unlock(&((*(*s_etat_processus) - .s_liste_variables[i].objet).mutex)); - - // Les variables de niveau 0 sont des définitions qui - // ne sont pas copiées entre threads. - if ((*s_etat_processus).s_liste_variables[i].niveau > 0) - { - liberation(s_etat_processus, - (*s_etat_processus).s_liste_variables[i].objet); - } - - free((*s_etat_processus).s_liste_variables[i].nom); - } - - free((*s_etat_processus).s_liste_variables); + liberation_arbre_variables(s_etat_processus, + (*s_etat_processus).s_arbre_variables, d_faux); for(i = 0; i < (*s_etat_processus).nombre_variables_statiques; i++) { @@ -1328,6 +1318,7 @@ liberation_threads(struct_processus *s_e sem_destroy2((*s_etat_processus).semaphore_fork, sem_fork); # endif + liberation_contexte_cas(s_etat_processus); free(s_etat_processus); s_etat_processus = candidat; @@ -1350,7 +1341,8 @@ liberation_threads(struct_processus *s_e s_argument_thread = (struct_descripteur_thread *) (*l_element_courant).donnee; - if (pthread_mutex_lock(&((*s_argument_thread).mutex)) != 0) + if (pthread_mutex_lock(&((*s_argument_thread).mutex_nombre_references)) + != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; sem_post(&semaphore_liste_threads); @@ -1373,7 +1365,8 @@ liberation_threads(struct_processus *s_e close((*s_argument_thread).pipe_interruptions[0]); close((*s_argument_thread).pipe_nombre_interruptions_attente[0]); - if (pthread_mutex_unlock(&((*s_argument_thread).mutex)) != 0) + if (pthread_mutex_unlock(&((*s_argument_thread) + .mutex_nombre_references)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; sem_post(&semaphore_liste_threads); @@ -1381,6 +1374,8 @@ liberation_threads(struct_processus *s_e } pthread_mutex_destroy(&((*s_argument_thread).mutex)); + pthread_mutex_destroy(&((*s_argument_thread) + .mutex_nombre_references)); if ((*s_argument_thread).processus_detache == d_faux) { @@ -1394,7 +1389,8 @@ liberation_threads(struct_processus *s_e } else { - if (pthread_mutex_unlock(&((*s_argument_thread).mutex)) != 0) + if (pthread_mutex_unlock(&((*s_argument_thread) + .mutex_nombre_references)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; sem_post(&semaphore_liste_threads); @@ -1461,8 +1457,8 @@ recherche_thread(pid_t pid, pthread_t ti return(s_etat_processus); } -static logical1 -recherche_thread_principal(pid_t pid, pthread_t *thread) +static struct_processus * +recherche_thread_principal(pid_t pid) { volatile struct_liste_chainee_volatile *l_element_courant; @@ -1486,12 +1482,11 @@ recherche_thread_principal(pid_t pid, pt * Le processus n'existe plus. On ne distribue aucun signal. */ - return(d_faux); + return(NULL); } - (*thread) = (*((struct_thread *) (*l_element_courant).donnee)).tid; - - return(d_vrai); + return((*((struct_thread *) (*l_element_courant).donnee)) + .s_etat_processus); } @@ -1592,12 +1587,12 @@ verrouillage_gestionnaire_signaux() // ce que ce soit possible. # ifndef SEMAPHORES_NOMMES - while(sem_trywait(&semaphore_liste_threads) == -1) + while(sem_wait(&semaphore_liste_threads) == -1) # else - while(sem_trywait(semaphore_liste_threads) == -1) + while(sem_wait(semaphore_liste_threads) == -1) # endif { - if ((errno != EINTR) && (errno != EAGAIN)) + if (errno != EINTR) { pthread_sigmask(SIG_SETMASK, &oldset, NULL); @@ -1613,8 +1608,6 @@ verrouillage_gestionnaire_signaux() BUG(1, uprintf("Lock error !\n")); return; } - - sched_yield(); } } @@ -1724,460 +1717,107 @@ deverrouillage_gestionnaire_signaux() return; } -#ifdef _BROKEN_SIGINFO +#define test_signal(signal) \ + if (signal_test == SIGTEST) \ + { signal_test = initialisation_queue_interruptions(signal); return; } -static int *fifos; -static int segment; -static int segment_mutexes; -static int longueur_queue; -static int nombre_queues; - -static pthread_mutex_t *mutexes; - -static unsigned char *chemin = NULL; +/* + * Les interruptions sont mise en mémoire puis traitées depuis + * la fonction scrutation_injection() parce que les fonctions pthread*() + * ne sont pas 'async signal safe'. + * + * Les interruptions sont ainsi empilées dans un buffer circulaire puis + * traitées au fur et à mesure. + */ -unsigned char * -nom_segment(unsigned char *chemin, pid_t pid) +static struct { - unsigned char *fichier; +# define SIGNAL_MAX 32 +# define SIGNAL_BUFFER 1024 +# define ECRITURE 0 +# define LECTURE 1 - if ((fichier = malloc((strlen(chemin) + 1 + 256 + 1) * - sizeof(unsigned char))) == NULL) - { - return(NULL); - } + sig_atomic_t nombre_interruptions_en_queue; + int pointeur[SIGNAL_MAX][2]; - sprintf(fichier, "%s/RPL-SIGQUEUES-%d", chemin, (int) pid); + pid_t pid[SIGNAL_MAX][SIGNAL_BUFFER]; +} queue_interruptions; - return(fichier); -} +pthread_mutex_t mutex_signal = PTHREAD_MUTEX_INITIALIZER; -unsigned char * -nom_segment_mutexes(unsigned char *chemin, pid_t pid) +static inline int +initialisation_queue_interruptions(int signal) { - unsigned char *fichier; + int i; - if ((fichier = malloc((strlen(chemin) + 1 + 256 + 1) * - sizeof(unsigned char))) == NULL) + if (signal > SIGNAL_MAX) { - return(NULL); + return(signal + 1); } - sprintf(fichier, "%s/RPL-SIGMUTEXES-%d", chemin, (int) pid); - - return(fichier); -} + queue_interruptions.nombre_interruptions_en_queue = 0; -int -queue_de_signal(int signal) -{ - switch(signal) + for(i = 0; i < SIGNAL_MAX; i++) { - case SIGINT: - BUG(1, uprintf("SIGINT is not queued as it does not " - "come from program itself !\n")); - return(0); - case SIGTSTP: - return(1); - case SIGCONT: - return(2); - case SIGURG: - return(3); - case SIGPIPE: - return(4); - case SIGALRM: - return(5); - case SIGFSTOP: - return(6); - case SIGSTART: - return(7); - case SIGINJECT: - return(8); - case SIGABORT: - return(9); - case SIGFABORT: - return(10); + queue_interruptions.pointeur[i][ECRITURE] = 0; + queue_interruptions.pointeur[i][LECTURE] = 0; } - return(-1); + return(signal); } void -creation_fifos_signaux(struct_processus *s_etat_processus) +interruption1(SIGHANDLER_ARGS) { - 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; - - if ((nom = nom_segment((*s_etat_processus).chemin_fichiers_temporaires, - getpid())) == NULL) - { - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; - 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; - return; - } - - fclose(desc); - - if ((clef = ftok(nom, 1)) == -1) - { - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; - return; - } - - free(nom); - - if ((segment = shmget(clef, - nombre_queues * (longueur_queue + 4) * sizeof(int), - IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR)) == -1) - { - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; - return; - } - - fifos = shmat(segment, NULL, 0); - - if (((void *) fifos) == ((void *) -1)) - { - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; - return; - } - - for(i = 0; i < nombre_queues; i++) - { - fifos[(i * (longueur_queue + 4))] = 0; - fifos[(i * (longueur_queue + 4)) + 1] = 0; - fifos[(i * (longueur_queue + 4)) + 2] = longueur_queue; - 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; - } - - if ((desc = fopen(nom, "w")) == NULL) - { - (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; - return; - } - - fclose(desc); - - if ((clef = ftok(nom, 1)) == -1) - { - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; - return; - } - - free(nom); + pid_t pid; - if ((segment_mutexes = shmget(clef, - nombre_queues * sizeof(pthread_mutex_t), - IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR)) == -1) - { - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; - return; - } + test_signal(signal); - mutexes = shmat(segment_mutexes, NULL, 0); +# ifdef _BROKEN_SIGINFO + if ((signal == SIGINT) || (signal == SIGTERM)) + { + // Si l'interruption provient du clavier, il n'y a pas eu d'appel + // à queue_in(). - if (((void *) mutexes) == ((void *) -1)) - { - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; - return; - } + pid = getpid(); + } + else + { + pid = origine_signal(signal); + } +# else /* - * 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. + * Une vieille spécification POSIX permet au pointeur siginfo + * d'être nul dans le cas d'un ^C envoyé depuis le clavier. + * Solaris suit en particulier cette spécification. */ - 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); - } - - pthread_mutexattr_destroy(&attributs_mutex); - return; -} - -void -liberation_fifos_signaux(struct_processus *s_etat_processus) -{ - if (shmdt(fifos) == -1) - { - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; - return; - } - - if (shmdt(mutexes) == -1) - { - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; - return; - } - - return; -} - -void -destruction_fifos_signaux(struct_processus *s_etat_processus) -{ - int i; - - unsigned char *nom; - - if (shmdt(fifos) == -1) - { - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; - return; - } - - if (shmctl(segment, IPC_RMID, 0) == -1) - { - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; - return; - } - - for(i = 0; i < nombre_queues; i++) - { - pthread_mutex_destroy(&(mutexes[i])); - } - - if (shmdt(mutexes) == -1) - { - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; - return; - } - - if (shmctl(segment_mutexes, IPC_RMID, 0) == -1) - { - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; - return; - } - - if ((nom = nom_segment_mutexes((*s_etat_processus) - .chemin_fichiers_temporaires, getpid())) == 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) - { - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; - return; - } - - unlink(nom); - free(nom); + if (siginfo != NULL) + { + pid = (*siginfo).si_pid; + } + else + { + pid = getpid(); + } +# endif + queue_interruptions.pid[signal][queue_interruptions.pointeur + [signal][ECRITURE]] = pid; + queue_interruptions.pointeur[signal][ECRITURE] = + (queue_interruptions.pointeur[signal][ECRITURE] + 1) + % SIGNAL_BUFFER; + queue_interruptions.nombre_interruptions_en_queue++; return; } -int -queue_in(pid_t pid, int signal) -{ - int *base; - int *buffer; - int *projection_fifos; - int queue; - int identifiant; - - key_t clef; - - pthread_mutex_t *projection_mutexes; - - unsigned char *nom; - - queue = queue_de_signal(signal); - - // Ouverture des projections - - if ((nom = nom_segment(chemin, pid)) == NULL) - { - return(-1); - } - - 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); - - projection_fifos = shmat(identifiant, NULL, 0); - - if ((nom = nom_segment_mutexes(chemin, pid)) == NULL) - { - return(-1); - } - - if ((clef = ftok(nom, 1)) == -1) - { - free(nom); - return(-1); - } - - free(nom); - - while((identifiant = shmget(clef, - nombre_queues * sizeof(pthread_mutex_t), - S_IRUSR | S_IWUSR)) == -1); - - projection_mutexes = shmat(identifiant, NULL, 0); - - if (pthread_mutex_lock(&(projection_mutexes[queue])) != 0) - { - return(-1); - } - - 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 non lus - if (base[3] <= 0) - { - pthread_mutex_unlock(&(projection_mutexes[queue])); - shmdt(projection_mutexes); - shmdt(projection_fifos); - return(-1); - } - - base[3]--; - - if (pthread_mutex_unlock(&(projection_mutexes[queue])) != 0) - { - shmdt(projection_mutexes); - shmdt(projection_fifos); - return(-1); - } - - // Fermeture des projections - shmdt(projection_mutexes); - shmdt(projection_fifos); - return(0); -} - -pid_t -origine_signal(int signal) +static void +corps_interruption1(struct_processus *s_etat_processus, int signal, pid_t pid) { - int *base; - int *buffer; - int pid; - int queue; - - queue = queue_de_signal(signal); - - BUG(queue == -1, uprintf("[%d] Unknown signal %d in this context\n", - (int) getpid(), signal)); - - if (pthread_mutex_lock(&(mutexes[queue])) != 0) - { - return(-1); - } - - 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])); - return(-1); - } - if (pthread_mutex_unlock(&(mutexes[queue])) != 0) - { - perror("unlock"); - return(-1); - } - - return((pid_t) pid); -} - -#endif - -void -interruption1(SIGHANDLER_ARGS) -{ - pid_t pid; - - pthread_t thread; - - struct_processus *s_etat_processus; - volatile sig_atomic_t exclusion = 0; -# ifdef _BROKEN_SIGINFO - if (signal == SIGINT) - { - // Si l'interruption provient du clavier, il n'y a pas eu d'appel - // à queue_in(). - - pid = getpid(); - } - else - { - pid = origine_signal(signal); - } -# else - pid = (*siginfo).si_pid; -# endif + struct_processus *s_thread_principal; verrouillage_gestionnaire_signaux(); @@ -2187,13 +1827,6 @@ interruption1(SIGHANDLER_ARGS) { if (pid == getpid()) { - if ((s_etat_processus = recherche_thread(getpid(), - pthread_self())) == NULL) - { - deverrouillage_gestionnaire_signaux(); - return; - } - if (((*s_etat_processus).type_debug & d_debug_signaux) != 0) { printf("[%d] SIGALRM (thread %llu)\n", (int) getpid(), @@ -2213,9 +1846,13 @@ interruption1(SIGHANDLER_ARGS) } else { - if (recherche_thread_principal(getpid(), &thread) == d_vrai) + if ((s_thread_principal = recherche_thread_principal(getpid())) + != NULL) { - pthread_kill(thread, signal); + while((*s_etat_processus).signal_a_traiter == d_vrai); + (*s_etat_processus).signal = signal; + (*s_etat_processus).origine_signal = getpid(); + (*s_etat_processus).signal_a_traiter = d_vrai; } } @@ -2223,33 +1860,23 @@ interruption1(SIGHANDLER_ARGS) } case SIGINT : + case SIGTERM : { - /* - * Une vieille spécification POSIX permet au pointeur siginfo - * d'être nul dans le cas d'un ^C envoyé depuis le clavier. - * Solaris suit en particulier cette spécification. - */ - -# ifndef _BROKEN_SIGINFO - if (siginfo == NULL) - { - kill(getpid(), signal); - } - else -# endif if (pid == getpid()) { - if ((s_etat_processus = recherche_thread(getpid(), - pthread_self())) == NULL) - { - deverrouillage_gestionnaire_signaux(); - return; - } - if (((*s_etat_processus).type_debug & d_debug_signaux) != 0) { - printf("[%d] SIGINT (thread %llu)\n", (int) getpid(), - (unsigned long long) pthread_self()); + if (signal == SIGINT) + { + printf("[%d] SIGINT (thread %llu)\n", (int) getpid(), + (unsigned long long) pthread_self()); + } + else + { + printf("[%d] SIGTERM (thread %llu)\n", (int) getpid(), + (unsigned long long) pthread_self()); + } + fflush(stdout); } @@ -2271,16 +1898,19 @@ interruption1(SIGHANDLER_ARGS) return; } - if (strncmp(getenv("LANG"), "fr", 2) == 0) + if (signal == SIGINT) { - printf("+++Interruption\n"); - } - else - { - printf("+++Interrupt\n"); - } + if (strncmp(getenv("LANG"), "fr", 2) == 0) + { + printf("+++Interruption\n"); + } + else + { + printf("+++Interrupt\n"); + } - fflush(stdout); + fflush(stdout); + } (*s_etat_processus).var_volatile_requete_arret = -1; (*s_etat_processus).var_volatile_alarme = -1; @@ -2290,9 +1920,13 @@ interruption1(SIGHANDLER_ARGS) } else { - if (recherche_thread_principal(getpid(), &thread) == d_vrai) + if ((s_thread_principal = recherche_thread_principal(getpid())) + != NULL) { - pthread_kill(thread, signal); + while((*s_etat_processus).signal_a_traiter == d_vrai); + (*s_etat_processus).signal = signal; + (*s_etat_processus).origine_signal = getpid(); + (*s_etat_processus).signal_a_traiter = d_vrai; } } @@ -2314,49 +1948,59 @@ interruption1(SIGHANDLER_ARGS) void interruption2(SIGHANDLER_ARGS) { - pid_t pid; - - pthread_t thread; + pid_t pid; - struct_processus *s_etat_processus; + test_signal(signal); # ifdef _BROKEN_SIGINFO pid = origine_signal(signal); # else - pid = (*siginfo).si_pid; + if (siginfo != NULL) + { + pid = (*siginfo).si_pid; + } + else + { + pid = getpid(); + } # endif - verrouillage_gestionnaire_signaux(); + queue_interruptions.pid[signal][queue_interruptions.pointeur + [signal][ECRITURE]] = pid; + queue_interruptions.pointeur[signal][ECRITURE] = + (queue_interruptions.pointeur[signal][ECRITURE] + 1) + % SIGNAL_BUFFER; + + /* + * Le signal SIGFSTP provient de la mort du processus de contrôle. + * Sous certains systèmes (Linux...), la mort du terminal de contrôle + * se traduit par l'envoi d'un SIGHUP au processus. Sur d'autres + * (SunOS), le processus reçoit un SIGFSTP avec une structure siginfo + * non initialisée (pointeur NULL) issue de TERMIO. + */ -# ifndef _BROKEN_SIGINFO if (siginfo == NULL) { - /* - * Le signal SIGFSTP provient de la mort du processus de contrôle. - * Sous certains systèmes (Linux...), la mort du terminal de contrôle - * se traduit par l'envoi d'un SIGHUP au processus. Sur d'autres - * (SunOS), le processus reçoit un SIGFSTP avec une structure siginfo - * non initialisée (pointeur NULL) issue de TERMIO. - */ - - if (recherche_thread_principal(getpid(), &thread) == d_vrai) - { - pthread_kill(thread, SIGHUP); - deverrouillage_gestionnaire_signaux(); - return; - } + queue_interruptions.pid[SIGHUP][queue_interruptions.pointeur + [SIGHUP][ECRITURE]] = pid; + queue_interruptions.pointeur[SIGHUP][ECRITURE] = + (queue_interruptions.pointeur[SIGHUP][ECRITURE] + 1) + % SIGNAL_BUFFER; + queue_interruptions.nombre_interruptions_en_queue += 2; } - else -# endif + + return; +} + +static void +corps_interruption2(struct_processus *s_etat_processus, int signal, pid_t pid) +{ + struct_processus *s_thread_principal; + + verrouillage_gestionnaire_signaux(); + if (pid == getpid()) { - if ((s_etat_processus = recherche_thread(getpid(), pthread_self())) - == NULL) - { - deverrouillage_gestionnaire_signaux(); - return; - } - /* * 0 => fonctionnement normal * -1 => requête @@ -2383,11 +2027,13 @@ interruption2(SIGHANDLER_ARGS) { // Envoi d'un signal au thread maître du groupe. - if (recherche_thread_principal(getpid(), &thread) == d_vrai) + if ((s_thread_principal = recherche_thread_principal(getpid())) + != NULL) { - pthread_kill(thread, SIGTSTP); - deverrouillage_gestionnaire_signaux(); - return; + while((*s_etat_processus).signal_a_traiter == d_vrai); + (*s_etat_processus).signal = signal; + (*s_etat_processus).origine_signal = getpid(); + (*s_etat_processus).signal_a_traiter = d_vrai; } } @@ -2398,18 +2044,29 @@ interruption2(SIGHANDLER_ARGS) void interruption3(SIGHANDLER_ARGS) { - pid_t pid; + // Si on passe par ici, c'est qu'il est impossible de récupérer + // l'erreur d'accès à la mémoire. On sort donc du programme quitte à + // ce qu'il reste des processus orphelins. - struct_processus *s_etat_processus; + unsigned char message[] = "+++System : Uncaught access violation\n" + "+++System : Aborting !\n; - static int compteur = 0; + if (pid_processus_pere == getpid()) + { + kill(pid_processus_pere, SIGALRM); + } -# ifdef _BROKEN_SIGINFO - pid = origine_signal(signal); -# else - pid = (*siginfo).si_pid; -# endif + write(STDERR_FILENO, message, strlen(message)); + _exit(EXIT_FAILURE); +} +void INTERRUPTION3_A_FIXER() +{ + pthread_t thread; + + struct_processus *s_etat_processus; + + test_signal(signal); verrouillage_gestionnaire_signaux(); if ((s_etat_processus = recherche_thread(getpid(), pthread_self())) == NULL) @@ -2436,24 +2093,79 @@ interruption3(SIGHANDLER_ARGS) // Segfault dans une routine interne if (strncmp(getenv("LANG"), "fr", 2) == 0) { - printf("+++Système : Violation d'accès (dépassement de pile)\n"); + printf("+++Système : Violation d'accès\n"); } else { - printf("+++System : Access violation (stack overflow)\n"); + printf("+++System : Access violation\n"); } fflush(stdout); - compteur++; + (*s_etat_processus).compteur_violation_d_acces++; - if (compteur > 1) + if ((*s_etat_processus).compteur_violation_d_acces > 1) { + // On vient de récupérer plus d'une erreur de segmentation + // dans le même processus ou le même thread. L'erreur n'est pas + // récupérable et on sort autoritairement du programme. Il peut + // rester des processus orphelins en attente ! + + if (strncmp(getenv("LANG"), "fr", 2) == 0) + { + printf("+++Système : Violation d'accès, tentative de " + "terminaison de la tâche\n"); + printf(" (defauts multiples)\n"); + } + else + { + printf("+++System : Access violation, trying to kill task " + "(multiple defaults)\n"); + } + + fflush(stdout); + deverrouillage_gestionnaire_signaux(); exit(EXIT_FAILURE); } else { + // Première erreur de segmentation. On essaie de terminer + // proprement le thread ou le processus. Le signal ne peut être + // envoyé que depuis le même processus. + + if (recherche_thread_principal(getpid(), &thread) == d_vrai) + { + if (pthread_equal(thread, pthread_self()) != 0) + { + deverrouillage_gestionnaire_signaux(); + + if ((*s_etat_processus).pid_processus_pere != getpid()) + { + // On est dans le thread principal d'un processus. + + longjmp(contexte_processus, -1); + } + else + { + // On est dans le thread principal du processus + // père. + + longjmp(contexte_initial, -1); + } + } + else + { + // On est dans un thread fils d'un thread principal. + + deverrouillage_gestionnaire_signaux(); + longjmp(contexte_thread, -1); + } + } + + // Là, on ramasse les miettes puisque le thread n'existe plus + // dans la base (corruption de la mémoire). + deverrouillage_gestionnaire_signaux(); longjmp(contexte_initial, -1); } @@ -2466,16 +2178,9 @@ interruption3(SIGHANDLER_ARGS) void interruption4(SIGHANDLER_ARGS) { - pid_t pid; - struct_processus *s_etat_processus; -# ifdef _BROKEN_SIGINFO - pid = origine_signal(signal); -# else - pid = (*siginfo).si_pid; -# endif - + test_signal(signal); verrouillage_gestionnaire_signaux(); if ((s_etat_processus = recherche_thread(getpid(), pthread_self())) == NULL) @@ -2508,14 +2213,15 @@ interruption5(SIGHANDLER_ARGS) struct_processus *s_etat_processus; + test_signal(signal); + verrouillage_gestionnaire_signaux(); + # ifdef _BROKEN_SIGINFO pid = origine_signal(signal); # else pid = (*siginfo).si_pid; # endif - verrouillage_gestionnaire_signaux(); - if (pid == getpid()) { if ((s_etat_processus = recherche_thread(getpid(), pthread_self())) @@ -2574,16 +2280,9 @@ interruption5(SIGHANDLER_ARGS) void interruption6(SIGHANDLER_ARGS) { - pid_t pid; - struct_processus *s_etat_processus; -# ifdef _BROKEN_SIGINFO - pid = origine_signal(signal); -# else - pid = (*siginfo).si_pid; -# endif - + test_signal(signal); verrouillage_gestionnaire_signaux(); if ((s_etat_processus = recherche_thread(getpid(), pthread_self())) == NULL) @@ -2606,16 +2305,9 @@ interruption6(SIGHANDLER_ARGS) void interruption7(SIGHANDLER_ARGS) { - pid_t pid; - struct_processus *s_etat_processus; -# ifdef _BROKEN_SIGINFO - pid = origine_signal(signal); -# else - pid = (*siginfo).si_pid; -# endif - + test_signal(signal); verrouillage_gestionnaire_signaux(); if ((s_etat_processus = recherche_thread(getpid(), pthread_self())) == NULL) @@ -2647,14 +2339,15 @@ interruption8(SIGHANDLER_ARGS) struct_processus *s_etat_processus; + test_signal(signal); + verrouillage_gestionnaire_signaux(); + # ifdef _BROKEN_SIGINFO pid = origine_signal(signal); # else pid = (*siginfo).si_pid; # endif - verrouillage_gestionnaire_signaux(); - if (pid == getpid()) { if ((s_etat_processus = recherche_thread(getpid(), pthread_self())) @@ -2693,16 +2386,9 @@ interruption8(SIGHANDLER_ARGS) void interruption9(SIGHANDLER_ARGS) { - pid_t pid; - struct_processus *s_etat_processus; -# ifdef _BROKEN_SIGINFO - pid = origine_signal(signal); -# else - pid = (*siginfo).si_pid; -# endif - + test_signal(signal); verrouillage_gestionnaire_signaux(); if ((s_etat_processus = recherche_thread(getpid(), pthread_self())) == NULL) @@ -2718,16 +2404,16 @@ interruption9(SIGHANDLER_ARGS) fflush(stdout); } - deverrouillage_gestionnaire_signaux(); - # ifdef _BROKEN_SIGINFO if (queue_in(getpid(), signal) != 0) { return; } + deverrouillage_gestionnaire_signaux(); interruption11(signal); # else + deverrouillage_gestionnaire_signaux(); interruption11(signal, siginfo, context); # endif return; @@ -2738,18 +2424,11 @@ interruption10(SIGHANDLER_ARGS) { file *fichier; - pid_t pid; - struct_processus *s_etat_processus; unsigned char nom[8 + 64 + 1]; -# ifdef _BROKEN_SIGINFO - pid = origine_signal(signal); -# else - pid = (*siginfo).si_pid; -# endif - + test_signal(signal); verrouillage_gestionnaire_signaux(); if ((s_etat_processus = recherche_thread(getpid(), pthread_self())) == NULL) @@ -2791,14 +2470,15 @@ interruption11(SIGHANDLER_ARGS) struct_processus *s_etat_processus; + test_signal(signal); + verrouillage_gestionnaire_signaux(); + # ifdef _BROKEN_SIGINFO pid = origine_signal(signal); # else pid = (*siginfo).si_pid; # endif - verrouillage_gestionnaire_signaux(); - if (pid == getpid()) { if ((s_etat_processus = recherche_thread(getpid(), pthread_self())) @@ -2877,45 +2557,78 @@ traitement_exceptions_gsl(const char *re return; } -#ifdef _BROKEN_SIGINFO - -#undef kill -#undef pthread_kill - -int -rpl_kill(pid_t pid, int signal) +static inline void +structation_interruptions_elementaires(struct_processus *s_etat_processus, + int signal, pid_t pid) { - /* - * Lorsqu'on veut interrompre le processus pid, on ouvre le segment - * correspondant au processus en question et ou ajoute le pid dans la - * queue. - */ - - if ((signal != 0) && (signal != SIGINT)) + switch(signal) { - if (queue_in(pid, signal) != 0) + case SIGINT: + case SIGTERM: + case SIGALRM: { - return(-1); + corps_interruption1(s_etat_processus, signal, pid); + break; + } + + case SIGTSTP: + { + corps_interruption2(s_etat_processus, signal, pid); } } - return(kill(pid, signal)); + return; } -int -rpl_pthread_kill(pthread_t tid, int signal) +void +scrutation_interruptions(struct_processus *s_etat_processus) { - if ((signal != 0) && (signal != SIGINT)) + int i; + + // Interruption par processus. + + if (pthread_mutex_lock(&mutex_signal) != 0) { - if (queue_in(getpid(), signal) != 0) + (*s_etat_processus).erreur_systeme = d_es_processus; + return; + } + + if (queue_interruptions.nombre_interruptions_en_queue > 0) + { + for(i = 0; i < SIGNAL_MAX; i++) { - return(-1); + if ((queue_interruptions.pointeur[i][ECRITURE] - + queue_interruptions.pointeur[i][LECTURE]) != 0) + { + // Il y a une interruption dans la queue. + + queue_interruptions.nombre_interruptions_en_queue--; + scrutation_interruptions_elementaires(s_etat_processus, i, + queue_interruptions.pid[signal] + [queue_interruptions.pointeur[signal][LECTURE]]); + queue_interruptions.pointeur[signal][LECTURE] = + (queue_interruptions.pointeur[signal][LECTURE] + 1) + % SIGNAL_BUFFER; + } } } - return(pthread_kill(tid, signal)); -} + if (pthread_mutex_unlock(&mutex_signal) != 0) + { + (*s_etat_processus).erreur_systeme = d_es_processus; + return; + } -#endif + // Interruption par thread + + if ((*s_etat_processus).signal_a_traiter == d_vrai) + { + (*s_etat_processus).signal_a_traiter = d_faux; + scrutation_interruptions_elementaires(s_etat_processus, + (*s_etat_processus).signal, (*s_etat_processus).origine_signal); + } + + return; +} // vim: ts=4