--- rpl/src/interruptions.c 2011/09/09 12:23:25 1.65 +++ rpl/src/interruptions.c 2011/09/10 20:45:06 1.66 @@ -1457,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; @@ -1482,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); } @@ -1719,58 +1718,115 @@ deverrouillage_gestionnaire_signaux() } #define test_signal(signal) \ - if (signal_test == SIGTEST) { signal_test = signal; return; } + if (signal_test == SIGTEST) \ + { signal_test = initialisation_queue_interruptions(signal); return; } -void -interruption1(SIGHANDLER_ARGS) +/* + * 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. + */ + +static struct { - pid_t pid; +# define SIGNAL_MAX 32 +# define SIGNAL_BUFFER 1024 +# define ECRITURE 0 +# define LECTURE 1 - pthread_t thread; + sig_atomic_t nombre_interruptions_en_queue; + int pointeur[SIGNAL_MAX][2]; - struct_processus *s_etat_processus; + pid_t pid[SIGNAL_MAX][SIGNAL_BUFFER]; +} queue_interruptions; - volatile sig_atomic_t exclusion = 0; +pthread_mutex_t mutex_signal = PTHREAD_MUTEX_INITIALIZER; - test_signal(signal); - verrouillage_gestionnaire_signaux(); +static inline int +initialisation_queue_interruptions(int signal) +{ + int i; -# ifdef _BROKEN_SIGINFO - if ((signal == SIGINT) || (signal == SIGTERM)) + if (signal > SIGNAL_MAX) { - // Si l'interruption provient du clavier, il n'y a pas eu d'appel - // à queue_in(). - - pid = getpid(); + return(signal + 1); } - else + + queue_interruptions.nombre_interruptions_en_queue = 0; + + for(i = 0; i < SIGNAL_MAX; i++) { - pid = origine_signal(signal); + queue_interruptions.pointeur[i][ECRITURE] = 0; + queue_interruptions.pointeur[i][LECTURE] = 0; } + + return(signal); +} + +void +interruption1(SIGHANDLER_ARGS) +{ + pid_t pid; + + test_signal(signal); + +# ifdef _BROKEN_SIGINFO + if ((signal == SIGINT) || (signal == SIGTERM)) + { + // Si l'interruption provient du clavier, il n'y a pas eu d'appel + // à queue_in(). + + pid = getpid(); + } + else + { + pid = origine_signal(signal); + } # else - if (siginfo != NULL) - { - pid = (*siginfo).si_pid; - } - else - { - pid = getpid(); - } + + /* + * 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. + */ + + 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; +} + +static void +corps_interruption1(struct_processus *s_etat_processus, int signal, pid_t pid) +{ + volatile sig_atomic_t exclusion = 0; + + struct_processus *s_thread_principal; + + verrouillage_gestionnaire_signaux(); + switch(signal) { case SIGALRM : { 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(), @@ -1790,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; } } @@ -1802,28 +1862,8 @@ 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) { if (signal == SIGINT) @@ -1880,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; } } @@ -1904,14 +1948,9 @@ interruption1(SIGHANDLER_ARGS) void interruption2(SIGHANDLER_ARGS) { - pid_t pid; - - pthread_t thread; - - struct_processus *s_etat_processus; + pid_t pid; test_signal(signal); - verrouillage_gestionnaire_signaux(); # ifdef _BROKEN_SIGINFO pid = origine_signal(signal); @@ -1926,35 +1965,42 @@ interruption2(SIGHANDLER_ARGS) } # endif -# ifndef _BROKEN_SIGINFO + 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. + */ + 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 @@ -1981,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; } } @@ -1996,6 +2044,24 @@ interruption2(SIGHANDLER_ARGS) void interruption3(SIGHANDLER_ARGS) { + // 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. + + unsigned char message[] = "+++System : Uncaught access violation\n" + "+++System : Aborting !\n; + + if (pid_processus_pere == getpid()) + { + kill(pid_processus_pere, SIGALRM); + } + + write(STDERR_FILENO, message, strlen(message)); + _exit(EXIT_FAILURE); +} + +void INTERRUPTION3_A_FIXER() +{ pthread_t thread; struct_processus *s_etat_processus; @@ -2491,4 +2557,78 @@ traitement_exceptions_gsl(const char *re return; } +static inline void +structation_interruptions_elementaires(struct_processus *s_etat_processus, + int signal, pid_t pid) +{ + switch(signal) + { + case SIGINT: + case SIGTERM: + case SIGALRM: + { + corps_interruption1(s_etat_processus, signal, pid); + break; + } + + case SIGTSTP: + { + corps_interruption2(s_etat_processus, signal, pid); + } + } + + return; +} + +void +scrutation_interruptions(struct_processus *s_etat_processus) +{ + int i; + + // Interruption par processus. + + if (pthread_mutex_lock(&mutex_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++) + { + 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; + } + } + } + + if (pthread_mutex_unlock(&mutex_signal) != 0) + { + (*s_etat_processus).erreur_systeme = d_es_processus; + return; + } + + // 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