/* ================================================================================ RPL/2 (R) version 4.1.3 Copyright (C) 1989-2011 Dr. BERTRAND Joël This file is part of RPL/2. RPL/2 is free software; you can redistribute it and/or modify it under the terms of the CeCILL V2 License as published by the french CEA, CNRS and INRIA. RPL/2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL V2 License for more details. You should have received a copy of the CeCILL License along with RPL/2. If not, write to info@cecill.info. ================================================================================ */ #include "rpl-conv.h" /* ================================================================================ Procédures de gestion par thread des variables issues des gestionnaires de signaux ================================================================================ Entrée : variable globale -------------------------------------------------------------------------------- Sortie : variable globale modifiée -------------------------------------------------------------------------------- Effets de bord : néant ================================================================================ */ typedef struct thread { pid_t pid; pthread_t tid; logical1 thread_principal; struct_processus *s_etat_processus; } struct_thread; typedef struct liste_chainee_volatile { volatile struct liste_chainee_volatile *suivant; volatile void *donnee; } struct_liste_chainee_volatile; static volatile struct_liste_chainee_volatile *liste_threads = NULL; static volatile struct_liste_chainee_volatile *liste_threads_surveillance = NULL; static volatile int code_erreur_gsl = 0; unsigned char *racine_segment; static pthread_mutex_t mutex_interruptions = PTHREAD_MUTEX_INITIALIZER; void modification_pid_thread_pere(struct_processus *s_etat_processus) { // La variable existe toujours et aucun thread concurrent ne peut // la modifier puisque cette routine ne peut être appelée que depuis // DAEMON. (*((struct_thread *) (*liste_threads).donnee)).pid = (*s_etat_processus).pid_processus_pere; return; } void insertion_thread(struct_processus *s_etat_processus, logical1 thread_principal) { volatile struct_liste_chainee_volatile *l_nouvel_objet; if ((l_nouvel_objet = malloc(sizeof(struct_liste_chainee_volatile))) == NULL) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } if (((*l_nouvel_objet).donnee = malloc(sizeof(struct_thread))) == NULL) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } (*((struct_thread *) (*l_nouvel_objet).donnee)).pid = getpid(); (*((struct_thread *) (*l_nouvel_objet).donnee)).tid = pthread_self(); (*((struct_thread *) (*l_nouvel_objet).donnee)).thread_principal = thread_principal; (*((struct_thread *) (*l_nouvel_objet).donnee)).s_etat_processus = s_etat_processus; if (pthread_mutex_lock(&mutex_liste_threads) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } (*l_nouvel_objet).suivant = liste_threads; liste_threads = l_nouvel_objet; if (pthread_mutex_unlock(&mutex_liste_threads) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } return; } void insertion_thread_surveillance(struct_processus *s_etat_processus, struct_descripteur_thread *s_argument_thread) { volatile struct_liste_chainee_volatile *l_nouvel_objet; if ((l_nouvel_objet = malloc(sizeof(struct_liste_chainee_volatile))) == NULL) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } if (pthread_mutex_lock(&mutex_liste_threads) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } pthread_mutex_lock(&((*s_argument_thread).mutex_nombre_references)); (*s_argument_thread).nombre_references++; pthread_mutex_unlock(&((*s_argument_thread).mutex_nombre_references)); (*l_nouvel_objet).suivant = liste_threads_surveillance; (*l_nouvel_objet).donnee = (void *) s_argument_thread; liste_threads_surveillance = l_nouvel_objet; if (pthread_mutex_unlock(&mutex_liste_threads) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } return; } void retrait_thread(struct_processus *s_etat_processus) { volatile struct_liste_chainee_volatile *l_element_precedent; volatile struct_liste_chainee_volatile *l_element_courant; if (pthread_mutex_lock(&mutex_liste_threads) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } l_element_precedent = NULL; l_element_courant = liste_threads; while(l_element_courant != NULL) { if (((*((struct_thread *) (*l_element_courant).donnee)).pid == getpid()) && (pthread_equal((*((struct_thread *) (*l_element_courant).donnee)).tid, pthread_self()) != 0)) { break; } l_element_precedent = l_element_courant; l_element_courant = (*l_element_courant).suivant; } if (l_element_courant == NULL) { pthread_mutex_unlock(&mutex_liste_threads); (*s_etat_processus).erreur_systeme = d_es_processus; return; } if (l_element_precedent == NULL) { liste_threads = (*l_element_courant).suivant; } else { (*l_element_precedent).suivant = (*l_element_courant).suivant; } if (pthread_mutex_unlock(&mutex_liste_threads) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } free((void *) (*l_element_courant).donnee); free((struct_liste_chainee_volatile *) l_element_courant); return; } void retrait_thread_surveillance(struct_processus *s_etat_processus, struct_descripteur_thread *s_argument_thread) { volatile struct_liste_chainee_volatile *l_element_precedent; volatile struct_liste_chainee_volatile *l_element_courant; if (pthread_mutex_lock(&mutex_liste_threads) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } l_element_precedent = NULL; l_element_courant = liste_threads_surveillance; while(l_element_courant != NULL) { if ((*l_element_courant).donnee == (void *) s_argument_thread) { break; } l_element_precedent = l_element_courant; l_element_courant = (*l_element_courant).suivant; } if (l_element_courant == NULL) { pthread_mutex_unlock(&mutex_liste_threads); (*s_etat_processus).erreur_systeme = d_es_processus; return; } if (l_element_precedent == NULL) { liste_threads_surveillance = (*l_element_courant).suivant; } else { (*l_element_precedent).suivant = (*l_element_courant).suivant; } if (pthread_mutex_lock(&((*s_argument_thread).mutex_nombre_references)) != 0) { pthread_mutex_unlock(&mutex_liste_threads); (*s_etat_processus).erreur_systeme = d_es_processus; return; } (*s_argument_thread).nombre_references--; BUG((*s_argument_thread).nombre_references < 0, printf("(*s_argument_thread).nombre_references = %d\n", (int) (*s_argument_thread).nombre_references)); if ((*s_argument_thread).nombre_references == 0) { if (pthread_mutex_unlock(&((*s_argument_thread) .mutex_nombre_references)) != 0) { pthread_mutex_unlock(&mutex_liste_threads); (*s_etat_processus).erreur_systeme = d_es_processus; return; } 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_nombre_references)) != 0) { pthread_mutex_unlock(&mutex_liste_threads); (*s_etat_processus).erreur_systeme = d_es_processus; return; } } if (pthread_mutex_unlock(&mutex_liste_threads) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } free((struct_liste_chainee_volatile *) l_element_courant); return; } void verrouillage_threads_concurrents(struct_processus *s_etat_processus) { volatile struct_liste_chainee_volatile *l_element_courant; if (pthread_mutex_lock(&mutex_liste_threads) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } l_element_courant = liste_threads; while(l_element_courant != NULL) { if (((*((struct_thread *) (*l_element_courant).donnee)).pid == getpid()) && (pthread_equal((*((struct_thread *) (*l_element_courant).donnee)).tid, pthread_self()) == 0)) { if (sem_wait(&((*(*((struct_thread *) (*l_element_courant) .donnee)).s_etat_processus).semaphore_fork)) == -1) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } } l_element_courant = (*l_element_courant).suivant; } return; } void deverrouillage_threads_concurrents(struct_processus *s_etat_processus) { volatile struct_liste_chainee_volatile *l_element_courant; l_element_courant = liste_threads; while(l_element_courant != NULL) { if (((*((struct_thread *) (*l_element_courant).donnee)).pid == getpid()) && (pthread_equal((*((struct_thread *) (*l_element_courant).donnee)).tid, pthread_self()) == 0)) { if (sem_post(&((*(*((struct_thread *) (*l_element_courant).donnee)).s_etat_processus) .semaphore_fork)) != 0) { if (pthread_mutex_unlock(&mutex_liste_threads) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } (*s_etat_processus).erreur_systeme = d_es_processus; return; } } l_element_courant = (*l_element_courant).suivant; } if (pthread_mutex_unlock(&mutex_liste_threads) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } return; } void liberation_threads(struct_processus *s_etat_processus) { logical1 suppression_variables_partagees; struct_descripteur_thread *s_argument_thread; struct_processus *candidat; unsigned long i; void *element_candidat; void *element_courant; void *element_suivant; volatile struct_liste_chainee_volatile *l_element_courant; volatile struct_liste_chainee_volatile *l_element_suivant; if (pthread_mutex_lock(&mutex_liste_threads) == -1) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } l_element_courant = liste_threads; suppression_variables_partagees = d_faux; while(l_element_courant != NULL) { if ((*((struct_thread *) (*l_element_courant).donnee)).s_etat_processus != s_etat_processus) { candidat = s_etat_processus; s_etat_processus = (*((struct_thread *) (*l_element_courant).donnee)).s_etat_processus; free((*s_etat_processus).localisation); // (*s_etat_processus).instruction_courante peut pointer sur // n'importe quoi (une instruction courante ou un champ d'une // structure objet). On ne le libère pas quitte à avoir une // petite fuite mémoire dans le processus fils. if ((*s_etat_processus).instruction_courante != NULL) { //free((*s_etat_processus).instruction_courante); } close((*s_etat_processus).pipe_acquittement); close((*s_etat_processus).pipe_donnees); close((*s_etat_processus).pipe_injections); close((*s_etat_processus).pipe_nombre_injections); close((*s_etat_processus).pipe_interruptions); close((*s_etat_processus).pipe_nombre_objets_attente); close((*s_etat_processus).pipe_nombre_interruptions_attente); liberation(s_etat_processus, (*s_etat_processus).at_exit); if ((*s_etat_processus).nom_fichier_impression != NULL) { free((*s_etat_processus).nom_fichier_impression); } while((*s_etat_processus).fichiers_graphiques != NULL) { free((*(*s_etat_processus).fichiers_graphiques).nom); if ((*(*s_etat_processus).fichiers_graphiques).legende != NULL) { free((*(*s_etat_processus).fichiers_graphiques).legende); } element_courant = (*s_etat_processus).fichiers_graphiques; (*s_etat_processus).fichiers_graphiques = (*(*s_etat_processus).fichiers_graphiques).suivant; free(element_courant); } if ((*s_etat_processus).entree_standard != NULL) { pclose((*s_etat_processus).entree_standard); } if ((*s_etat_processus).generateur_aleatoire != NULL) { liberation_generateur_aleatoire(s_etat_processus); } if ((*s_etat_processus).instruction_derniere_erreur != NULL) { free((*s_etat_processus).instruction_derniere_erreur); (*s_etat_processus).instruction_derniere_erreur = NULL; } element_courant = (void *) (*s_etat_processus) .l_base_pile_processus; while(element_courant != NULL) { s_argument_thread = (struct_descripteur_thread *) (*((struct_liste_chainee *) element_courant)).donnee; if (pthread_mutex_lock(&((*s_argument_thread) .mutex_nombre_references)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; pthread_mutex_unlock(&mutex_liste_threads); return; } (*s_argument_thread).nombre_references--; BUG((*s_argument_thread).nombre_references < 0, printf("(*s_argument_thread).nombre_references = %d\n", (int) (*s_argument_thread).nombre_references)); if ((*s_argument_thread).nombre_references == 0) { close((*s_argument_thread).pipe_objets[0]); close((*s_argument_thread).pipe_acquittement[1]); close((*s_argument_thread).pipe_injections[1]); close((*s_argument_thread).pipe_nombre_injections[1]); close((*s_argument_thread).pipe_nombre_objets_attente[0]); close((*s_argument_thread).pipe_interruptions[0]); close((*s_argument_thread) .pipe_nombre_interruptions_attente[0]); if (pthread_mutex_unlock(&((*s_argument_thread) .mutex_nombre_references)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; pthread_mutex_unlock(&mutex_liste_threads); return; } pthread_mutex_destroy(&((*s_argument_thread).mutex)); pthread_mutex_destroy(&((*s_argument_thread) .mutex_nombre_references)); if ((*s_argument_thread).processus_detache == d_faux) { if ((*s_argument_thread).destruction_objet == d_vrai) { liberation(s_etat_processus, (*s_argument_thread) .argument); } } free(s_argument_thread); } else { if (pthread_mutex_unlock(&((*s_argument_thread) .mutex_nombre_references)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; pthread_mutex_unlock(&mutex_liste_threads); return; } } element_suivant = (*((struct_liste_chainee *) element_courant)) .suivant; free(element_courant); element_courant = element_suivant; } (*s_etat_processus).l_base_pile_processus = NULL; pthread_mutex_trylock(&((*(*s_etat_processus).indep).mutex)); pthread_mutex_unlock(&((*(*s_etat_processus).indep).mutex)); liberation(s_etat_processus, (*s_etat_processus).indep); pthread_mutex_trylock(&((*(*s_etat_processus).depend).mutex)); pthread_mutex_unlock(&((*(*s_etat_processus).depend).mutex)); liberation(s_etat_processus, (*s_etat_processus).depend); free((*s_etat_processus).label_x); free((*s_etat_processus).label_y); free((*s_etat_processus).label_z); free((*s_etat_processus).titre); free((*s_etat_processus).legende); pthread_mutex_trylock(&((*(*s_etat_processus) .parametres_courbes_de_niveau).mutex)); pthread_mutex_unlock(&((*(*s_etat_processus) .parametres_courbes_de_niveau).mutex)); liberation(s_etat_processus, (*s_etat_processus) .parametres_courbes_de_niveau); for(i = 0; i < d_NOMBRE_INTERRUPTIONS; i++) { if ((*s_etat_processus).corps_interruptions[i] != NULL) { pthread_mutex_trylock(&((*(*s_etat_processus) .corps_interruptions[i]).mutex)); pthread_mutex_unlock(&((*(*s_etat_processus) .corps_interruptions[i]).mutex)); liberation(s_etat_processus, (*s_etat_processus).corps_interruptions[i]); } element_courant = (*s_etat_processus) .pile_origine_interruptions[i]; while(element_courant != NULL) { element_suivant = (*((struct_liste_chainee *) element_courant)).suivant; pthread_mutex_trylock(&((*(*((struct_liste_chainee *) element_courant)).donnee).mutex)); pthread_mutex_unlock(&((*(*((struct_liste_chainee *) element_courant)).donnee).mutex)); liberation(s_etat_processus, (*((struct_liste_chainee *) element_courant)) .donnee); free(element_courant); element_courant = element_suivant; } } 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++) { pthread_mutex_trylock(&((*(*s_etat_processus) .s_liste_variables_statiques[i].objet).mutex)); pthread_mutex_unlock(&((*(*s_etat_processus) .s_liste_variables_statiques[i].objet).mutex)); liberation(s_etat_processus, (*s_etat_processus) .s_liste_variables_statiques[i].objet); free((*s_etat_processus).s_liste_variables_statiques[i].nom); } free((*s_etat_processus).s_liste_variables_statiques); // Ne peut être effacé qu'une seule fois if (suppression_variables_partagees == d_faux) { suppression_variables_partagees = d_vrai; for(i = 0; i < (*(*s_etat_processus) .s_liste_variables_partagees).nombre_variables; i++) { pthread_mutex_trylock(&((*(*(*s_etat_processus) .s_liste_variables_partagees).table[i].objet) .mutex)); pthread_mutex_unlock(&((*(*(*s_etat_processus) .s_liste_variables_partagees).table[i].objet) .mutex)); liberation(s_etat_processus, (*(*s_etat_processus) .s_liste_variables_partagees).table[i].objet); free((*(*s_etat_processus).s_liste_variables_partagees) .table[i].nom); } if ((*(*s_etat_processus).s_liste_variables_partagees).table != NULL) { free((struct_variable_partagee *) (*(*s_etat_processus) .s_liste_variables_partagees).table); } pthread_mutex_trylock(&((*(*s_etat_processus) .s_liste_variables_partagees).mutex)); pthread_mutex_unlock(&((*(*s_etat_processus) .s_liste_variables_partagees).mutex)); } element_courant = (*s_etat_processus).l_base_pile; while(element_courant != NULL) { element_suivant = (*((struct_liste_chainee *) element_courant)).suivant; pthread_mutex_trylock(&((*(*((struct_liste_chainee *) element_courant)).donnee).mutex)); pthread_mutex_unlock(&((*(*((struct_liste_chainee *) element_courant)).donnee).mutex)); liberation(s_etat_processus, (*((struct_liste_chainee *) element_courant)).donnee); free((struct_liste_chainee *) element_courant); element_courant = element_suivant; } element_courant = (*s_etat_processus).l_base_pile_contextes; while(element_courant != NULL) { element_suivant = (*((struct_liste_chainee *) element_courant)).suivant; pthread_mutex_trylock(&((*(*((struct_liste_chainee *) element_courant)).donnee).mutex)); pthread_mutex_unlock(&((*(*((struct_liste_chainee *) element_courant)).donnee).mutex)); liberation(s_etat_processus, (*((struct_liste_chainee *) element_courant)).donnee); free((struct_liste_chainee *) element_courant); element_courant = element_suivant; } element_courant = (*s_etat_processus).l_base_pile_taille_contextes; while(element_courant != NULL) { element_suivant = (*((struct_liste_chainee *) element_courant)).suivant; pthread_mutex_trylock(&((*(*((struct_liste_chainee *) element_courant)).donnee).mutex)); pthread_mutex_unlock(&((*(*((struct_liste_chainee *) element_courant)).donnee).mutex)); liberation(s_etat_processus, (*((struct_liste_chainee *) element_courant)).donnee); free((struct_liste_chainee *) element_courant); element_courant = element_suivant; } for(i = 0; i < (*s_etat_processus).nombre_instructions_externes; i++) { free((*s_etat_processus).s_instructions_externes[i].nom); free((*s_etat_processus).s_instructions_externes[i] .nom_bibliotheque); } if ((*s_etat_processus).nombre_instructions_externes != 0) { free((*s_etat_processus).s_instructions_externes); } element_courant = (*s_etat_processus).s_bibliotheques; while(element_courant != NULL) { element_suivant = (*((struct_liste_chainee *) element_courant)).suivant; element_candidat = (*candidat).s_bibliotheques; while(element_candidat != NULL) { if (((*((struct_bibliotheque *) (*((struct_liste_chainee *) element_courant)).donnee)) .descripteur == (*((struct_bibliotheque *) (*((struct_liste_chainee *) element_candidat)) .donnee)).descripteur) && ((*((struct_bibliotheque *) (*((struct_liste_chainee *) element_courant)) .donnee)).pid == (*((struct_bibliotheque *) (*((struct_liste_chainee *) element_candidat)) .donnee)).pid) && (pthread_equal( (*((struct_bibliotheque *) (*((struct_liste_chainee *) element_courant)) .donnee)).tid, (*((struct_bibliotheque *) (*((struct_liste_chainee *) element_candidat)) .donnee)).tid) != 0)) { break; } element_candidat = (*((struct_liste_chainee *) element_candidat)).suivant; } if (element_candidat == NULL) { dlclose((*((struct_bibliotheque *) (*((struct_liste_chainee *) element_courant)) .donnee)).descripteur); } free((*((struct_bibliotheque *) (*((struct_liste_chainee *) element_courant)).donnee)).nom); free((*((struct_liste_chainee *) element_courant)).donnee); free(element_courant); element_courant = element_suivant; } element_courant = (*s_etat_processus).l_base_pile_last; while(element_courant != NULL) { element_suivant = (*((struct_liste_chainee *) element_courant)).suivant; pthread_mutex_trylock(&((*(*((struct_liste_chainee *) element_courant)).donnee).mutex)); pthread_mutex_unlock(&((*(*((struct_liste_chainee *) element_courant)).donnee).mutex)); liberation(s_etat_processus, (*((struct_liste_chainee *) element_courant)).donnee); free(element_courant); element_courant = element_suivant; } element_courant = (*s_etat_processus).l_base_pile_systeme; while(element_courant != NULL) { element_suivant = (*((struct_liste_pile_systeme *) element_courant)).suivant; if ((*((struct_liste_pile_systeme *) element_courant)).indice_boucle != NULL) { pthread_mutex_trylock(&((*(*((struct_liste_pile_systeme *) element_courant)).indice_boucle).mutex)); pthread_mutex_unlock(&((*(*((struct_liste_pile_systeme *) element_courant)).indice_boucle).mutex)); } liberation(s_etat_processus, (*((struct_liste_pile_systeme *) element_courant)).indice_boucle); if ((*((struct_liste_pile_systeme *) element_courant)).limite_indice_boucle != NULL) { pthread_mutex_trylock(&((*(*((struct_liste_pile_systeme *) element_courant)).limite_indice_boucle).mutex)); pthread_mutex_unlock(&((*(*((struct_liste_pile_systeme *) element_courant)).limite_indice_boucle).mutex)); } liberation(s_etat_processus, (*((struct_liste_pile_systeme *) element_courant)).limite_indice_boucle); if ((*((struct_liste_pile_systeme *) element_courant)).objet_de_test != NULL) { pthread_mutex_trylock(&((*(*((struct_liste_pile_systeme *) element_courant)).objet_de_test).mutex)); pthread_mutex_unlock(&((*(*((struct_liste_pile_systeme *) element_courant)).objet_de_test).mutex)); } liberation(s_etat_processus, (*((struct_liste_pile_systeme *) element_courant)).objet_de_test); if ((*((struct_liste_pile_systeme *) element_courant)).nom_variable != NULL) { free((*((struct_liste_pile_systeme *) element_courant)).nom_variable); } free(element_courant); element_courant = element_suivant; } element_courant = (*s_etat_processus).s_fichiers; while(element_courant != NULL) { element_suivant = (*((struct_liste_chainee *) element_courant)).suivant; element_candidat = (*candidat).s_fichiers; while(element_candidat != NULL) { if (((*((struct_descripteur_fichier *) (*((struct_liste_chainee *) element_courant)) .donnee)).pid == (*((struct_descripteur_fichier *) (*((struct_liste_chainee *) element_candidat)) .donnee)).pid) && (pthread_equal( (*((struct_descripteur_fichier *) (*((struct_liste_chainee *) element_courant)) .donnee)).tid, (*((struct_descripteur_fichier *) (*((struct_liste_chainee *) element_candidat)) .donnee)).tid) != 0)) { if ((*((struct_descripteur_fichier *) (*((struct_liste_chainee *) element_courant)) .donnee)).type == (*((struct_descripteur_fichier *) (*((struct_liste_chainee *) element_candidat)) .donnee)).type) { if ((*((struct_descripteur_fichier *) (*((struct_liste_chainee *) element_candidat)).donnee)).type == 'C') { if ((*((struct_descripteur_fichier *) (*((struct_liste_chainee *) element_courant)).donnee)) .descripteur_c == (*((struct_descripteur_fichier *) (*((struct_liste_chainee *) element_candidat)).donnee)) .descripteur_c) { break; } } else { if (((*((struct_descripteur_fichier *) (*((struct_liste_chainee *) element_courant)).donnee)) .descripteur_sqlite == (*((struct_descripteur_fichier *) (*((struct_liste_chainee *) element_candidat)).donnee)) .descripteur_sqlite) && ((*((struct_descripteur_fichier *) (*((struct_liste_chainee *) element_courant)).donnee)) .descripteur_c == (*((struct_descripteur_fichier *) (*((struct_liste_chainee *) element_candidat)).donnee)) .descripteur_c)) { break; } } } } element_candidat = (*((struct_liste_chainee *) element_candidat)).suivant; } if (element_candidat == NULL) { fclose((*((struct_descripteur_fichier *) (*((struct_liste_chainee *) element_courant)) .donnee)).descripteur_c); if ((*((struct_descripteur_fichier *) (*((struct_liste_chainee *) element_courant)) .donnee)).type != 'C') { sqlite3_close((*((struct_descripteur_fichier *) (*((struct_liste_chainee *) element_courant)) .donnee)).descripteur_sqlite); } } free((*((struct_descripteur_fichier *) (*((struct_liste_chainee *) element_courant)).donnee)).nom); free((struct_descripteur_fichier *) (*((struct_liste_chainee *) element_courant)).donnee); free(element_courant); element_courant = element_suivant; } element_courant = (*s_etat_processus).s_sockets; while(element_courant != NULL) { element_suivant = (*((struct_liste_chainee *) element_courant)).suivant; element_candidat = (*candidat).s_sockets; while(element_candidat != NULL) { if (((*((struct_socket *) (*((struct_liste_chainee *) element_courant)) .donnee)).socket == (*((struct_socket *) (*((struct_liste_chainee *) element_candidat)) .donnee)).socket) && ((*((struct_socket *) (*((struct_liste_chainee *) element_courant)) .donnee)).pid == (*((struct_socket *) (*((struct_liste_chainee *) element_candidat)) .donnee)).pid) && (pthread_equal( (*((struct_socket *) (*((struct_liste_chainee *) element_courant)) .donnee)).tid, (*((struct_socket *) (*((struct_liste_chainee *) element_candidat)) .donnee)).tid) != 0)) { break; } element_candidat = (*((struct_liste_chainee *) element_candidat)).suivant; } if (element_candidat == NULL) { if ((*((struct_socket *) (*((struct_liste_chainee *) element_courant)).donnee)).socket_connectee == d_vrai) { shutdown((*((struct_socket *) (*((struct_liste_chainee *) element_courant)) .donnee)).socket, SHUT_RDWR); } close((*((struct_socket *) (*((struct_liste_chainee *) element_courant)) .donnee)).socket); } pthread_mutex_trylock(&((*(*((struct_liste_chainee *) element_courant)).donnee).mutex)); pthread_mutex_unlock(&((*(*((struct_liste_chainee *) element_courant)).donnee).mutex)); liberation(s_etat_processus, (*((struct_liste_chainee *) element_courant)).donnee); free(element_courant); element_courant = element_suivant; } /* ================================================================================ À noter : on ne ferme pas la connexion car la conséquence immédiate est une destruction de l'objet pour le processus père. ================================================================================ element_courant = (*s_etat_processus).s_connecteurs_sql; while(element_courant != NULL) { element_suivant = (*((struct_liste_chainee *) element_courant)).suivant; element_candidat = (*candidat).s_connecteurs_sql; while(element_candidat != NULL) { if ((( #ifdef MYSQL_SUPPORT ((*((struct_connecteur_sql *) (*((struct_liste_chainee *) element_courant)) .donnee)).descripteur.mysql == (*((struct_connecteur_sql *) (*((struct_liste_chainee *) element_candidat)) .donnee)).descripteur.mysql) && (strcmp((*((struct_connecteur_sql *) (*((struct_liste_chainee *) element_courant)) .donnee)).type, "MYSQL") == 0) && (strcmp((*((struct_connecteur_sql *) (*((struct_liste_chainee *) element_candidat)) .donnee)).type, "MYSQL") == 0) #else 0 #endif ) || ( #ifdef POSTGRESQL_SUPPORT ((*((struct_connecteur_sql *) (*((struct_liste_chainee *) element_courant)) .donnee)).descripteur.postgresql == (*((struct_connecteur_sql *) (*((struct_liste_chainee *) element_candidat)) .donnee)).descripteur.postgresql) && (strcmp((*((struct_connecteur_sql *) (*((struct_liste_chainee *) element_courant)) .donnee)).type, "POSTGRESQL") == 0) && (strcmp((*((struct_connecteur_sql *) (*((struct_liste_chainee *) element_candidat)) .donnee)).type, "POSTGRESQL") == 0) #else 0 #endif )) && ((*((struct_connecteur_sql *) (*((struct_liste_chainee *) element_courant)) .donnee)).pid == (*((struct_connecteur_sql *) (*((struct_liste_chainee *) element_candidat)) .donnee)).pid) && (pthread_equal( (*((struct_connecteur_sql *) (*((struct_liste_chainee *) element_courant)) .donnee)).tid, (*((struct_connecteur_sql *) (*((struct_liste_chainee *) element_candidat)) .donnee)).tid) != 0)) { break; } element_candidat = (*((struct_liste_chainee *) element_candidat)).suivant; } if (element_candidat == NULL) { sqlclose((*((struct_liste_chainee *) element_courant)) .donnee); } pthread_mutex_trylock(&((*(*((struct_liste_chainee *) element_courant)).donnee).mutex)); pthread_mutex_unlock(&((*(*((struct_liste_chainee *) element_courant)).donnee).mutex)); liberation(s_etat_processus, (*((struct_liste_chainee *) element_courant)).donnee); free(element_courant); element_courant = element_suivant; } */ (*s_etat_processus).s_connecteurs_sql = NULL; element_courant = (*s_etat_processus).s_marques; while(element_courant != NULL) { free((*((struct_marque *) element_courant)).label); free((*((struct_marque *) element_courant)).position); element_suivant = (*((struct_marque *) element_courant)) .suivant; free(element_courant); element_courant = element_suivant; } liberation_allocateur(s_etat_processus); sem_post(&((*s_etat_processus).semaphore_fork)); sem_destroy(&((*s_etat_processus).semaphore_fork)); liberation_contexte_cas(s_etat_processus); free(s_etat_processus); s_etat_processus = candidat; } l_element_suivant = (*l_element_courant).suivant; free((struct_thread *) (*l_element_courant).donnee); free((struct_liste_chainee *) l_element_courant); l_element_courant = l_element_suivant; } liste_threads = NULL; l_element_courant = liste_threads_surveillance; while(l_element_courant != NULL) { s_argument_thread = (struct_descripteur_thread *) (*l_element_courant).donnee; if (pthread_mutex_lock(&((*s_argument_thread).mutex_nombre_references)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; pthread_mutex_unlock(&mutex_liste_threads); return; } (*s_argument_thread).nombre_references--; BUG((*s_argument_thread).nombre_references < 0, printf("(*s_argument_thread).nombre_references = %d\n", (int) (*s_argument_thread).nombre_references)); if ((*s_argument_thread).nombre_references == 0) { close((*s_argument_thread).pipe_objets[0]); close((*s_argument_thread).pipe_acquittement[1]); close((*s_argument_thread).pipe_injections[1]); close((*s_argument_thread).pipe_nombre_injections[1]); close((*s_argument_thread).pipe_nombre_objets_attente[0]); close((*s_argument_thread).pipe_interruptions[0]); close((*s_argument_thread).pipe_nombre_interruptions_attente[0]); if (pthread_mutex_unlock(&((*s_argument_thread) .mutex_nombre_references)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; pthread_mutex_unlock(&mutex_liste_threads); return; } pthread_mutex_destroy(&((*s_argument_thread).mutex)); pthread_mutex_destroy(&((*s_argument_thread) .mutex_nombre_references)); if ((*s_argument_thread).processus_detache == d_faux) { if ((*s_argument_thread).destruction_objet == d_vrai) { liberation(s_etat_processus, (*s_argument_thread).argument); } } free(s_argument_thread); } else { if (pthread_mutex_unlock(&((*s_argument_thread) .mutex_nombre_references)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; pthread_mutex_unlock(&mutex_liste_threads); return; } } l_element_suivant = (*l_element_courant).suivant; free((struct_liste_chainee *) l_element_courant); l_element_courant = l_element_suivant; } liste_threads_surveillance = NULL; if (pthread_mutex_unlock(&mutex_liste_threads) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } return; } static struct_processus * recherche_thread(pid_t pid, pthread_t tid) { volatile struct_liste_chainee_volatile *l_element_courant; struct_processus *s_etat_processus; l_element_courant = liste_threads; while(l_element_courant != NULL) { if ((pthread_equal((*((struct_thread *) (*l_element_courant).donnee)) .tid, tid) != 0) && ((*((struct_thread *) (*l_element_courant).donnee)).pid == pid)) { break; } l_element_courant = (*l_element_courant).suivant; } if (l_element_courant == NULL) { /* * Le processus n'existe plus. On ne distribue aucun signal. */ return(NULL); } s_etat_processus = (*((struct_thread *) (*l_element_courant).donnee)).s_etat_processus; return(s_etat_processus); } static struct_processus * recherche_thread_principal(pid_t pid) { volatile struct_liste_chainee_volatile *l_element_courant; l_element_courant = liste_threads; while(l_element_courant != NULL) { if (((*((struct_thread *) (*l_element_courant).donnee)).thread_principal == d_vrai) && ((*((struct_thread *) (*l_element_courant).donnee)).pid == pid)) { break; } l_element_courant = (*l_element_courant).suivant; } if (l_element_courant == NULL) { /* * Le processus n'existe plus. On ne distribue aucun signal. */ return(NULL); } return((*((struct_thread *) (*l_element_courant).donnee)) .s_etat_processus); } /* ================================================================================ Procédures de gestion des signaux d'interruption ================================================================================ Entrée : variable globale -------------------------------------------------------------------------------- Sortie : variable globale modifiée -------------------------------------------------------------------------------- Effets de bord : néant ================================================================================ */ // Les routines suivantes sont uniquement appelées depuis les gestionnaires // des signaux asynchrones. Elles ne doivent pas bloquer dans le cas où // les sémaphores sont déjà bloqués par un gestionnaire de signal. static inline void verrouillage_gestionnaire_signaux(struct_processus *s_etat_processus) { int semaphore; if (sem_post(&((*s_etat_processus).semaphore_fork)) != 0) { BUG(1, uprintf("Lock error !\n")); return; } // Il faut respecteur l'atomicité des deux opérations suivantes ! if (pthread_mutex_lock(&mutex_gestionnaires_signaux_atomique) != 0) { sem_wait(&((*s_etat_processus).semaphore_fork)); BUG(1, uprintf("Unlock error !\n")); return; } # ifndef SEMAPHORES_NOMMES if (sem_post(&semaphore_gestionnaires_signaux) == -1) # else if (sem_post(semaphore_gestionnaires_signaux) == -1) # endif { sem_wait(&((*s_etat_processus).semaphore_fork)); BUG(1, uprintf("Lock error !\n")); return; } # ifndef SEMAPHORES_NOMMES if (sem_getvalue(&semaphore_gestionnaires_signaux, &semaphore) != 0) # else if (sem_getvalue(semaphore_gestionnaires_signaux, &semaphore) != 0) # endif { sem_wait(&((*s_etat_processus).semaphore_fork)); BUG(1, uprintf("Lock error !\n")); return; } if (pthread_mutex_unlock(&mutex_gestionnaires_signaux_atomique) != 0) { sem_wait(&((*s_etat_processus).semaphore_fork)); BUG(1, uprintf("Unlock error !\n")); return; } if (semaphore == 1) { // Le semaphore ne peut être pris par le thread qui a appelé // le gestionnaire de signal car le signal est bloqué par ce thread // dans les zones critiques. Ce sémaphore ne peut donc être bloqué que // par un thread concurrent. On essaye donc de le bloquer jusqu'à // ce que ce soit possible. if (pthread_mutex_lock(&mutex_liste_threads) != 0) { sem_wait(&((*s_etat_processus).semaphore_fork)); BUG(1, uprintf("Lock error !\n")); return; } } return; } static inline void deverrouillage_gestionnaire_signaux(struct_processus *s_etat_processus) { int semaphore; // Il faut respecteur l'atomicité des deux opérations suivantes ! if (pthread_mutex_lock(&mutex_gestionnaires_signaux_atomique) == -1) { sem_wait(&((*s_etat_processus).semaphore_fork)); BUG(1, uprintf("Unlock error !\n")); return; } # ifndef SEMAPHORES_NOMMES if (sem_getvalue(&semaphore_gestionnaires_signaux, &semaphore) != 0) # else if (sem_getvalue(semaphore_gestionnaires_signaux, &semaphore) != 0) # endif { sem_wait(&((*s_etat_processus).semaphore_fork)); BUG(1, uprintf("Unlock error !\n")); return; } # ifndef SEMAPHORES_NOMMES while(sem_wait(&semaphore_gestionnaires_signaux) == -1) # else while(sem_wait(semaphore_gestionnaires_signaux) == -1) # endif { if (errno != EINTR) { sem_wait(&((*s_etat_processus).semaphore_fork)); BUG(1, uprintf("Unlock error !\n")); return; } } if (pthread_mutex_unlock(&mutex_gestionnaires_signaux_atomique) != 0) { sem_wait(&((*s_etat_processus).semaphore_fork)); BUG(1, uprintf("Unlock error !\n")); return; } if (sem_wait(&((*s_etat_processus).semaphore_fork)) != 0) { BUG(1, uprintf("Unlock error !\n")); return; } if (semaphore == 1) { if (pthread_mutex_unlock(&mutex_liste_threads) != 0) { BUG(1, uprintf("Unlock error !\n")); return; } } return; } #define test_signal(signal) \ if (signal_test == SIGTEST) { signal_test = signal; return; } // Récupération des signaux // - SIGINT (arrêt au clavier) // - SIGTERM (signal d'arrêt en provenance du système) void interruption1(int signal) { test_signal(signal); switch(signal) { case SIGINT: envoi_signal_processus(getpid(), rpl_sigint); break; case SIGTERM: envoi_signal_processus(getpid(), rpl_sigterm); break; case SIGALRM: envoi_signal_processus(getpid(), rpl_sigalrm); break; } return; } inline static void signal_alrm(struct_processus *s_etat_processus, pid_t pid) { struct_processus *s_thread_principal; verrouillage_gestionnaire_signaux(s_etat_processus); if (pid == getpid()) { // Si pid est égal à getpid(), le signal à traiter est issu // du même processus que celui qui va le traiter, mais d'un thread // différent. if (((*s_etat_processus).type_debug & d_debug_signaux) != 0) { printf("[%d] RPL/SIGALRM (thread %llu)\n", (int) getpid(), (unsigned long long) pthread_self()); fflush(stdout); } if ((*s_etat_processus).pid_processus_pere != getpid()) { // On n'est pas dans le processus père, on remonte le signal. envoi_signal_processus((*s_etat_processus).pid_processus_pere, rpl_sigalrm); } else { // On est dans le processus père, on effectue un arrêt d'urgence. (*s_etat_processus).var_volatile_alarme = -1; (*s_etat_processus).var_volatile_requete_arret = -1; } } else { // Le signal est issu d'un processus différent. On recherche le // thread principal pour remonter le signal. if ((s_thread_principal = recherche_thread_principal(getpid())) != NULL) { envoi_signal_contexte(s_thread_principal, rpl_sigalrm); } } deverrouillage_gestionnaire_signaux(s_etat_processus); return; } inline static void signal_term(struct_processus *s_etat_processus, pid_t pid) { struct_processus *s_thread_principal; volatile sig_atomic_t exclusion = 0; verrouillage_gestionnaire_signaux(s_etat_processus); if (pid == getpid()) { if (((*s_etat_processus).type_debug & d_debug_signaux) != 0) { printf("[%d] RPL/SIGTERM (thread %llu)\n", (int) getpid(), (unsigned long long) pthread_self()); fflush(stdout); } if ((*s_etat_processus).pid_processus_pere != getpid()) { envoi_signal_processus((*s_etat_processus).pid_processus_pere, rpl_sigterm); } else { (*s_etat_processus).var_volatile_traitement_sigint = -1; while(exclusion == 1); exclusion = 1; if ((*s_etat_processus).var_volatile_requete_arret == -1) { deverrouillage_gestionnaire_signaux(s_etat_processus); exclusion = 0; return; } (*s_etat_processus).var_volatile_requete_arret = -1; (*s_etat_processus).var_volatile_alarme = -1; exclusion = 0; } } else { if ((s_thread_principal = recherche_thread_principal(getpid())) != NULL) { envoi_signal_contexte(s_thread_principal, rpl_sigterm); } } deverrouillage_gestionnaire_signaux(s_etat_processus); return; } inline static void signal_int(struct_processus *s_etat_processus, pid_t pid) { struct_processus *s_thread_principal; volatile sig_atomic_t exclusion = 0; verrouillage_gestionnaire_signaux(s_etat_processus); if (pid == getpid()) { if (((*s_etat_processus).type_debug & d_debug_signaux) != 0) { printf("[%d] RPL/SIGINT (thread %llu)\n", (int) getpid(), (unsigned long long) pthread_self()); fflush(stdout); } if ((*s_etat_processus).pid_processus_pere != getpid()) { envoi_signal_processus((*s_etat_processus).pid_processus_pere, rpl_sigint); } else { (*s_etat_processus).var_volatile_traitement_sigint = -1; while(exclusion == 1); exclusion = 1; if ((*s_etat_processus).var_volatile_requete_arret == -1) { deverrouillage_gestionnaire_signaux(s_etat_processus); exclusion = 0; return; } if ((*s_etat_processus).langue == 'F') { printf("+++Interruption\n"); } else { printf("+++Interrupt\n"); } fflush(stdout); (*s_etat_processus).var_volatile_requete_arret = -1; (*s_etat_processus).var_volatile_alarme = -1; exclusion = 0; } } else { if ((s_thread_principal = recherche_thread_principal(getpid())) != NULL) { envoi_signal_contexte(s_thread_principal, rpl_sigint); } } deverrouillage_gestionnaire_signaux(s_etat_processus); return; } // Récupération des signaux // - SIGFSTP // // ATTENTION : // 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. void interruption2(int signal) { test_signal(signal); envoi_signal_processus(getpid(), rpl_sigtstp); return; } static inline void signal_tstp(struct_processus *s_etat_processus, pid_t pid) { struct_processus *s_thread_principal; verrouillage_gestionnaire_signaux(s_etat_processus); if (pid == getpid()) { /* * 0 => fonctionnement normal * -1 => requête * 1 => requête acceptée en attente de traitement */ if (((*s_etat_processus).type_debug & d_debug_signaux) != 0) { printf("[%d] RPL/SIGTSTP (thread %llu)\n", (int) getpid(), (unsigned long long) pthread_self()); fflush(stdout); } if ((*s_etat_processus).var_volatile_processus_pere == 0) { envoi_signal_processus((*s_etat_processus).pid_processus_pere, rpl_sigtstp); } else { (*s_etat_processus).var_volatile_requete_arret2 = -1; } } else { // Envoi d'un signal au thread maître du groupe. if ((s_thread_principal = recherche_thread_principal(getpid())) != NULL) { envoi_signal_contexte(s_thread_principal, rpl_sigtstp); } } deverrouillage_gestionnaire_signaux(s_etat_processus); return; } void interruption3(int signal) { // 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"; test_signal(signal); if (pid_processus_pere == getpid()) { kill(pid_processus_pere, SIGALRM); } write(STDERR_FILENO, message, strlen(message)); _exit(EXIT_FAILURE); } #if 0 // Utiliser libsigsegv void INTERRUPTION3_A_FIXER() { pthread_t thread; struct_processus *s_etat_processus; test_signal(signal); verrouillage_gestionnaire_signaux(s_etat_processus); if ((s_etat_processus = recherche_thread(getpid(), pthread_self())) == NULL) { deverrouillage_gestionnaire_signaux(s_etat_processus); return; } if (((*s_etat_processus).type_debug & d_debug_signaux) != 0) { printf("[%d] SIGSEGV (thread %llu)\n", (int) getpid(), (unsigned long long) pthread_self()); fflush(stdout); } if ((*s_etat_processus).var_volatile_recursivite == -1) { // Segfault dans un appel de fonction récursive deverrouillage_gestionnaire_signaux(s_etat_processus); longjmp(contexte, -1); } else { // Segfault dans une routine interne if (strncmp(getenv("LANG"), "fr", 2) == 0) { printf("+++Système : Violation d'accès\n"); } else { printf("+++System : Access violation\n"); } fflush(stdout); (*s_etat_processus).compteur_violation_d_acces++; 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(s_etat_processus); 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(s_etat_processus); 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(s_etat_processus); 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(s_etat_processus); longjmp(contexte_initial, -1); } } deverrouillage_gestionnaire_signaux(s_etat_processus); return; } #endif // Traitement de rpl_sigstart static inline void signal_start(struct_processus *s_etat_processus, pid_t pid) { struct_processus *s_thread_principal; verrouillage_gestionnaire_signaux(s_etat_processus); if (pid == getpid()) { (*s_etat_processus).demarrage_fils = d_vrai; } else { // Envoi d'un signal au thread maître du groupe. if ((s_thread_principal = recherche_thread_principal(getpid())) != NULL) { envoi_signal_contexte(s_thread_principal, rpl_sigstart); } } deverrouillage_gestionnaire_signaux(s_etat_processus); return; } // Traitement de rpl_sigcont static inline void signal_cont(struct_processus *s_etat_processus, pid_t pid) { struct_processus *s_thread_principal; verrouillage_gestionnaire_signaux(s_etat_processus); if (pid == getpid()) { (*s_etat_processus).redemarrage_processus = d_vrai; } else { // Envoi d'un signal au thread maître du groupe. if ((s_thread_principal = recherche_thread_principal(getpid())) != NULL) { envoi_signal_contexte(s_thread_principal, rpl_sigcont); } } deverrouillage_gestionnaire_signaux(s_etat_processus); return; } // Traitement de rpl_sigstop static inline void signal_stop(struct_processus *s_etat_processus, pid_t pid) { struct_processus *s_thread_principal; verrouillage_gestionnaire_signaux(s_etat_processus); if (pid == getpid()) { if ((s_etat_processus = recherche_thread(getpid(), pthread_self())) == NULL) { deverrouillage_gestionnaire_signaux(s_etat_processus); return; } if (((*s_etat_processus).type_debug & d_debug_signaux) != 0) { printf("[%d] RPL/SIGSTOP (thread %llu)\n", (int) getpid(), (unsigned long long) pthread_self()); fflush(stdout); } /* * var_globale_traitement_retarde_stop : * 0 -> traitement immédiat * 1 -> traitement retardé (aucun signal reçu) * -1 -> traitement retardé (un ou plusieurs signaux stop reçus) */ if ((*s_etat_processus).var_volatile_traitement_retarde_stop == 0) { (*s_etat_processus).var_volatile_requete_arret = -1; } else { (*s_etat_processus).var_volatile_traitement_retarde_stop = -1; } } else { // Envoi d'un signal au thread maître du groupe. if ((s_thread_principal = recherche_thread_principal(getpid())) != NULL) { envoi_signal_contexte(s_thread_principal, rpl_sigstop); } } deverrouillage_gestionnaire_signaux(s_etat_processus); return; } // Traitement de rpl_siginject static inline void signal_inject(struct_processus *s_etat_processus, pid_t pid) { verrouillage_gestionnaire_signaux(s_etat_processus); if ((s_etat_processus = recherche_thread(getpid(), pthread_self())) == NULL) { deverrouillage_gestionnaire_signaux(s_etat_processus); return; } if (((*s_etat_processus).type_debug & d_debug_signaux) != 0) { printf("[%d] RPL/SIGINJECT (thread %llu)\n", (int) getpid(), (unsigned long long) pthread_self()); fflush(stdout); } deverrouillage_gestionnaire_signaux(s_etat_processus); return; } // Récupération des signaux // - SIGPIPE void interruption5(int signal) { unsigned char message[] = "+++System : SIGPIPE\n" "+++System : Aborting !\n"; test_signal(signal); if (pid_processus_pere == getpid()) { envoi_signal_processus(pid_processus_pere, rpl_sigalrm); } write(STDERR_FILENO, message, strlen(message)); return; } static inline void signal_urg(struct_processus *s_etat_processus, pid_t pid) { struct_processus *s_thread_principal; verrouillage_gestionnaire_signaux(s_etat_processus); if (pid == getpid()) { if ((s_etat_processus = recherche_thread(getpid(), pthread_self())) == NULL) { deverrouillage_gestionnaire_signaux(s_etat_processus); return; } if (((*s_etat_processus).type_debug & d_debug_signaux) != 0) { printf("[%d] RPL/SIGURG (thread %llu)\n", (int) getpid(), (unsigned long long) pthread_self()); fflush(stdout); } (*s_etat_processus).var_volatile_alarme = -1; (*s_etat_processus).var_volatile_requete_arret = -1; } else { // Envoi d'un signal au thread maître du groupe. if ((s_thread_principal = recherche_thread_principal(getpid())) != NULL) { envoi_signal_contexte(s_thread_principal, rpl_sigurg); } } deverrouillage_gestionnaire_signaux(s_etat_processus); return; } // Traitement de rpl_sigabort static inline void signal_abort(struct_processus *s_etat_processus, pid_t pid) { struct_processus *s_thread_principal; verrouillage_gestionnaire_signaux(s_etat_processus); if ((s_etat_processus = recherche_thread(getpid(), pthread_self())) == NULL) { deverrouillage_gestionnaire_signaux(s_etat_processus); return; } if (((*s_etat_processus).type_debug & d_debug_signaux) != 0) { printf("[%d] RPL/SIGABORT (thread %llu)\n", (int) getpid(), (unsigned long long) pthread_self()); fflush(stdout); } if (pid == getpid()) { if ((s_etat_processus = recherche_thread(getpid(), pthread_self())) == NULL) { deverrouillage_gestionnaire_signaux(s_etat_processus); return; } (*s_etat_processus).arret_depuis_abort = -1; /* * var_globale_traitement_retarde_stop : * 0 -> traitement immédiat * 1 -> traitement retardé (aucun signal reçu) * -1 -> traitement retardé (un ou plusieurs signaux stop reçus) */ if ((*s_etat_processus).var_volatile_traitement_retarde_stop == 0) { (*s_etat_processus).var_volatile_requete_arret = -1; } else { (*s_etat_processus).var_volatile_traitement_retarde_stop = -1; } } else { (*s_etat_processus).arret_depuis_abort = -1; // Envoi d'un signal au thread maître du groupe. if ((s_thread_principal = recherche_thread_principal(getpid())) != NULL) { envoi_signal_contexte(s_thread_principal, rpl_sigabort); } } deverrouillage_gestionnaire_signaux(s_etat_processus); return; } // Récupération des signaux // - SIGHUP void interruption4(int signal) { test_signal(signal); envoi_signal_processus(getpid(), rpl_sighup); return; } static inline void signal_hup(struct_processus *s_etat_processus, pid_t pid) { file *fichier; unsigned char nom[8 + 64 + 1]; verrouillage_gestionnaire_signaux(s_etat_processus); if ((s_etat_processus = recherche_thread(getpid(), pthread_self())) == NULL) { deverrouillage_gestionnaire_signaux(s_etat_processus); return; } snprintf(nom, 8 + 64 + 1, "rpl-out-%lu-%lu", (unsigned long) getpid(), (unsigned long) pthread_self()); if ((fichier = fopen(nom, "w+")) != NULL) { fclose(fichier); freopen(nom, "w", stdout); freopen(nom, "w", stderr); } freopen("/dev/null", "r", stdin); if (((*s_etat_processus).type_debug & d_debug_signaux) != 0) { printf("[%d] RPL/SIGHUP (thread %llu)\n", (int) getpid(), (unsigned long long) pthread_self()); fflush(stdout); } deverrouillage_gestionnaire_signaux(s_etat_processus); return; } void traitement_exceptions_gsl(const char *reason, const char *file, int line, int gsl_errno) { code_erreur_gsl = gsl_errno; envoi_signal_processus(getpid(), rpl_sigexcept); return; } static inline void signal_except(struct_processus *s_etat_processus, pid_t pid) { verrouillage_gestionnaire_signaux(s_etat_processus); if ((s_etat_processus = recherche_thread(getpid(), pthread_self())) == NULL) { deverrouillage_gestionnaire_signaux(s_etat_processus); return; } (*s_etat_processus).var_volatile_exception_gsl = code_erreur_gsl; deverrouillage_gestionnaire_signaux(s_etat_processus); return; } static inline void envoi_interruptions(struct_processus *s_etat_processus, enum signaux_rpl signal, pid_t pid_source) { switch(signal) { case rpl_signull: break; case rpl_sigint: signal_int(s_etat_processus, pid_source); break; case rpl_sigterm: signal_term(s_etat_processus, pid_source); break; case rpl_sigstart: signal_start(s_etat_processus, pid_source); break; case rpl_sigcont: signal_cont(s_etat_processus, pid_source); break; case rpl_sigstop: signal_stop(s_etat_processus, pid_source); break; case rpl_sigabort: signal_abort(s_etat_processus, pid_source); break; case rpl_sigurg: signal_urg(s_etat_processus, pid_source); break; case rpl_siginject: signal_inject(s_etat_processus, pid_source); break; case rpl_sigalrm: signal_alrm(s_etat_processus, pid_source); break; case rpl_sighup: signal_hup(s_etat_processus, pid_source); break; case rpl_sigtstp: signal_tstp(s_etat_processus, pid_source); break; case rpl_sigexcept: signal_except(s_etat_processus, pid_source); break; default: if ((*s_etat_processus).langue == 'F') { printf("+++System : Spurious signal (%d) !\n", signal); } else { printf("+++System : Signal inconnu (%d) !\n", signal); } break; } return; } void scrutation_interruptions(struct_processus *s_etat_processus) { // Interruptions qui arrivent sur le processus depuis un // processus externe. // Les pointeurs de lecture pointent sur les prochains éléments // à lire. Les pointeurs d'écriture pointent sur les prochains éléments à // écrire. # ifndef SEMAPHORES_NOMMES if (sem_trywait(&((*s_queue_signaux).semaphore)) == 0) # else if (sem_trywait(semaphore_queue_signaux) == 0) # endif { if ((*s_queue_signaux).pointeur_lecture != (*s_queue_signaux).pointeur_ecriture) { // Il y a un signal en attente dans le segment partagé. On le // traite. envoi_interruptions(s_etat_processus, (*s_queue_signaux).queue[(*s_queue_signaux) .pointeur_lecture].signal, (*s_queue_signaux).queue [(*s_queue_signaux).pointeur_lecture].pid); (*s_queue_signaux).pointeur_lecture = ((*s_queue_signaux).pointeur_lecture + 1) % LONGUEUR_QUEUE_SIGNAUX; } # ifndef SEMAPHORES_NOMMES sem_post(&((*s_queue_signaux).semaphore)); # else sem_post(semaphore_queue_signaux); # endif } // Interruptions qui arrivent depuis le groupe courant de threads. if (pthread_mutex_trylock(&mutex_interruptions) == 0) { if ((*s_etat_processus).pointeur_signal_lecture != (*s_etat_processus).pointeur_signal_ecriture) { // Il y a un signal dans la queue du thread courant. On le traite. envoi_interruptions(s_etat_processus, (*s_etat_processus).signaux_en_queue [(*s_etat_processus).pointeur_signal_lecture], getpid()); (*s_etat_processus).pointeur_signal_lecture = ((*s_etat_processus).pointeur_signal_lecture + 1) % LONGUEUR_QUEUE_SIGNAUX; } pthread_mutex_unlock(&mutex_interruptions); } return; } /* ================================================================================ Fonction renvoyant le nom du segment de mémoire partagée en fonction du pid du processus. ================================================================================ Entrée : Chemin absolue servant de racine, pid du processus -------------------------------------------------------------------------------- Sortie : NULL ou nom du segment -------------------------------------------------------------------------------- Effet de bord : Néant ================================================================================ */ static unsigned char * nom_segment(unsigned char *chemin, pid_t pid) { unsigned char *fichier; # ifdef IPCS_SYSV // !POSIX # ifndef OS2 // !OS2 if ((fichier = malloc((strlen(chemin) + 1 + 256 + 1) * sizeof(unsigned char))) == NULL) { return(NULL); } sprintf(fichier, "%s/RPL-SIGQUEUES-%d", chemin, (int) pid); # else // OS2 if ((fichier = malloc((10 + 256 + 1) * sizeof(unsigned char))) == NULL) { return(NULL); } sprintf(fichier, "\\SHAREMEM\\RPL-SIGQUEUES-%d", (int) pid); # endif // OS2 # else // POSIX if ((fichier = malloc((1 + 256 + 1) * sizeof(unsigned char))) == NULL) { return(NULL); } sprintf(fichier, "/RPL-SIGQUEUES-%d", (int) pid); # endif return(fichier); } /* ================================================================================ Fonctions d'envoi d'un signal à un thread ou à un processus. ================================================================================ Entrée : processus et signal -------------------------------------------------------------------------------- Sortie : erreur -------------------------------------------------------------------------------- Effet de bord : Néant ================================================================================ */ int envoi_signal_processus(pid_t pid, enum signaux_rpl signal) { int segment; # ifndef IPCS_SYSV # ifdef SEMAPHORES_NOMMES sem_t *semaphore; # endif # else int desc; key_t clef; # endif struct_queue_signaux *queue; unsigned char *nom; // Il s'agit d'ouvrir le segment de mémoire partagée, de le projeter en // mémoire puis d'y inscrire le signal à traiter. if (pid == getpid()) { // Le signal est envoyé au même processus. if (s_queue_signaux == NULL) { return(1); } # ifndef SEMAPHORES_NOMMES if (sem_wait(&((*s_queue_signaux).semaphore)) != 0) # else if (sem_wait(semaphore_queue_signaux) != 0) # endif { return(1); } (*s_queue_signaux).queue[(*s_queue_signaux).pointeur_ecriture] .pid = pid; (*s_queue_signaux).queue[(*s_queue_signaux).pointeur_ecriture] .signal = signal; (*s_queue_signaux).pointeur_ecriture = ((*s_queue_signaux).pointeur_ecriture + 1) % LONGUEUR_QUEUE_SIGNAUX; # ifndef SEMAPHORES_NOMMES if (sem_post(&((*s_queue_signaux).semaphore)) != 0) # else if (sem_post(semaphore_queue_signaux) != 0) # endif { return(1); } } else { // Le signal est envoyé depuis un processus distinct. # ifdef IPCS_SYSV if ((nom = nom_segment(racine_segment, pid)) == NULL) { return(1); } if ((desc = open(nom, O_RDWR)) == -1) { free(nom); return(1); } close(desc); if ((clef = ftok(nom, 1)) == -1) { free(nom); return(1); } free(nom); if ((segment = shmget(clef, sizeof(struct_queue_signaux), 0)) == -1) { return(1); } queue = shmat(segment, NULL, 0); # else // POSIX if ((nom = nom_segment(racine_segment, pid)) == NULL) { return(1); } if ((segment = shm_open(nom, O_RDWR, 0)) == -1) { free(nom); return(1); } free(nom); if ((queue = mmap(NULL, sizeof(struct_queue_signaux), PROT_READ | PROT_WRITE, MAP_SHARED, segment, 0)) == MAP_FAILED) { close(segment); return(1); } # endif // À ce moment, le segment de mémoire partagée est projeté // dans l'espace du processus. # ifndef IPCS_SYSV // POSIX # ifndef SEMAPHORES_NOMMES if (sem_wait(&((*queue).semaphore)) != 0) { return(1); } # else if ((semaphore = sem_open2(pid)) == SEM_FAILED) { return(1); } if (sem_wait(semaphore) != 0) { sem_close(semaphore); return(1); } # endif # else // IPCS_SYSV if (sem_wait(&((*queue).semaphore)) != 0) { return(1); } # endif (*queue).queue[(*queue).pointeur_ecriture].pid = getpid(); (*queue).queue[(*queue).pointeur_ecriture].signal = signal; (*queue).pointeur_ecriture = ((*queue).pointeur_ecriture + 1) % LONGUEUR_QUEUE_SIGNAUX; # ifndef IPCS_SYSV // POSIX # ifndef SEMAPHORES_NOMMES if (sem_post(&((*queue).semaphore)) != 0) { return(1); } # else if (sem_post(semaphore) != 0) { sem_close(semaphore); return(1); } if (sem_close(semaphore) != 0) { return(1); } # endif if (munmap(queue, sizeof(struct_queue_signaux)) != 0) { close(segment); return(1); } # else // IPCS_SYSV if (sem_post(&((*queue).semaphore)) != 0) { return(1); } if (shmdt(queue) != 0) { return(1); } # endif } return(0); } int envoi_signal_thread(pthread_t tid, enum signaux_rpl signal) { // Un signal est envoyé d'un thread à un autre thread du même processus. volatile struct_liste_chainee_volatile *l_element_courant; struct_processus *s_etat_processus; if (pthread_mutex_lock(&mutex_liste_threads) != 0) { return(1); } l_element_courant = liste_threads; while(l_element_courant != NULL) { if (((*((struct_thread *) (*l_element_courant).donnee)).pid == getpid()) && (pthread_equal((*((struct_thread *) (*l_element_courant).donnee)).tid, tid) != 0)) { break; } l_element_courant = (*l_element_courant).suivant; } if (l_element_courant == NULL) { pthread_mutex_unlock(&mutex_liste_threads); return(1); } if (pthread_mutex_lock(&mutex_interruptions) != 0) { pthread_mutex_unlock(&mutex_liste_threads); return(1); } s_etat_processus = (*((struct_thread *) (*l_element_courant).donnee)) .s_etat_processus; (*s_etat_processus).signaux_en_queue [(*s_etat_processus).pointeur_signal_ecriture] = signal; (*s_etat_processus).pointeur_signal_ecriture = ((*s_etat_processus).pointeur_signal_ecriture + 1) % LONGUEUR_QUEUE_SIGNAUX; if (pthread_mutex_unlock(&mutex_interruptions) != 0) { pthread_mutex_unlock(&mutex_liste_threads); return(1); } if (pthread_mutex_unlock(&mutex_liste_threads) != 0) { return(1); } return(0); } int envoi_signal_contexte(struct_processus *s_etat_processus_a_signaler, enum signaux_rpl signal) { pthread_mutex_lock(&mutex_interruptions); (*s_etat_processus_a_signaler).signaux_en_queue [(*s_etat_processus_a_signaler).pointeur_signal_ecriture] = signal; (*s_etat_processus_a_signaler).pointeur_signal_ecriture = ((*s_etat_processus_a_signaler).pointeur_signal_ecriture + 1) % LONGUEUR_QUEUE_SIGNAUX; pthread_mutex_unlock(&mutex_interruptions); return(0); } /* ================================================================================ Fonction créant un segment de mémoire partagée destiné à contenir la queue des signaux. ================================================================================ Entrée : structure de description du processus -------------------------------------------------------------------------------- Sortie : Néant -------------------------------------------------------------------------------- Effet de bord : Néant ================================================================================ */ void creation_queue_signaux(struct_processus *s_etat_processus) { unsigned char *nom; racine_segment = (*s_etat_processus).chemin_fichiers_temporaires; # ifndef IPCS_SYSV // POSIX if ((nom = nom_segment((*s_etat_processus).chemin_fichiers_temporaires, getpid())) == NULL) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } if ((f_queue_signaux = shm_open(nom, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) == -1) { free(nom); (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } if (ftruncate(f_queue_signaux, sizeof(struct_queue_signaux)) == -1) { free(nom); (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } s_queue_signaux = mmap(NULL, sizeof(struct_queue_signaux), PROT_READ | PROT_WRITE, MAP_SHARED, f_queue_signaux, 0); if (((void *) s_queue_signaux) == ((void *) -1)) { if (shm_unlink(nom) == -1) { free(nom); (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } free(nom); (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } free(nom); # ifndef SEMAPHORES_NOMMES sem_init(&((*s_queue_signaux).semaphore), 1, 1); # else if ((semaphore_queue_signaux = sem_init2(1, getpid())) == SEM_FAILED) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } # endif (*s_queue_signaux).pointeur_lecture = 0; (*s_queue_signaux).pointeur_ecriture = 0; if (msync(s_queue_signaux, sizeof(struct_queue_signaux), 0)) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } # else // IPCS_SYSV # ifndef OS2 int segment; int support; key_t clef; // Création d'un segment de données associé au PID du processus // courant if ((nom = nom_segment((*s_etat_processus) .chemin_fichiers_temporaires, getpid())) == NULL) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } if ((support = open(nom, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) == -1) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return; } if ((clef = ftok(nom, 1)) == -1) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } close(support); free(nom); if ((segment = shmget(clef, sizeof(struct_queue_signaux), IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR)) == -1) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } s_queue_signaux = shmat(segment, NULL, 0); f_queue_signaux = segment; if (((void *) s_queue_signaux) == ((void *) -1)) { if (shmctl(f_queue_signaux, IPC_RMID, 0) == -1) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } sem_init(&((*s_queue_signaux).semaphore), 1, 1); (*s_queue_signaux).pointeur_lecture = 0; (*s_queue_signaux).pointeur_ecriture = 0; # else // OS/2 if ((nom = nom_segment(NULL, getpid())) == NULL) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } if (DosAllocSharedMem(&ptr_os2, nom, nombre_queues * ((2 * longueur_queue) + 4) * sizeof(int), PAG_WRITE | PAG_READ | PAG_COMMIT) != 0) { free(nom); (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } free(nom); fifos = ptr_os2; # endif # endif return; } /* ================================================================================ Fonction libérant le segment de mémoire partagée destiné à contenir la queue des signaux. ================================================================================ Entrée : structure de description du processus -------------------------------------------------------------------------------- Sortie : Néant -------------------------------------------------------------------------------- Effet de bord : Néant ================================================================================ */ void liberation_queue_signaux(struct_processus *s_etat_processus) { # ifdef IPCS_SYSV // SystemV # ifndef OS2 if (shmdt(s_queue_signaux) == -1) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } # else // OS/2 # endif # else // POSIX # ifndef SEMAPHORES_NOMMES sem_close(&((*s_queue_signaux).semaphore)); # else sem_close(semaphore_queue_signaux); # endif if (munmap(s_queue_signaux, sizeof(struct_queue_signaux)) != 0) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } close(f_queue_signaux); # endif return; } /* ================================================================================ Fonction détruisant le segment de mémoire partagée destiné à contenir la queue des signaux. ================================================================================ Entrée : structure de description du processus -------------------------------------------------------------------------------- Sortie : Néant -------------------------------------------------------------------------------- Effet de bord : Néant ================================================================================ */ void destruction_queue_signaux(struct_processus *s_etat_processus) { unsigned char *nom; # ifdef IPCS_SYSV // SystemV # ifndef OS2 // Il faut commencer par éliminer le sémaphore. if (semctl((*s_queue_signaux).semaphore.sem, 0, IPC_RMID) == -1) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } unlink((*s_queue_signaux).semaphore.path); if (shmdt(s_queue_signaux) == -1) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } if (shmctl(f_queue_signaux, IPC_RMID, 0) == -1) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } 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); # else if (DosFreeMem(fifos) != 0) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } // FERMER LE FICHIER # endif # else // POSIX # ifndef SEMAPHORES_NOMMES sem_close(&((*s_queue_signaux).semaphore)); sem_destroy(&((*s_queue_signaux).semaphore)); # else sem_close(semaphore_queue_signaux); sem_destroy2(semaphore_queue_signaux, getpid()); # endif if (munmap(s_queue_signaux, sizeof(struct_queue_signaux)) != 0) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } if ((nom = nom_segment(NULL, getpid())) == NULL) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } close(f_queue_signaux); if (shm_unlink(nom) != 0) { free(nom); (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } free(nom); # endif return; } // vim: ts=4