/* ================================================================================ RPL/2 (R) version 4.1.20 Copyright (C) 1989-2015 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 void * thread_surveillance_signaux(void *argument) { // Cette fonction est lancée dans un thread créé par processus pour // gérer le cas des appels système qui seraient bloqués lors de l'arrivée du // signal SIGALRM. Les processus externes n'envoient plus un signal au // processus ou au thread à signaler mais positionnent les informations // nécessaires dans la queue des signaux et incrémentent le sémaphore. // Le sémaphore est décrémenté lorsque le signal est effectivement traité. int nombre_signaux_envoyes; struct_processus *s_etat_processus; struct timespec attente; volatile struct_liste_chainee_volatile *l_element_courant; sigset_t set; sigfillset(&set); pthread_sigmask(SIG_BLOCK, &set, NULL); s_etat_processus = (struct_processus *) argument; for(;;) { attente.tv_sec = 0; attente.tv_nsec = GRANULARITE_us * 1000; if (sem_wait(semaphore_signalisation) == 0) { if (sem_wait(semaphore_arret_signalisation) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; } if ((*s_queue_signaux).requete_arret == d_vrai) { sem_post(semaphore_arret_signalisation); sem_post(semaphore_signalisation); break; } sem_post(semaphore_arret_signalisation); sem_post(semaphore_signalisation); nombre_signaux_envoyes = 0; sched_yield(); // Dans un premier temps, on verrouille la queue des signaux // affectée au processus courant pour vérifier s'il y a quelque // chose à traiter. sem_wait(semaphore_queue_signaux); if ((*s_queue_signaux).pointeur_lecture != (*s_queue_signaux).pointeur_ecriture) { // Attention : raise() envoit le signal au thread appelant ! // kill() l'envoie au processus appelant, donc dans notre // cas à un thread aléatoire du processus, ce qui nous // convient tout à fait puisqu'il s'agit de débloquer les // appels système lents. nombre_signaux_envoyes++; kill(getpid(), SIGALRM); } sem_post(semaphore_queue_signaux); // Dans un second temps, on balaye toutes les queues de signaux // des threads du processus courant. // Attention : l'ordre de verrouillage des mutexes est important // pour éviter les conditions bloquantes ! pthread_mutex_lock(&mutex_liste_threads); l_element_courant = liste_threads; while(l_element_courant != NULL) { if ((*((struct_thread *) (*l_element_courant).donnee)).pid == getpid()) { pthread_mutex_lock(&((*(*((struct_thread *) (*l_element_courant).donnee)).s_etat_processus) .mutex_signaux)); if ((*(*((struct_thread *) (*l_element_courant).donnee)) .s_etat_processus).pointeur_signal_ecriture != (*(*((struct_thread *) (*l_element_courant) .donnee)).s_etat_processus) .pointeur_signal_lecture) { nombre_signaux_envoyes++; pthread_kill((*((struct_thread *) (*l_element_courant).donnee)).tid, SIGALRM); } pthread_mutex_unlock(&((*(*((struct_thread *) (*l_element_courant).donnee)).s_etat_processus) .mutex_signaux)); } l_element_courant = (*l_element_courant).suivant; } pthread_mutex_unlock(&mutex_liste_threads); // Nanosleep if (nombre_signaux_envoyes > 0) { nanosleep(&attente, NULL); } } else { if (errno != EINTR) { (*s_etat_processus).erreur_systeme = d_es_processus; } } } pthread_exit(NULL); } 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; } // Le thread ne peut plus traiter de signaux explicites. Il convient // alors de corriger le sémaphore pour annuler les signaux en attente. while((*(*((struct_thread *) (*l_element_courant).donnee)).s_etat_processus) .pointeur_signal_ecriture != (*(*((struct_thread *) (*l_element_courant).donnee)).s_etat_processus) .pointeur_signal_lecture) { while(sem_wait(semaphore_signalisation) != 0) { if (errno != EINTR) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } } (*(*((struct_thread *) (*l_element_courant).donnee)).s_etat_processus) .pointeur_signal_lecture = ((*(*((struct_thread *) (*l_element_courant).donnee)).s_etat_processus) .pointeur_signal_lecture + 1) % LONGUEUR_QUEUE_SIGNAUX; } 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)) { # ifndef SEMAPHORES_NOMMES while(sem_wait(&((*(*((struct_thread *) (*l_element_courant) .donnee)).s_etat_processus).semaphore_fork)) == -1) # else while(sem_wait((*(*((struct_thread *) (*l_element_courant) .donnee)).s_etat_processus).semaphore_fork) == -1) # endif { (*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)) { # ifndef SEMAPHORES_NOMMES if (sem_post(&((*(*((struct_thread *) (*l_element_courant).donnee)).s_etat_processus) .semaphore_fork)) != 0) # else if (sem_post((*(*((struct_thread *) (*l_element_courant).donnee)).s_etat_processus) .semaphore_fork) != 0) # endif { 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; struct_liste_variables_partagees *l_element_partage_courant; struct_liste_variables_partagees *l_element_partage_suivant; struct_liste_variables_statiques *l_element_statique_courant; struct_liste_variables_statiques *l_element_statique_suivant; integer8 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_elements_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_elements_attente[0]); close((*s_argument_thread).pipe_interruptions[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; } } // ne peut être effacé qu'une seule fois if (suppression_variables_partagees == d_faux) { suppression_variables_partagees = d_vrai; liberation_arbre_variables_partagees(s_etat_processus, (*(*s_etat_processus).s_arbre_variables_partagees)); l_element_partage_courant = (*(*s_etat_processus) .l_liste_variables_partagees); while(l_element_partage_courant != NULL) { l_element_partage_suivant = (*l_element_partage_courant).suivant; free(l_element_partage_courant); l_element_partage_courant = l_element_partage_suivant; } } liberation_arbre_variables(s_etat_processus, (*s_etat_processus).s_arbre_variables, d_faux); l_element_statique_courant = (*s_etat_processus) .l_liste_variables_statiques; while(l_element_statique_courant != NULL) { l_element_statique_suivant = (*l_element_statique_courant).suivant; free(l_element_statique_courant); l_element_statique_courant = l_element_statique_suivant; } 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); # ifndef SEMAPHORES_NOMMES sem_post(&((*s_etat_processus).semaphore_fork)); sem_destroy(&((*s_etat_processus).semaphore_fork)); # else sem_post((*s_etat_processus).semaphore_fork); sem_close((*s_etat_processus).semaphore_fork); # endif liberation_contexte_cas(s_etat_processus); liberation_allocateur_buffer(s_etat_processus); sys_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_elements_attente[0]); close((*s_argument_thread).pipe_interruptions[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; if (pthread_mutex_lock(&mutex_liste_threads) != 0) { return(NULL); } 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. */ pthread_mutex_unlock(&mutex_liste_threads); return(NULL); } s_etat_processus = (*((struct_thread *) (*l_element_courant).donnee)).s_etat_processus; if (pthread_mutex_unlock(&mutex_liste_threads) != 0) { return(NULL); } 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) { # ifndef SEMAPHORES_NOMMES if (sem_post(&((*s_etat_processus).semaphore_fork)) != 0) # else if (sem_post((*s_etat_processus).semaphore_fork) != 0) # endif { BUG(1, uprintf("Lock error !\n")); return; } return; } static inline void deverrouillage_gestionnaire_signaux(struct_processus *s_etat_processus) { # ifndef SEMAPHORES_NOMMES while(sem_wait(&((*s_etat_processus).semaphore_fork)) != 0) # else while(sem_wait((*s_etat_processus).semaphore_fork) != 0) # endif { if (errno != EINTR) { BUG(1, uprintf("Unlock error !\n")); return; } } return; } /* ================================================================================ Fonctions de gestion des signaux dans les threads. Lorsqu'un processus reçoit un signal, il appelle le gestionnaire de signal associé qui ne fait qu'envoyer au travers de write() le signal reçus dans un pipe. Un second thread est bloqué sur ce pipe et effectue le traitement adéquat pour le signal donné. ================================================================================ */ #define test_signal(signal) \ if (signal_test == SIGTEST) { signal_test = signal; return; } static int pipe_signaux; logical1 lancement_thread_signaux(struct_processus *s_etat_processus) { pthread_attr_t attributs; void *argument; if (pipe((*s_etat_processus).pipe_signaux) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return(d_erreur); } pipe_signaux = (*s_etat_processus).pipe_signaux[1]; if (pthread_attr_init(&attributs) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return(d_erreur); } if (pthread_attr_setdetachstate(&attributs, PTHREAD_CREATE_JOINABLE) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return(d_erreur); } argument = (*s_etat_processus).pipe_signaux; if (pthread_create(&((*s_etat_processus).thread_signaux), &attributs, thread_signaux, argument) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return(d_erreur); } return(d_absence_erreur); } logical1 arret_thread_signaux(struct_processus *s_etat_processus) { unsigned char signal; ssize_t n; signal = (unsigned char ) (rpl_sigmax & 0xFF); do { n = write((*s_etat_processus).pipe_signaux[1], &signal, sizeof(signal)); if (n < 0) { return(d_erreur); } } while(n != 1); pthread_join((*s_etat_processus).thread_signaux, NULL); close((*s_etat_processus).pipe_signaux[0]); close((*s_etat_processus).pipe_signaux[1]); return(d_absence_erreur); } void * thread_signaux(void *argument) { int *pipe; sigset_t masque; struct pollfd fds; unsigned char signal; pipe = (int *) argument; fds.fd = pipe[0]; fds.events = POLLIN; fds.revents = 0; sigfillset(&masque); pthread_sigmask(SIG_BLOCK, &masque, NULL); do { if (poll(&fds, 1, -1) == -1) { pthread_exit(NULL); } # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunused-result" read(fds.fd, &signal, 1); # pragma GCC diagnostic pop if (signal != (0xFF & rpl_sigmax)) { envoi_signal_processus(getpid(), signal); // Un signal SIGALRM est envoyé par le thread de surveillance // des signaux jusqu'à ce que les signaux soient tous traités. } } while(signal != (0xFF & rpl_sigmax)); pthread_exit(NULL); } // Récupération des signaux // - SIGINT (arrêt au clavier) // - SIGTERM (signal d'arrêt en provenance du système) void interruption1(int signal) { unsigned char signal_tronque; test_signal(signal); # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunused-result" switch(signal) { case SIGINT: signal_tronque = (unsigned char) (rpl_sigint & 0xFF); write(pipe_signaux, &signal_tronque, sizeof(signal_tronque)); break; case SIGTERM: signal_tronque = (unsigned char) (rpl_sigterm & 0xFF); write(pipe_signaux, &signal_tronque, sizeof(signal_tronque)); break; case SIGUSR1: signal_tronque = (unsigned char) (rpl_sigalrm & 0xFF); write(pipe_signaux, &signal_tronque, sizeof(signal_tronque)); break; default: // SIGALRM break; } # pragma GCC diagnostic pop 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) { unsigned char signal_tronque; test_signal(signal); signal_tronque = (unsigned char) (rpl_sigtstp & 0xFF); # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunused-result" write(pipe_signaux, &signal_tronque, sizeof(signal_tronque)); # pragma GCC diagnostic pop 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_1[] = "+++System : Uncaught access violation\n" "+++System : Aborting !\n"; unsigned char message_2[] = "+++System : Stack overflow\n" "+++System : Aborting !\n"; test_signal(signal); if (pid_processus_pere == getpid()) { kill(pid_processus_pere, SIGUSR1); } # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunused-result" if (signal != SIGUSR2) { write(STDERR_FILENO, message_1, strlen(message_1)); } else { write(STDERR_FILENO, message_2, strlen(message_2)); } # pragma GCC diagnostic pop _exit(EXIT_FAILURE); } // Récupération des signaux // - SIGHUP void interruption4(int signal) { unsigned char signal_tronque; test_signal(signal); signal_tronque = (unsigned char) (rpl_sighup & 0xFF); # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunused-result" write(pipe_signaux, &signal_tronque, sizeof(signal_tronque)); # pragma GCC diagnostic pop return; } // Récupération des signaux // - SIGPIPE void interruption5(int signal) { unsigned char message[] = "+++System : SIGPIPE\n" "+++System : Aborting !\n"; unsigned char signal_tronque; test_signal(signal); # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunused-result" if (pid_processus_pere == getpid()) { signal_tronque = (unsigned char) (rpl_sigalrm & 0xFF); write(pipe_signaux, &signal_tronque, sizeof(signal_tronque)); } write(STDERR_FILENO, message, strlen(message)); # pragma GCC diagnostic pop 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; pthread_mutex_t exclusion = PTHREAD_MUTEX_INITIALIZER; 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; pthread_mutex_lock(&exclusion); if ((*s_etat_processus).var_volatile_requete_arret == -1) { deverrouillage_gestionnaire_signaux(s_etat_processus); pthread_mutex_unlock(&exclusion); return; } (*s_etat_processus).var_volatile_requete_arret = -1; (*s_etat_processus).var_volatile_alarme = -1; pthread_mutex_unlock(&exclusion); } } 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; } 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; } static void sortie_interruption_depassement_pile(void *arg1, void *arg2, void *arg3) { switch((*((volatile int *) arg1))) { case 1: longjmp(contexte_ecriture, -1); break; case 2: longjmp(contexte_impression, -1); break; } return; } void interruption_depassement_pile(int urgence, stackoverflow_context_t scp) { if ((urgence == 0) && (routine_recursive != 0)) { // On peut tenter de récupérer le dépassement de pile. Si la variable // 'routine_recursive' est non nulle, on récupère l'erreur. sigsegv_leave_handler(sortie_interruption_depassement_pile, (void *) &routine_recursive, NULL, NULL); } // Ici, la panique est totale et il vaut mieux quitter l'application. interruption3(SIGUSR2); return; } int interruption_violation_access(void *adresse_fautive, int gravite) { unsigned char message[] = "+++System : Trying to catch access " "violation\n"; static int compteur_erreur = 0; if ((gravite == 0) && (routine_recursive != 0)) { // Il peut s'agir d'un dépassement de pile. sigsegv_leave_handler(sortie_interruption_depassement_pile, (void *) &routine_recursive, NULL, NULL); } // On est dans une bonne vieille violation d'accès. On essaie // de fermer au mieux l'application. compteur_erreur++; if (compteur_erreur >= 2) { // Erreurs multiples, on arrête l'application. interruption3(SIGSEGV); return(0); } # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunused-result" write(STDERR_FILENO, message, strlen(message)); # pragma GCC diagnostic pop if (pid_processus_pere == getpid()) { longjmp(contexte_initial, -1); return(1); } else { longjmp(contexte_processus, -1); return(1); } // On renvoie 0 parce qu'on décline toute responsabilité quant à la // suite des événements... return(0); } // 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).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; } 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).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()) { (*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; } 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-%llu-%llu", (unsigned long long) getpid(), (unsigned long long) pthread_self()); # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunused-result" if ((fichier = fopen(nom, "w+")) != NULL) { fclose(fichier); freopen(nom, "w", stdout); freopen(nom, "w", stderr); } freopen("/dev/null", "r", stdin); # pragma GCC diagnostic pop 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 : Signal inconnu (%d) !\n", signal); } else { printf("+++System : Spurious signal (%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. if (sem_trywait(semaphore_queue_signaux) == 0) { while((*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 IPCS_SYSV if (msync(s_queue_signaux, sizeof(s_queue_signaux), MS_ASYNC | MS_INVALIDATE) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } # endif while(sem_wait(semaphore_signalisation) != 0) { if (errno != EINTR) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } } } sem_post(semaphore_queue_signaux); } // Interruptions qui arrivent depuis le groupe courant de threads. if (pthread_mutex_trylock(&((*s_etat_processus).mutex_signaux)) == 0) { while((*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; while(sem_wait(semaphore_signalisation) != 0) { if (errno != EINTR) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } } } pthread_mutex_unlock(&((*s_etat_processus).mutex_signaux)); } 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 = sys_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 = sys_malloc((10 + 256 + 1) * sizeof(unsigned char))) == NULL) { return(NULL); } sprintf(fichier, "\\SHAREMEM\\RPL-SIGQUEUES-%d", (int) pid); # endif // OS2 # else // POSIX if ((fichier = sys_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) { # ifndef OS2 int segment; # endif # ifndef IPCS_SYSV sem_t *semaphore; sem_t *signalisation; # else sem_t *semaphore; sem_t *signalisation; # ifndef OS2 int desc; key_t clef; # endif # 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); } while(sem_wait(semaphore_queue_signaux) != 0) { if (errno != EINTR) { 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 IPCS_SYSV if (msync(s_queue_signaux, sizeof(s_queue_signaux), MS_ASYNC | MS_INVALIDATE) != 0) { return(1); } # endif if (sem_post(semaphore_queue_signaux) != 0) { return(1); } if (sem_post(semaphore_signalisation) != 0) { return(1); } } else { // Le signal est envoyé depuis un processus distinct. # ifdef IPCS_SYSV if ((nom = nom_segment(racine_segment, pid)) == NULL) { return(1); } # ifndef OS2 // SysV if ((desc = open(nom, O_RDWR)) == -1) { sys_free(nom); return(1); } close(desc); if ((clef = ftok(nom, 1)) == -1) { sys_free(nom); return(1); } sys_free(nom); if ((segment = shmget(clef, sizeof(struct_queue_signaux), 0)) == -1) { return(1); } queue = shmat(segment, NULL, 0); # else // OS/2 if (DosGetNamedSharedMem((PVOID) &queue, nom, PAG_WRITE | PAG_READ) != 0) { sys_free(nom); return(1); } sys_free(nom); # endif # else // POSIX if ((nom = nom_segment(racine_segment, pid)) == NULL) { return(1); } if ((segment = shm_open(nom, O_RDWR, 0)) == -1) { sys_free(nom); return(1); } sys_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. if ((semaphore = sem_open2(pid, SEM_QUEUE)) == SEM_FAILED) { return(1); } if ((signalisation = sem_open2(pid, SEM_SIGNALISATION)) == SEM_FAILED) { return(1); } while(sem_wait(semaphore) != 0) { if (errno != EINTR) { sem_close(semaphore); sem_close(signalisation); return(1); } } (*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 if (msync(queue, sizeof(queue), MS_ASYNC | MS_INVALIDATE) != 0) { sem_close(semaphore); sem_close(signalisation); return(1); } # endif if (sem_post(semaphore) != 0) { sem_close(semaphore); sem_close(signalisation); return(1); } if (sem_close(semaphore) != 0) { return(1); } if (sem_post(signalisation) != 0) { sem_close(signalisation); return(1); } if (sem_close(signalisation) != 0) { return(1); } # ifndef IPCS_SYSV // POSIX if (munmap(queue, sizeof(struct_queue_signaux)) != 0) { close(segment); return(1); } # else // IPCS_SYSV # ifndef OS2 // SysV if (shmdt(queue) != 0) { return(1); } # else // OS/2 // Pendant de DosGetNamedSHaredMem() # endif # 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); } s_etat_processus = (*((struct_thread *) (*l_element_courant).donnee)) .s_etat_processus; if (pthread_mutex_lock(&((*s_etat_processus).mutex_signaux)) != 0) { pthread_mutex_unlock(&mutex_liste_threads); return(1); } (*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(&((*s_etat_processus).mutex_signaux)) != 0) { pthread_mutex_unlock(&mutex_liste_threads); return(1); } if (pthread_mutex_unlock(&mutex_liste_threads) != 0) { return(1); } if (sem_post(semaphore_signalisation) != 0) { return(1); } return(0); } int envoi_signal_contexte(struct_processus *s_etat_processus_a_signaler, enum signaux_rpl signal) { pthread_mutex_lock(&((*s_etat_processus_a_signaler).mutex_signaux)); (*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(&((*s_etat_processus_a_signaler).mutex_signaux)); if (sem_post(semaphore_signalisation) != 0) { return(1); } 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) { pthread_attr_t attributs; 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) { sys_free(nom); (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } if (ftruncate(f_queue_signaux, sizeof(struct_queue_signaux)) == -1) { sys_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) { sys_free(nom); (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } sys_free(nom); (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } sys_free(nom); if ((semaphore_queue_signaux = sem_init2(1, getpid(), SEM_QUEUE)) == SEM_FAILED) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } if ((semaphore_signalisation = sem_init2(0, getpid(), SEM_SIGNALISATION)) == SEM_FAILED) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } if ((semaphore_arret_signalisation = sem_init2(1, getpid(), SEM_ARRET_SIGNALISATION)) == SEM_FAILED) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } (*s_queue_signaux).pointeur_lecture = 0; (*s_queue_signaux).pointeur_ecriture = 0; (*s_queue_signaux).requete_arret = d_faux; if (msync(s_queue_signaux, sizeof(struct_queue_signaux), MS_SYNC)) { (*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); sys_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; } if ((semaphore_queue_signaux = sem_init2(1, getpid(), SEM_QUEUE)) == SEM_FAILED) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } if ((semaphore_signalisation = sem_init2(0, getpid(), SEM_SIGNALISATION)) == SEM_FAILED) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } if ((semaphore_arret_signalisation = sem_init2(1, getpid(), SEM_ARRET_SIGNALISATION)) == SEM_FAILED) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } (*s_queue_signaux).pointeur_lecture = 0; (*s_queue_signaux).pointeur_ecriture = 0; (*s_queue_signaux).requete_arret = d_faux; # else // OS/2 if ((nom = nom_segment(NULL, getpid())) == NULL) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } if (DosAllocSharedMem((PVOID) &s_queue_signaux, nom, sizeof(struct_queue_signaux), PAG_WRITE | PAG_READ | PAG_COMMIT) != 0) { sys_free(nom); (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } sys_free(nom); sem_init(&((*s_queue_signaux).semaphore), 1, 1); sem_init(&((*s_queue_signaux).signalisation), 1, 0); sem_init(&((*s_queue_signaux).arret_signalisation), 1, 1); (*s_queue_signaux).pointeur_lecture = 0; (*s_queue_signaux).pointeur_ecriture = 0; (*s_queue_signaux).requete_arret = d_faux; # endif # endif // Lancement du thread de récupération des signaux. if (pthread_attr_init(&attributs) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } if (pthread_attr_setdetachstate(&attributs, PTHREAD_CREATE_JOINABLE) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } # ifdef SCHED_OTHER if (pthread_attr_setschedpolicy(&attributs, SCHED_OTHER) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } # endif # ifdef PTHREAD_EXPLICIT_SCHED if (pthread_attr_setinheritsched(&attributs, PTHREAD_EXPLICIT_SCHED) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } # endif # ifdef PTHREAD_SCOPE_SYSTEM if (pthread_attr_setscope(&attributs, PTHREAD_SCOPE_SYSTEM) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } # endif if (pthread_attr_destroy(&attributs) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } if (pthread_create(&((*s_queue_signaux).thread_signaux), &attributs, thread_surveillance_signaux, s_etat_processus) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } 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) { sem_wait(semaphore_arret_signalisation); (*s_queue_signaux).requete_arret = d_vrai; # ifndef IPCS_SYSV msync(s_queue_signaux, sizeof(s_queue_signaux), MS_ASYNC | MS_INVALIDATE); # endif sem_post(semaphore_arret_signalisation); // Incrémenter le sémaphore pour être sûr de le débloquer. sem_post(semaphore_signalisation); pthread_join((*s_queue_signaux).thread_signaux, NULL); # 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 sem_close(semaphore_queue_signaux); sem_close(semaphore_signalisation); sem_close(semaphore_arret_signalisation); 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) { # ifndef OS2 unsigned char *nom; # endif sem_wait(semaphore_arret_signalisation); (*s_queue_signaux).requete_arret = d_vrai; # ifndef IPCS_SYSV msync(s_queue_signaux, sizeof(s_queue_signaux), MS_ASYNC | MS_INVALIDATE); # endif sem_post(semaphore_arret_signalisation); // Incrémenter le sémaphore pour être sûr de le débloquer. sem_post(semaphore_signalisation); pthread_join((*s_queue_signaux).thread_signaux, NULL); # ifdef IPCS_SYSV // SystemV # ifndef OS2 // Il faut commencer par éliminer le sémaphore. if (semctl((*semaphore_queue_signaux).sem, 0, IPC_RMID) == -1) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } unlink((*semaphore_queue_signaux).path); sys_free((*semaphore_queue_signaux).path); if (semctl((*semaphore_signalisation).sem, 0, IPC_RMID) == -1) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } unlink((*semaphore_signalisation).path); sys_free((*semaphore_signalisation).path); if (semctl((*semaphore_arret_signalisation).sem, 0, IPC_RMID) == -1) { (*s_etat_processus).erreur_systeme = d_es_processus; return; } unlink((*semaphore_arret_signalisation).path); sys_free((*semaphore_arret_signalisation).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); sys_free(nom); # else sem_close(&((*s_queue_signaux).semaphore)); sem_destroy(&((*s_queue_signaux).semaphore)); sem_close(&((*s_queue_signaux).signalisation)); sem_destroy(&((*s_queue_signaux).signalisation)); sem_close(&((*s_queue_signaux).arret_signalisation)); sem_destroy(&((*s_queue_signaux).arret_signalisation)); if (DosFreeMem(s_queue_signaux) != 0) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } # endif # else // POSIX sem_destroy2(semaphore_queue_signaux, getpid(), SEM_QUEUE); sem_destroy2(semaphore_signalisation, getpid(), SEM_SIGNALISATION); sem_destroy2(semaphore_arret_signalisation, getpid(), SEM_ARRET_SIGNALISATION); 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) { sys_free(nom); (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } sys_free(nom); # endif return; } // vim: ts=4