--- rpl/src/gestion_objets.c 2010/02/05 19:02:56 1.3 +++ rpl/src/gestion_objets.c 2020/01/10 11:15:42 1.148 @@ -1,7 +1,7 @@ /* ================================================================================ - RPL/2 (R) version 4.0.10 - Copyright (C) 1989-2010 Dr. BERTRAND Joël + RPL/2 (R) version 4.1.32 + Copyright (C) 1989-2020 Dr. BERTRAND Joël This file is part of RPL/2. @@ -20,12 +20,12 @@ */ -#include "rpl.conv.h" +#include "rpl-conv.h" /* ================================================================================ - Routine de gestion du nombre d'occurrences comme grandeur atomique + Routines de gestion du nombre d'occurrences comme grandeur atomique ================================================================================ entrées : structure sur l'état du processus et objet à afficher -------------------------------------------------------------------------------- @@ -57,7 +57,7 @@ decrementation_atomique(struct_objet *s_ return((*s_objet).nombre_occurrences); } -inline void +void initialisation_objet(struct_objet *s_objet) { pthread_mutexattr_t attributs_mutex; @@ -106,11 +106,19 @@ initialisation_allocateur(struct_process (*s_etat_processus).pointeur_int = 0; (*s_etat_processus).pointeur_mat = 0; (*s_etat_processus).pointeur_nom = 0; + (*s_etat_processus).pointeur_rec = 0; (*s_etat_processus).pointeur_rel = 0; (*s_etat_processus).pointeur_tab = 0; (*s_etat_processus).pointeur_vec = 0; (*s_etat_processus).pointeur_maillons = 0; + (*s_etat_processus).pointeur_variables_noeud = 0; + (*s_etat_processus).pointeur_variables_partagees_noeud = 0; + (*s_etat_processus).pointeur_variables_feuille = 0; + (*s_etat_processus).pointeur_variables_variable = 0; + (*s_etat_processus).pointeur_variables_tableau_noeuds = 0; + (*s_etat_processus).pointeur_variables_tableau_noeuds_partages = 0; + return; } @@ -134,6 +142,8 @@ liberation_allocateur(struct_processus * free((*s_etat_processus).objets_mat[i++])); for(i = 0; i < (*s_etat_processus).pointeur_nom; free((*s_etat_processus).objets_nom[i++])); + for(i = 0; i < (*s_etat_processus).pointeur_rec; + free((*s_etat_processus).objets_rec[i++])); for(i = 0; i < (*s_etat_processus).pointeur_rel; free((*s_etat_processus).objets_rel[i++])); for(i = 0; i < (*s_etat_processus).pointeur_tab; @@ -143,6 +153,20 @@ liberation_allocateur(struct_processus * for(i = 0; i < (*s_etat_processus).pointeur_maillons; free((*s_etat_processus).maillons[i++])); + for(i = 0; i < (*s_etat_processus).pointeur_variables_noeud; + free((*s_etat_processus).variables_noeud[i++])); + for(i = 0; i < (*s_etat_processus).pointeur_variables_partagees_noeud; + free((*s_etat_processus).variables_partagees_noeud[i++])); + for(i = 0; i < (*s_etat_processus).pointeur_variables_feuille; + free((*s_etat_processus).variables_feuille[i++])); + for(i = 0; i < (*s_etat_processus).pointeur_variables_variable; + free((*s_etat_processus).variables_variable[i++])); + for(i = 0; i < (*s_etat_processus).pointeur_variables_tableau_noeuds; + free((*s_etat_processus).variables_tableau_noeuds[i++])); + for(i = 0; i < (*s_etat_processus) + .pointeur_variables_tableau_noeuds_partages; + free((*s_etat_processus).variables_tableau_noeuds_partages[i++])); + { struct_liste_chainee *l_element_courant; struct_liste_chainee *l_element_suivant; @@ -224,6 +248,7 @@ allocation_maillon(struct_processus *s_e { if ((s_maillon = malloc(sizeof(struct_liste_chainee))) == NULL) { + (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return(NULL); } } @@ -234,7 +259,7 @@ allocation_maillon(struct_processus *s_e /* ================================================================================ - Routine d'allocation d'un maillon d'un objet (liste, expression...) + Routine de libération d'un maillon d'un objet (liste, expression...) ================================================================================ Entrées : structure sur l'état du processus et objet à afficher -------------------------------------------------------------------------------- @@ -266,7 +291,7 @@ liberation_maillon(struct_processus *s_e ================================================================================ Routine d'allocation d'une structure *s_objet ================================================================================ - Entrées : structure sur l'état du processus et objet à afficher + Entrées : structure sur l'état du processus et objet à allouer -------------------------------------------------------------------------------- Sorties : chaine de caractères -------------------------------------------------------------------------------- @@ -274,17 +299,30 @@ liberation_maillon(struct_processus *s_e ================================================================================ */ -void * +struct_objet * allocation(struct_processus *s_etat_processus, enum t_type type) { struct_objet *s_objet; + if (pthread_mutex_lock(&((*s_etat_processus).mutex_allocation)) != 0) + { + (*s_etat_processus).erreur_systeme = d_es_processus; + return(NULL); + } + if ((*s_etat_processus).pile_objets == NULL) { + if (pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation)) != 0) + { + (*s_etat_processus).erreur_systeme = d_es_processus; + return(NULL); + } + // Il n'existe aucune structure struct_objet disponible dans le cache. if ((s_objet = malloc(sizeof(struct_objet))) == NULL) { + (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return(NULL); } @@ -299,9 +337,17 @@ allocation(struct_processus *s_etat_proc (*s_etat_processus).taille_pile_objets--; (*s_objet).nombre_occurrences = 1; + + if (pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation)) != 0) + { + (*s_etat_processus).erreur_systeme = d_es_processus; + return(NULL); + } } (*s_objet).type = type; + (*s_objet).extension_type = 0; + (*s_objet).descripteur_bibliotheque = NULL; switch(type) { @@ -314,8 +360,10 @@ allocation(struct_processus *s_etat_proc } else { - if (((*s_objet).objet = malloc(sizeof(unsigned long))) == NULL) + if (((*s_objet).objet = malloc(sizeof(integer8))) == NULL) { + (*s_etat_processus).erreur_systeme = + d_es_allocation_memoire; free(s_objet); return(NULL); } @@ -341,6 +389,8 @@ allocation(struct_processus *s_etat_proc { if (((*s_objet).objet = malloc(sizeof(logical8))) == NULL) { + (*s_etat_processus).erreur_systeme = + d_es_allocation_memoire; free(s_objet); return(NULL); } @@ -367,6 +417,8 @@ allocation(struct_processus *s_etat_proc if (((*s_objet).objet = malloc(sizeof(struct_complexe16))) == NULL) { + (*s_etat_processus).erreur_systeme = + d_es_allocation_memoire; free(s_objet); return(NULL); } @@ -379,6 +431,7 @@ allocation(struct_processus *s_etat_proc { if (((*s_objet).objet = malloc(sizeof(struct_fichier))) == NULL) { + (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; free(s_objet); return(NULL); } @@ -386,6 +439,12 @@ allocation(struct_processus *s_etat_proc break; } + case EXT : + { + // Aucune allocation + break; + } + case FCT : { if ((*s_etat_processus).pointeur_fct > 0) @@ -398,12 +457,17 @@ allocation(struct_processus *s_etat_proc if (((*s_objet).objet = malloc(sizeof(struct_fonction))) == NULL) { + (*s_etat_processus).erreur_systeme = + d_es_allocation_memoire; free(s_objet); return(NULL); } } + (*((struct_fonction *) (*s_objet).objet)).fonction = NULL; (*((struct_fonction *) (*s_objet).objet)).prediction_saut = NULL; + (*((struct_fonction *) (*s_objet).objet)).prediction_execution + = d_faux; break; } @@ -418,6 +482,8 @@ allocation(struct_processus *s_etat_proc { if (((*s_objet).objet = malloc(sizeof(integer8))) == NULL) { + (*s_etat_processus).erreur_systeme = + d_es_allocation_memoire; free(s_objet); return(NULL); } @@ -443,6 +509,8 @@ allocation(struct_processus *s_etat_proc { if (((*s_objet).objet = malloc(sizeof(struct_matrice))) == NULL) { + (*s_etat_processus).erreur_systeme = + d_es_allocation_memoire; free(s_objet); return(NULL); } @@ -466,6 +534,8 @@ allocation(struct_processus *s_etat_proc { if (((*s_objet).objet = malloc(sizeof(struct_matrice))) == NULL) { + (*s_etat_processus).erreur_systeme = + d_es_allocation_memoire; free(s_objet); return(NULL); } @@ -489,6 +559,8 @@ allocation(struct_processus *s_etat_proc { if (((*s_objet).objet = malloc(sizeof(struct_matrice))) == NULL) { + (*s_etat_processus).erreur_systeme = + d_es_allocation_memoire; free(s_objet); return(NULL); } @@ -505,10 +577,12 @@ allocation(struct_processus *s_etat_proc { if (((*s_objet).objet = malloc(sizeof(struct_mutex))) == NULL) { + (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; free(s_objet); return(NULL); } + (*((struct_mutex *) (*s_objet).objet)).tid = pthread_self(); break; } @@ -523,6 +597,8 @@ allocation(struct_processus *s_etat_proc { if (((*s_objet).objet = malloc(sizeof(struct_nom))) == NULL) { + (*s_etat_processus).erreur_systeme = + d_es_allocation_memoire; free(s_objet); return(NULL); } @@ -542,6 +618,7 @@ allocation(struct_processus *s_etat_proc if (((*s_objet).objet = malloc(sizeof(struct_processus_fils))) == NULL) { + (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; free(s_objet); return(NULL); } @@ -549,6 +626,28 @@ allocation(struct_processus *s_etat_proc break; } + case REC : + { + if ((*s_etat_processus).pointeur_rec > 0) + { + (*s_objet).objet = (*s_etat_processus).objets_rec + [--(*s_etat_processus).pointeur_rec]; + } + else + { + if (((*s_objet).objet = malloc(sizeof(struct_record))) + == NULL) + { + (*s_etat_processus).erreur_systeme = + d_es_allocation_memoire; + free(s_objet); + return(NULL); + } + } + + break; + } + case REL : { if ((*s_etat_processus).pointeur_rel > 0) @@ -560,6 +659,8 @@ allocation(struct_processus *s_etat_proc { if (((*s_objet).objet = malloc(sizeof(real8))) == NULL) { + (*s_etat_processus).erreur_systeme = + d_es_allocation_memoire; free(s_objet); return(NULL); } @@ -578,6 +679,7 @@ allocation(struct_processus *s_etat_proc { if (((*s_objet).objet = malloc(sizeof(struct_socket))) == NULL) { + (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; free(s_objet); return(NULL); } @@ -590,6 +692,7 @@ allocation(struct_processus *s_etat_proc if (((*s_objet).objet = malloc(sizeof(struct_bibliotheque))) == NULL) { + (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; free(s_objet); return(NULL); } @@ -601,6 +704,7 @@ allocation(struct_processus *s_etat_proc { if (((*s_objet).objet = malloc(sizeof(struct_semaphore))) == NULL) { + (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; free(s_objet); return(NULL); } @@ -613,6 +717,7 @@ allocation(struct_processus *s_etat_proc if (((*s_objet).objet = malloc(sizeof(struct_connecteur_sql))) == NULL) { + (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; free(s_objet); return(NULL); } @@ -631,6 +736,8 @@ allocation(struct_processus *s_etat_proc { if (((*s_objet).objet = malloc(sizeof(struct_tableau))) == NULL) { + (*s_etat_processus).erreur_systeme = + d_es_allocation_memoire; free(s_objet); return(NULL); } @@ -652,6 +759,8 @@ allocation(struct_processus *s_etat_proc { if (((*s_objet).objet = malloc(sizeof(struct_vecteur))) == NULL) { + (*s_etat_processus).erreur_systeme = + d_es_allocation_memoire; free(s_objet); return(NULL); } @@ -674,6 +783,8 @@ allocation(struct_processus *s_etat_proc { if (((*s_objet).objet = malloc(sizeof(struct_vecteur))) == NULL) { + (*s_etat_processus).erreur_systeme = + d_es_allocation_memoire; free(s_objet); return(NULL); } @@ -696,6 +807,8 @@ allocation(struct_processus *s_etat_proc { if (((*s_objet).objet = malloc(sizeof(struct_vecteur))) == NULL) { + (*s_etat_processus).erreur_systeme = + d_es_allocation_memoire; free(s_objet); return(NULL); } @@ -740,7 +853,9 @@ liberation(struct_processus *s_etat_proc struct_liste_chainee *l_element_courant; struct_liste_chainee *l_element_suivant; - unsigned long i; + integer8 i; + integer8 (*__type_drop)(struct_processus *, + void **); if (s_objet == NULL) { @@ -779,7 +894,7 @@ liberation(struct_processus *s_etat_proc } else { - free((unsigned long *) ((*s_objet).objet)); + free((*s_objet).objet); } break; @@ -846,7 +961,7 @@ liberation(struct_processus *s_etat_proc return; } - free((unsigned char *) ((*s_objet).objet)); + free((unsigned char *) (*s_objet).objet); break; } @@ -874,12 +989,21 @@ liberation(struct_processus *s_etat_proc { if (decrementation_atomique(s_objet) > 0) { + BUG((*(*((struct_fichier *) (*s_objet).objet)).format) + .nombre_occurrences <= 1, + pthread_mutex_unlock(&((*s_objet).mutex)), + printf("(*(*((struct_fichier *) (*s_objet).objet))" + ".format).nombre_occurrences=%ld\n", + (*(*((struct_fichier *) (*s_objet).objet)).format) + .nombre_occurrences)); + + liberation(s_etat_processus, + (*((struct_fichier *) (*s_objet).objet)).format); return; } liberation(s_etat_processus, (*((struct_fichier *) (*s_objet).objet)).format); - free((unsigned char *) (*((struct_fichier *) (*s_objet).objet)).nom); free((struct_fichier *) ((*s_objet).objet)); @@ -1059,6 +1183,28 @@ liberation(struct_processus *s_etat_proc return; } + if (pthread_mutex_trylock(&((*((struct_mutex *) + (*s_objet).objet)).mutex)) == 0) + { + // On a pu verrouiller le mutex. Il faut donc spécifier le tid. + (*((struct_mutex *) (*s_objet).objet)).tid = pthread_self(); + } + + if (pthread_equal(pthread_self(), + (*((struct_mutex *) (*s_objet).objet)).tid) != 0) + { + pthread_mutex_unlock(&((*((struct_mutex *) + (*s_objet).objet)).mutex)); + } + else + { + (*s_etat_processus).erreur_systeme = + d_es_mutex_acquis_autre_thread; + return; + } + + pthread_mutex_destroy(&((*((struct_mutex *) + (*s_objet).objet)).mutex)); free((struct_mutex *) (*s_objet).objet); break; } @@ -1092,14 +1238,13 @@ liberation(struct_processus *s_etat_proc return; } - free(s_objet); break; } case PRC : { if (pthread_mutex_lock(&((*(*((struct_processus_fils *) - (*s_objet).objet)).thread).mutex)) != 0) + (*s_objet).objet)).thread).mutex_nombre_references)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return; @@ -1109,7 +1254,8 @@ liberation(struct_processus *s_etat_proc .nombre_references--; BUG((*(*((struct_processus_fils *) (*s_objet).objet)).thread) - .nombre_references < 0, printf("(*(*((struct_processus_fils" + .nombre_references < 0, uprintf( + "(*(*((struct_processus_fils" " *) (*s_objet).objet)).thread).nombre_references = %d\n", (int) (*(*((struct_processus_fils *) (*s_objet).objet)) .thread).nombre_references)); @@ -1125,7 +1271,7 @@ liberation(struct_processus *s_etat_proc } if (pthread_mutex_unlock(&((*(*((struct_processus_fils *) - (*s_objet).objet)).thread).mutex)) != 0) + (*s_objet).objet)).thread).mutex_nombre_references)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return; @@ -1135,11 +1281,16 @@ liberation(struct_processus *s_etat_proc { pthread_mutex_destroy(&((*(*((struct_processus_fils *) (*s_objet).objet)).thread).mutex)); + pthread_mutex_destroy(&((*(*((struct_processus_fils *) + (*s_objet).objet)).thread).mutex_nombre_references)); free((*((struct_processus_fils *) (*s_objet).objet)).thread); } if (decrementation_atomique(s_objet) > 0) { + BUG(drapeau == d_vrai, uprintf("(*(*((struct_processus_fils" + " *) (*s_objet).objet)).thread).nombre_references " + "= 0 with nombre_occurrences > 0\n")); return; } @@ -1147,6 +1298,31 @@ liberation(struct_processus *s_etat_proc break; } + case REC : + { + liberation(s_etat_processus, + (*((struct_record *) (*s_objet).objet)).noms); + liberation(s_etat_processus, + (*((struct_record *) (*s_objet).objet)).donnees); + + if (decrementation_atomique(s_objet) > 0) + { + return; + } + + if ((*s_etat_processus).pointeur_rec < TAILLE_CACHE) + { + (*s_etat_processus).objets_rec + [(*s_etat_processus).pointeur_rec++] = (*s_objet).objet; + } + else + { + free((struct_record *) ((*s_objet).objet)); + } + + break; + } + case REL : { if (decrementation_atomique(s_objet) > 0) @@ -1205,11 +1381,22 @@ liberation(struct_processus *s_etat_proc { if (decrementation_atomique(s_objet) > 0) { + BUG((*(*((struct_socket *) (*s_objet).objet)).format) + .nombre_occurrences <= 1, + pthread_mutex_unlock(&((*s_objet).mutex)), + printf("(*(*((struct_socket *) (*s_objet).objet))" + ".format).nombre_occurrences=%ld\n", + (*(*((struct_socket *) (*s_objet).objet)).format) + .nombre_occurrences)); + + liberation(s_etat_processus, (*((struct_socket *) + (*s_objet).objet)).format); return; } liberation(s_etat_processus, (*((struct_socket *) (*s_objet).objet)).format); + free((unsigned char *) (*((struct_socket *) (*s_objet).objet)) .adresse); free((unsigned char *) (*((struct_socket *) (*s_objet).objet)) @@ -1267,7 +1454,7 @@ liberation(struct_processus *s_etat_proc .nombre_occurrences <= 1, pthread_mutex_unlock(&((*s_objet).mutex)), printf("(*((*((struct_tableau *) (*s_objet).objet))" - ".element[%lu])).nombre_occurrences=%ld\n", i, + ".element[%lld])).nombre_occurrences=%ld\n", i, (*((*((struct_tableau *) (*s_objet).objet)) .elements[i])).nombre_occurrences)); liberation(s_etat_processus, (*((struct_tableau *) @@ -1366,6 +1553,57 @@ liberation(struct_processus *s_etat_proc break; } + case EXT: + { + if (decrementation_atomique(s_objet) > 0) + { + return; + } + + // Appel de la fonction de liberation associée à l'objet + // externe. Le descripteur de bibliothèque est directement + // associé à la structure objet. + + l_element_courant = (*s_etat_processus).s_bibliotheques; + + while(l_element_courant != NULL) + { + if ((*((struct_bibliotheque *) (*l_element_courant).donnee)) + .descripteur == (*s_objet).descripteur_bibliotheque) + { + if ((__type_drop = dlsym((*s_objet) + .descripteur_bibliotheque, "__type_drop")) == NULL) + { + // La fonction de libération n'existe pas dans la + // bibliothèque. + + (*s_etat_processus).erreur_execution = + d_ex_type_externe_drop; + } + else + { + if (__type_drop(s_etat_processus, (void **) &s_objet) + == 0) + { + (*s_etat_processus).erreur_execution = + d_ex_type_externe_drop; + } + } + + break; + } + + l_element_courant = (*l_element_courant).suivant; + } + + if (l_element_courant == NULL) + { + (*s_etat_processus).erreur_execution = d_ex_type_externe_drop; + } + + break; + } + default : { if (pthread_mutex_unlock(&((*s_objet).mutex)) != 0) @@ -1393,30 +1631,36 @@ liberation(struct_processus *s_etat_proc return; } - if (s_etat_processus != NULL) + if (pthread_mutex_lock(&((*s_etat_processus).mutex_allocation)) != 0) { - if ((*s_etat_processus).taille_pile_objets < TAILLE_CACHE) - { - (*s_objet).objet = (*s_etat_processus).pile_objets; - (*s_etat_processus).pile_objets = s_objet; - (*s_etat_processus).taille_pile_objets++; - } - else - { - if (pthread_mutex_destroy(&((*s_objet).mutex)) != 0) - { - (*s_etat_processus).erreur_systeme = d_es_processus; - return; - } + (*s_etat_processus).erreur_systeme = d_es_processus; + return; + } - free(s_objet); - } + if ((*s_etat_processus).taille_pile_objets < TAILLE_CACHE) + { + (*s_objet).objet = (*s_etat_processus).pile_objets; + (*s_etat_processus).pile_objets = s_objet; + (*s_etat_processus).taille_pile_objets++; } else { + if (pthread_mutex_destroy(&((*s_objet).mutex)) != 0) + { + pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation)); + (*s_etat_processus).erreur_systeme = d_es_processus; + return; + } + free(s_objet); } + if (pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation)) != 0) + { + (*s_etat_processus).erreur_systeme = d_es_processus; + return; + } + return; } @@ -1456,8 +1700,9 @@ copie_objet(struct_processus *s_etat_pro struct_objet *s_nouvel_objet; struct_objet *s_objet_tampon; - unsigned long i; - unsigned long j; + integer8 i; + integer8 j; + integer8 (*__type_dup)(struct_processus *, void **); if (pthread_mutex_lock(&((*s_objet).mutex)) != 0) { @@ -1508,8 +1753,8 @@ copie_objet(struct_processus *s_etat_pro return(NULL); } - (*((unsigned long *) ((*s_nouvel_objet).objet))) = - (*((unsigned long *) ((*s_objet).objet))); + (*((integer8 *) ((*s_nouvel_objet).objet))) = + (*((integer8 *) ((*s_objet).objet))); break; } @@ -1574,7 +1819,7 @@ copie_objet(struct_processus *s_etat_pro (*l_element_courant_lecture).suivant; } - (*s_nouvel_objet).objet = (void *) ((struct_liste_chainee *) + (*s_nouvel_objet).objet = ((struct_liste_chainee *) l_element_base); } else // type == 'P' @@ -1626,7 +1871,7 @@ copie_objet(struct_processus *s_etat_pro return(NULL); } - (*s_nouvel_objet).objet = (void *) ((unsigned char *) + (*s_nouvel_objet).objet = ((unsigned char *) malloc((strlen((unsigned char *) ((*s_objet).objet)) + 1) * sizeof(unsigned char))); @@ -1720,7 +1965,7 @@ copie_objet(struct_processus *s_etat_pro (*l_element_courant_lecture).suivant; } - (*s_nouvel_objet).objet = (void *) ((struct_liste_chainee *) + (*s_nouvel_objet).objet = ((struct_liste_chainee *) l_element_base); } else // type == 'P' @@ -1746,6 +1991,14 @@ copie_objet(struct_processus *s_etat_pro if (type == 'P') { incrementation_atomique(s_objet); + + if (((*((struct_fichier *) ((*s_objet).objet))).format = + copie_objet(s_etat_processus, (*((struct_fichier *) + ((*s_objet).objet))).format, 'P')) == NULL) + { + return(NULL); + } + return(s_objet); } @@ -1919,7 +2172,7 @@ copie_objet(struct_processus *s_etat_pro (*l_element_courant_lecture).suivant; } - (*s_nouvel_objet).objet = (void *) ((struct_liste_chainee *) + (*s_nouvel_objet).objet = ((struct_liste_chainee *) l_element_base); } else @@ -1954,9 +2207,8 @@ copie_objet(struct_processus *s_etat_pro } (*((struct_matrice *) ((*s_nouvel_objet).objet))).tableau = - (void **) ((integer8 **) malloc( - ((*((struct_matrice *) ((*s_objet).objet))).nombre_lignes) - * sizeof(integer8 *))); + malloc(((size_t) ((*((struct_matrice *) + ((*s_objet).objet))).nombre_lignes)) * sizeof(integer8 *)); if ((*((struct_matrice *) ((*s_nouvel_objet).objet))).tableau == NULL) @@ -1978,9 +2230,9 @@ copie_objet(struct_processus *s_etat_pro { if ((((integer8 **) ((*((struct_matrice *) ((*s_nouvel_objet).objet))).tableau))[i] = - (void *) ((integer8 *) malloc( + ((integer8 *) malloc(((size_t) ((*((struct_matrice *) ((*s_objet).objet))) - .nombre_colonnes) * sizeof(integer8)))) == NULL) + .nombre_colonnes)) * sizeof(integer8)))) == NULL) { for(j = 0; j < i; j++) { @@ -2021,9 +2273,9 @@ copie_objet(struct_processus *s_etat_pro } (*((struct_matrice *) ((*s_nouvel_objet).objet))).tableau = - (void **) ((struct_complexe16 **) malloc( - ((*((struct_matrice *) ((*s_objet).objet))).nombre_lignes) - * sizeof(struct_complexe16 *))); + malloc(((size_t) ((*((struct_matrice *) + ((*s_objet).objet))).nombre_lignes)) + * sizeof(struct_complexe16 *)); if ((*((struct_matrice *) ((*s_nouvel_objet).objet))).tableau == NULL) @@ -2045,9 +2297,9 @@ copie_objet(struct_processus *s_etat_pro { if ((((struct_complexe16 **) ((*((struct_matrice *) ((*s_nouvel_objet).objet))).tableau))[i] = - (void *) ((struct_complexe16 *) malloc( + ((struct_complexe16 *) malloc(((size_t) ((*((struct_matrice *) ((*s_objet).objet))) - .nombre_colonnes) * sizeof(struct_complexe16)))) + .nombre_colonnes)) * sizeof(struct_complexe16)))) == NULL) { for(j = 0; j < i; j++) @@ -2088,9 +2340,8 @@ copie_objet(struct_processus *s_etat_pro } (*((struct_matrice *) ((*s_nouvel_objet).objet))).tableau = - (void **) ((real8 **) malloc( - ((*((struct_matrice *) ((*s_objet).objet))).nombre_lignes) - * sizeof(real8 *))); + malloc(((size_t) ((*((struct_matrice *) + ((*s_objet).objet))).nombre_lignes)) * sizeof(real8 *)); if ((*((struct_matrice *) ((*s_nouvel_objet).objet))).tableau == NULL) @@ -2112,9 +2363,9 @@ copie_objet(struct_processus *s_etat_pro { if ((((real8 **) ((*((struct_matrice *) ((*s_nouvel_objet).objet))).tableau))[i] = - (void *) ((real8 *) malloc( + ((real8 *) malloc(((size_t) ((*((struct_matrice *) ((*s_objet).objet))) - .nombre_colonnes) * sizeof(real8)))) == NULL) + .nombre_colonnes)) * sizeof(real8)))) == NULL) { for(j = 0; j < i; j++) { @@ -2142,20 +2393,9 @@ copie_objet(struct_processus *s_etat_pro case MTX : { - if (type != 'O') - { - incrementation_atomique(s_objet); - return(s_objet); - } - - if ((s_nouvel_objet = allocation(s_etat_processus, MTX)) == NULL) - { - return(NULL); - } - - (*((struct_mutex *) ((*s_nouvel_objet).objet))).mutex = - (*((struct_mutex *) ((*s_objet).objet))).mutex; - break; + // La duplication d'un mutex renvoie le même objet. + incrementation_atomique(s_objet); + return(s_objet); } case NOM : @@ -2197,19 +2437,24 @@ copie_objet(struct_processus *s_etat_pro return(s_objet); } + // Un objet de type NON est un objet encapsulé dans une + // structure de type struct_objet. Elle peut très bien contenir + // une donnée, mais c'est à l'utilisateur de la libérer + // explicitement avec un free(). + if ((s_nouvel_objet = allocation(s_etat_processus, NON)) == NULL) { return(NULL); } - (*s_nouvel_objet).objet = NULL; + (*s_nouvel_objet).objet = (*s_objet).objet; break; } case PRC : { if (pthread_mutex_lock(&((*(*((struct_processus_fils *) - (*s_objet).objet)).thread).mutex)) != 0) + (*s_objet).objet)).thread).mutex_nombre_references)) != 0) { return(NULL); } @@ -2218,7 +2463,7 @@ copie_objet(struct_processus *s_etat_pro .nombre_references++; if (pthread_mutex_unlock(&((*(*((struct_processus_fils *) - (*s_objet).objet)).thread).mutex)) != 0) + (*s_objet).objet)).thread).mutex_nombre_references)) != 0) { return(NULL); } @@ -2239,6 +2484,46 @@ copie_objet(struct_processus *s_etat_pro break; } + case REC : + { + if (type != 'P') + { + if ((s_nouvel_objet = allocation(s_etat_processus, REC)) + == NULL) + { + return(NULL); + } + + if (((*((struct_record *) (*s_nouvel_objet).objet)).noms = + copie_objet(s_etat_processus, (*((struct_record *) + (*s_objet).objet)).noms, 'P')) == NULL) + { + return(NULL); + } + + if (((*((struct_record *) (*s_nouvel_objet).objet)).donnees = + copie_objet(s_etat_processus, (*((struct_record *) + (*s_objet).objet)).donnees, type)) == NULL) + { + return(NULL); + } + } + else + { + incrementation_atomique(s_objet); + (*((struct_record *) (*s_objet).objet)).noms = + copie_objet(s_etat_processus, (*((struct_record *) + (*s_objet).objet)).noms, 'P'); + (*((struct_record *) (*s_objet).objet)).donnees = + copie_objet(s_etat_processus, (*((struct_record *) + (*s_objet).objet)).donnees, 'P'); + + return(s_objet); + } + + break; + } + case REL : { if (type != 'O') @@ -2262,6 +2547,15 @@ copie_objet(struct_processus *s_etat_pro if (type == 'P') { incrementation_atomique(s_objet); + + if (((*((struct_socket *) ((*s_objet).objet))) + .format = copie_objet(s_etat_processus, + (*((struct_socket *) ((*s_objet).objet))).format, 'P')) + == NULL) + { + return(NULL); + } + return(s_objet); } @@ -2292,6 +2586,18 @@ copie_objet(struct_processus *s_etat_pro (*((struct_socket *) ((*s_objet).objet))).pid; (*((struct_socket *) ((*s_nouvel_objet).objet))).tid = (*((struct_socket *) ((*s_objet).objet))).tid; + (*((struct_socket *) ((*s_nouvel_objet).objet))).options = + (*((struct_socket *) ((*s_objet).objet))).options; + (*((struct_socket *) ((*s_nouvel_objet).objet))).priorite = + (*((struct_socket *) ((*s_objet).objet))).priorite; + (*((struct_socket *) ((*s_nouvel_objet).objet))).buffer_reception = + (*((struct_socket *) ((*s_objet).objet))).buffer_reception; + (*((struct_socket *) ((*s_nouvel_objet).objet))).buffer_emission = + (*((struct_socket *) ((*s_objet).objet))).buffer_emission; + (*((struct_socket *) ((*s_nouvel_objet).objet))).timeout_reception = + (*((struct_socket *) ((*s_objet).objet))).timeout_reception; + (*((struct_socket *) ((*s_nouvel_objet).objet))).timeout_emission = + (*((struct_socket *) ((*s_objet).objet))).timeout_emission; if (((*((struct_socket *) ((*s_nouvel_objet).objet))).format = copie_objet(s_etat_processus, (*((struct_socket *) @@ -2401,6 +2707,8 @@ copie_objet(struct_processus *s_etat_pro return(NULL); } + (*((struct_semaphore *) (*s_nouvel_objet).objet)).semaphore = + (*((struct_semaphore *) (*s_objet).objet)).semaphore; strcpy((*((struct_semaphore *) (*s_nouvel_objet).objet)).nom, (*((struct_semaphore *) (*s_objet).objet)).nom); break; @@ -2479,8 +2787,9 @@ copie_objet(struct_processus *s_etat_pro (*s_objet).objet)).nombre_elements; if (((*((struct_tableau *) (*s_nouvel_objet).objet)).elements = - malloc((*((struct_tableau *) (*s_objet).objet)) - .nombre_elements * sizeof(struct_objet *))) == NULL) + malloc(((size_t) (*((struct_tableau *) + (*s_objet).objet)).nombre_elements) + * sizeof(struct_objet *))) == NULL) { return(NULL); } @@ -2540,8 +2849,8 @@ copie_objet(struct_processus *s_etat_pro } (*((struct_vecteur *) ((*s_nouvel_objet).objet))).tableau = - (void *) ((integer8 *) malloc( - ((*((struct_vecteur *) ((*s_objet).objet))).taille) + ((integer8 *) malloc(((size_t) + ((*((struct_vecteur *) ((*s_objet).objet))).taille)) * sizeof(integer8))); if ((*((struct_vecteur *) ((*s_nouvel_objet).objet))).tableau @@ -2583,8 +2892,8 @@ copie_objet(struct_processus *s_etat_pro } (*((struct_vecteur *) ((*s_nouvel_objet).objet))).tableau = - (void *) ((struct_complexe16 *) malloc( - ((*((struct_vecteur *) ((*s_objet).objet))).taille) + ((struct_complexe16 *) malloc(((size_t) + ((*((struct_vecteur *) ((*s_objet).objet))).taille)) * sizeof(struct_complexe16))); if ((*((struct_vecteur *) ((*s_nouvel_objet).objet))).tableau @@ -2626,8 +2935,8 @@ copie_objet(struct_processus *s_etat_pro } (*((struct_vecteur *) ((*s_nouvel_objet).objet))).tableau = - (void *) ((real8 *) malloc( - ((*((struct_vecteur *) ((*s_objet).objet))).taille) + ((real8 *) malloc(((size_t) + ((*((struct_vecteur *) ((*s_objet).objet))).taille)) * sizeof(real8))); if ((*((struct_vecteur *) ((*s_nouvel_objet).objet))).tableau @@ -2655,6 +2964,59 @@ copie_objet(struct_processus *s_etat_pro break; } + case EXT: + { + if (type != 'O') + { + incrementation_atomique(s_objet); + return(s_objet); + } + + // Appel de la fonction de duplication associée à l'objet + // externe. Le descripteur de bibliothèque est directement + // associé à la structure objet. + + l_element_courant = (*s_etat_processus).s_bibliotheques; + + while(l_element_courant != NULL) + { + if ((*((struct_bibliotheque *) (*l_element_courant).donnee)) + .descripteur == (*s_objet).descripteur_bibliotheque) + { + if ((__type_dup = dlsym((*s_objet).descripteur_bibliotheque, + "__type_dup")) == NULL) + { + // La fonction de duplication n'existe pas dans la + // bibliothèque. + + (*s_etat_processus).erreur_execution = + d_ex_type_externe_dup; + return(NULL); + } + + s_nouvel_objet = s_objet; + + if (__type_dup(s_etat_processus, (void **) &s_nouvel_objet) + == 0) + { + return(NULL); + } + + break; + } + + l_element_courant = (*l_element_courant).suivant; + } + + if (l_element_courant == NULL) + { + (*s_etat_processus).erreur_execution = d_ex_type_externe_dup; + return(NULL); + } + + break; + } + default : { return(NULL); @@ -2690,25 +3052,71 @@ copie_etat_processus(struct_processus *s struct_processus *s_nouvel_etat_processus; - unsigned long i; + integer8 i; - if (pthread_mutex_lock(&((*s_etat_processus).mutex)) != 0) + if (pthread_mutex_lock(&((*s_etat_processus).mutex_pile_processus)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return(NULL); } - if ((s_nouvel_etat_processus = malloc(sizeof(struct_processus))) == NULL) + if ((s_nouvel_etat_processus = sys_malloc(sizeof(struct_processus))) + == NULL) { + if (pthread_mutex_unlock(&((*s_etat_processus) + .mutex_pile_processus)) != 0) + { + (*s_etat_processus).erreur_systeme = d_es_processus; + return(NULL); + } + (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return(NULL); } + + if (pthread_mutex_lock(&((*s_etat_processus).mutex_interruptions)) != 0) + { + (*s_etat_processus).erreur_systeme = d_es_processus; + return(NULL); + } + + if (pthread_mutex_lock(&((*s_etat_processus).mutex_signaux)) != 0) + { + (*s_etat_processus).erreur_systeme = d_es_processus; + return(NULL); + } + (*s_nouvel_etat_processus) = (*s_etat_processus); - // On réinitialise l'allocateur. + if (pthread_mutex_unlock(&((*s_etat_processus).mutex_signaux)) != 0) + { + (*s_etat_processus).erreur_systeme = d_es_processus; + return(NULL); + } + + if (pthread_mutex_unlock(&((*s_etat_processus).mutex_interruptions)) != 0) + { + (*s_etat_processus).erreur_systeme = d_es_processus; + return(NULL); + } + + // On réinitialise les allocateurs. + + pthread_mutexattr_init(&attributs_mutex); + pthread_mutexattr_settype(&attributs_mutex, PTHREAD_MUTEX_NORMAL); + pthread_mutex_init(&((*s_nouvel_etat_processus).mutex_allocation_buffer), + &attributs_mutex); + pthread_mutexattr_destroy(&attributs_mutex); + + pthread_mutexattr_init(&attributs_mutex); + pthread_mutexattr_settype(&attributs_mutex, PTHREAD_MUTEX_NORMAL); + pthread_mutex_init(&((*s_nouvel_etat_processus).mutex_allocation), + &attributs_mutex); + pthread_mutexattr_destroy(&attributs_mutex); initialisation_allocateur(s_nouvel_etat_processus); + initialisation_allocateur_buffer(s_nouvel_etat_processus); /* * (*s_etat_processus).definition_chainee, @@ -2718,9 +3126,17 @@ copie_etat_processus(struct_processus *s * n'ont aucune raison de changer. */ - sem_init(&((*s_nouvel_etat_processus).semaphore_fork), 0, 0); + (*s_nouvel_etat_processus).sections_critiques = 0; + (*s_nouvel_etat_processus).initialisation_scheduler = d_faux; + + // Les sémaphores sont initialisés dans le nouveau thread. Il + // s'agit d'une limitation de l'implantation de l'émulation + // de sem_init(). + + initialisation_contexte_cas(s_etat_processus); (*s_nouvel_etat_processus).var_volatile_processus_pere = 0; + (*s_nouvel_etat_processus).var_volatile_processus_racine = 0; (*s_nouvel_etat_processus).fichiers_graphiques = NULL; (*s_nouvel_etat_processus).entree_standard = NULL; (*s_nouvel_etat_processus).s_marques = NULL; @@ -2750,6 +3166,10 @@ copie_etat_processus(struct_processus *s (*s_nouvel_etat_processus).nombre_interruptions_en_queue = 0; (*s_nouvel_etat_processus).nombre_interruptions_non_affectees = 0; + (*s_nouvel_etat_processus).at_exit = NULL; + (*s_nouvel_etat_processus).at_poke = NULL; + (*s_nouvel_etat_processus).traitement_at_poke = 'N'; + for(i = 0; i < d_NOMBRE_INTERRUPTIONS; i++) { (*s_nouvel_etat_processus).corps_interruptions[i] = NULL; @@ -2760,16 +3180,23 @@ copie_etat_processus(struct_processus *s if ((*s_nouvel_etat_processus).generateur_aleatoire != NULL) { - (*s_nouvel_etat_processus).generateur_aleatoire = NULL; - } + if (((*s_nouvel_etat_processus).generateur_aleatoire = + gsl_rng_clone((*s_etat_processus).generateur_aleatoire)) + == NULL) + { + (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; + return(NULL); + } - (*s_nouvel_etat_processus).type_generateur_aleatoire = NULL; + gsl_rng_set((*s_nouvel_etat_processus).generateur_aleatoire, + gsl_rng_get((*s_etat_processus).generateur_aleatoire)); + } // Copie de la localisation - if (((*s_nouvel_etat_processus).localisation = malloc((strlen( - (*s_etat_processus).localisation) + 1) * sizeof(unsigned char))) - == NULL) + if (((*s_nouvel_etat_processus).localisation = rpl_malloc( + s_nouvel_etat_processus, (strlen((*s_etat_processus).localisation) + + 1) * sizeof(unsigned char))) == NULL) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return(NULL); @@ -2783,7 +3210,8 @@ copie_etat_processus(struct_processus *s if (((*s_nouvel_etat_processus).indep = copie_objet(s_etat_processus, (*s_etat_processus).indep, 'P')) == NULL) { - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) + if (pthread_mutex_unlock(&((*s_etat_processus) + .mutex_pile_processus)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return(NULL); @@ -2803,7 +3231,8 @@ copie_etat_processus(struct_processus *s if (((*s_nouvel_etat_processus).depend = copie_objet(s_etat_processus, (*s_etat_processus).depend, 'P')) == NULL) { - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) + if (pthread_mutex_unlock(&((*s_etat_processus) + .mutex_pile_processus)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return(NULL); @@ -2824,7 +3253,8 @@ copie_etat_processus(struct_processus *s copie_objet(s_etat_processus, (*s_etat_processus) .parametres_courbes_de_niveau, 'P')) == NULL) { - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) + if (pthread_mutex_unlock(&((*s_etat_processus) + .mutex_pile_processus)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return(NULL); @@ -2844,11 +3274,13 @@ copie_etat_processus(struct_processus *s if (((*s_etat_processus).instruction_courante != NULL) && (*s_etat_processus).evaluation_expression_compilee == 'N') { - if (((*s_nouvel_etat_processus).instruction_courante = malloc((strlen( + if (((*s_nouvel_etat_processus).instruction_courante = rpl_malloc( + s_nouvel_etat_processus, (strlen( (*s_etat_processus).instruction_courante) + 1) * sizeof(unsigned char))) == NULL) { - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) + if (pthread_mutex_unlock(&((*s_etat_processus) + .mutex_pile_processus)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return(NULL); @@ -2868,11 +3300,13 @@ copie_etat_processus(struct_processus *s if ((*s_etat_processus).label_x != NULL) { - if (((*s_nouvel_etat_processus).label_x = malloc((strlen( + if (((*s_nouvel_etat_processus).label_x = rpl_malloc( + s_nouvel_etat_processus, (strlen( (*s_etat_processus).label_x) + 1) * sizeof(unsigned char))) == NULL) { - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) + if (pthread_mutex_unlock(&((*s_etat_processus) + .mutex_pile_processus)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return(NULL); @@ -2892,11 +3326,12 @@ copie_etat_processus(struct_processus *s if ((*s_etat_processus).label_y != NULL) { - if (((*s_nouvel_etat_processus).label_y = malloc((strlen( - (*s_etat_processus).label_y) + 1) * - sizeof(unsigned char))) == NULL) + if (((*s_nouvel_etat_processus).label_y = rpl_malloc( + s_nouvel_etat_processus, (strlen((*s_etat_processus).label_y) + + 1) * sizeof(unsigned char))) == NULL) { - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) + if (pthread_mutex_unlock(&((*s_etat_processus) + .mutex_pile_processus)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return(NULL); @@ -2916,11 +3351,12 @@ copie_etat_processus(struct_processus *s if ((*s_etat_processus).label_z != NULL) { - if (((*s_nouvel_etat_processus).label_z = malloc((strlen( - (*s_etat_processus).label_z) + 1) * - sizeof(unsigned char))) == NULL) + if (((*s_nouvel_etat_processus).label_z = rpl_malloc( + s_nouvel_etat_processus, (strlen((*s_etat_processus).label_z) + + 1) * sizeof(unsigned char))) == NULL) { - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) + if (pthread_mutex_unlock(&((*s_etat_processus) + .mutex_pile_processus)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return(NULL); @@ -2940,11 +3376,12 @@ copie_etat_processus(struct_processus *s if ((*s_etat_processus).titre != NULL) { - if (((*s_nouvel_etat_processus).titre = malloc((strlen( - (*s_etat_processus).titre) + 1) * - sizeof(unsigned char))) == NULL) + if (((*s_nouvel_etat_processus).titre = rpl_malloc( + s_nouvel_etat_processus, (strlen((*s_etat_processus).titre) + 1) + * sizeof(unsigned char))) == NULL) { - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) + if (pthread_mutex_unlock(&((*s_etat_processus) + .mutex_pile_processus)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return(NULL); @@ -2964,11 +3401,12 @@ copie_etat_processus(struct_processus *s if ((*s_etat_processus).legende != NULL) { - if (((*s_nouvel_etat_processus).legende = malloc((strlen( - (*s_etat_processus).legende) + 1) * - sizeof(unsigned char))) == NULL) + if (((*s_nouvel_etat_processus).legende = rpl_malloc( + s_nouvel_etat_processus, (strlen((*s_etat_processus).legende) + + 1) * sizeof(unsigned char))) == NULL) { - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) + if (pthread_mutex_unlock(&((*s_etat_processus) + .mutex_pile_processus)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return(NULL); @@ -2990,133 +3428,18 @@ copie_etat_processus(struct_processus *s * Copie de la table des variables */ - if (((*s_nouvel_etat_processus).s_liste_variables = - malloc((*s_etat_processus).nombre_variables_allouees * - sizeof(struct_variable))) == NULL) - { - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) - { - (*s_etat_processus).erreur_systeme = d_es_processus; - return(NULL); - } - - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; - return(NULL); - } - - for(i = 0; i < (*s_etat_processus).nombre_variables; i++) - { - if (((*s_nouvel_etat_processus).s_liste_variables[i].nom = - malloc((strlen((*s_etat_processus).s_liste_variables[i].nom) - + 1) * sizeof(unsigned char))) == NULL) - { - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) - { - (*s_etat_processus).erreur_systeme = d_es_processus; - return(NULL); - } - - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; - return(NULL); - } - - strcpy((*s_nouvel_etat_processus).s_liste_variables[i].nom, - (*s_etat_processus).s_liste_variables[i].nom); - - (*s_nouvel_etat_processus).s_liste_variables[i].origine = - (*s_etat_processus).s_liste_variables[i].origine; - (*s_nouvel_etat_processus).s_liste_variables[i].niveau = - (*s_etat_processus).s_liste_variables[i].niveau; - (*s_nouvel_etat_processus).s_liste_variables[i].variable_statique = - (*s_etat_processus).s_liste_variables[i].variable_statique; - (*s_nouvel_etat_processus).s_liste_variables[i].variable_verrouillee = - (*s_etat_processus).s_liste_variables[i].variable_verrouillee; - - // Les définitions sont partagées entre tous les threads. - - if ((*s_etat_processus).s_liste_variables[i].niveau == 0) - { - (*s_nouvel_etat_processus).s_liste_variables[i].objet = - (*s_etat_processus).s_liste_variables[i].objet; - } - else - { - if (((*s_nouvel_etat_processus).s_liste_variables[i].objet = - copie_objet(s_etat_processus, - (*s_etat_processus).s_liste_variables[i] - .objet, 'P')) == NULL) - { - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) - { - (*s_etat_processus).erreur_systeme = d_es_processus; - return(NULL); - } + (*s_nouvel_etat_processus).l_liste_variables_statiques = NULL; + copie_arbre_variables(s_etat_processus, s_nouvel_etat_processus); - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; - return(NULL); - } - } - } - - /* - * Copie de la table des variables statiques - */ - - if (((*s_nouvel_etat_processus).s_liste_variables_statiques = - malloc((*s_etat_processus).nombre_variables_statiques_allouees * - sizeof(struct_variable_statique))) == NULL) + if ((*s_nouvel_etat_processus).erreur_systeme != d_es) { - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) - { - (*s_etat_processus).erreur_systeme = d_es_processus; - return(NULL); - } - - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return(NULL); } - for(i = 0; i < (*s_etat_processus).nombre_variables_statiques; i++) - { - if (((*s_nouvel_etat_processus).s_liste_variables_statiques[i].nom = - malloc((strlen((*s_etat_processus).s_liste_variables_statiques - [i].nom) + 1) * sizeof(unsigned char))) == NULL) - { - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) - { - (*s_etat_processus).erreur_systeme = d_es_processus; - return(NULL); - } - - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; - return(NULL); - } - - strcpy((*s_nouvel_etat_processus).s_liste_variables_statiques[i].nom, - (*s_etat_processus).s_liste_variables_statiques[i].nom); - - (*s_nouvel_etat_processus).s_liste_variables_statiques[i].origine = - (*s_etat_processus).s_liste_variables_statiques[i].origine; - (*s_nouvel_etat_processus).s_liste_variables_statiques[i].niveau = - (*s_etat_processus).s_liste_variables_statiques[i].niveau; - (*s_nouvel_etat_processus).s_liste_variables_statiques[i] - .variable_statique = (*s_etat_processus) - .s_liste_variables_statiques[i].variable_statique; - - if (((*s_nouvel_etat_processus).s_liste_variables_statiques[i].objet = - copie_objet(s_etat_processus, (*s_etat_processus) - .s_liste_variables_statiques[i].objet, 'P')) == NULL) - { - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) - { - (*s_etat_processus).erreur_systeme = d_es_processus; - return(NULL); - } - - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; - return(NULL); - } - } + (*(*s_nouvel_etat_processus).l_liste_variables_partagees) = + (*(*s_etat_processus).l_liste_variables_partagees); + (*(*s_nouvel_etat_processus).s_arbre_variables_partagees) = + (*(*s_etat_processus).s_arbre_variables_partagees); /* * Copie de la pile opérationnelle @@ -3128,9 +3451,11 @@ copie_etat_processus(struct_processus *s while(l_element_lecture != NULL) { - if ((l_element_suivant = malloc(sizeof(struct_liste_chainee))) == NULL) + if ((l_element_suivant = rpl_malloc(s_nouvel_etat_processus, + sizeof(struct_liste_chainee))) == NULL) { - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) + if (pthread_mutex_unlock(&((*s_etat_processus) + .mutex_pile_processus)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return(NULL); @@ -3143,7 +3468,8 @@ copie_etat_processus(struct_processus *s if (((*l_element_suivant).donnee = copie_objet(s_etat_processus, (*l_element_lecture).donnee, 'P')) == NULL) { - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) + if (pthread_mutex_unlock(&((*s_etat_processus) + .mutex_pile_processus)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return(NULL); @@ -3179,7 +3505,8 @@ copie_etat_processus(struct_processus *s if ((*s_nouvel_etat_processus).erreur_systeme != d_es) { - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) + if (pthread_mutex_unlock(&((*s_etat_processus).mutex_pile_processus)) + != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return(NULL); @@ -3201,7 +3528,8 @@ copie_etat_processus(struct_processus *s if ((*s_nouvel_etat_processus).erreur_systeme != d_es) { - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) + if (pthread_mutex_unlock(&((*s_etat_processus).mutex_pile_processus)) + != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return(NULL); @@ -3225,14 +3553,19 @@ copie_etat_processus(struct_processus *s * Copie des différents contextes */ + (*s_nouvel_etat_processus).pointeur_signal_lecture = d_faux; + (*s_nouvel_etat_processus).pointeur_signal_ecriture = d_faux; + (*s_nouvel_etat_processus).l_base_pile_contextes = NULL; l_element_lecture = (*s_etat_processus).l_base_pile_contextes; while(l_element_lecture != NULL) { - if ((l_element_suivant = malloc(sizeof(struct_liste_chainee))) == NULL) + if ((l_element_suivant = rpl_malloc(s_nouvel_etat_processus, + sizeof(struct_liste_chainee))) == NULL) { - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) + if (pthread_mutex_unlock(&((*s_etat_processus) + .mutex_pile_processus)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return(NULL); @@ -3245,7 +3578,8 @@ copie_etat_processus(struct_processus *s if (((*l_element_suivant).donnee = copie_objet(s_etat_processus, (*l_element_lecture).donnee, 'P')) == NULL) { - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) + if (pthread_mutex_unlock(&((*s_etat_processus) + .mutex_pile_processus)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return(NULL); @@ -3276,9 +3610,11 @@ copie_etat_processus(struct_processus *s while(l_element_lecture != NULL) { - if ((l_element_suivant = malloc(sizeof(struct_liste_chainee))) == NULL) + if ((l_element_suivant = rpl_malloc(s_nouvel_etat_processus, + sizeof(struct_liste_chainee))) == NULL) { - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) + if (pthread_mutex_unlock(&((*s_etat_processus) + .mutex_pile_processus)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return(NULL); @@ -3291,7 +3627,8 @@ copie_etat_processus(struct_processus *s if (((*l_element_suivant).donnee = copie_objet(s_etat_processus, (*l_element_lecture).donnee, 'P')) == NULL) { - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) + if (pthread_mutex_unlock(&((*s_etat_processus) + .mutex_pile_processus)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return(NULL); @@ -3327,9 +3664,11 @@ copie_etat_processus(struct_processus *s while(l_element_lecture != NULL) { - if ((l_element_suivant = malloc(sizeof(struct_liste_chainee))) == NULL) + if ((l_element_suivant = rpl_malloc(s_nouvel_etat_processus, + sizeof(struct_liste_chainee))) == NULL) { - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) + if (pthread_mutex_unlock(&((*s_etat_processus) + .mutex_pile_processus)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return(NULL); @@ -3342,7 +3681,8 @@ copie_etat_processus(struct_processus *s if (((*l_element_suivant).donnee = copie_objet(s_etat_processus, (*l_element_lecture).donnee, 'P')) == NULL) { - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) + if (pthread_mutex_unlock(&((*s_etat_processus) + .mutex_pile_processus)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return(NULL); @@ -3373,9 +3713,11 @@ copie_etat_processus(struct_processus *s while(l_element_lecture != NULL) { - if ((l_element_suivant = malloc(sizeof(struct_liste_chainee))) == NULL) + if ((l_element_suivant = rpl_malloc(s_nouvel_etat_processus, + sizeof(struct_liste_chainee))) == NULL) { - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) + if (pthread_mutex_unlock(&((*s_etat_processus) + .mutex_pile_processus)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return(NULL); @@ -3385,8 +3727,8 @@ copie_etat_processus(struct_processus *s return(NULL); } - if (((*l_element_suivant).donnee = malloc(sizeof(struct_bibliotheque))) - == NULL) + if (((*l_element_suivant).donnee = rpl_malloc(s_nouvel_etat_processus, + sizeof(struct_bibliotheque))) == NULL) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return(NULL); @@ -3401,10 +3743,12 @@ copie_etat_processus(struct_processus *s = (*((struct_bibliotheque *) (*l_element_lecture).donnee)).tid; if (((*((struct_bibliotheque *) (*l_element_suivant).donnee)).nom = - malloc((strlen((*((struct_bibliotheque *) (*l_element_lecture) + rpl_malloc(s_nouvel_etat_processus, + (strlen((*((struct_bibliotheque *) (*l_element_lecture) .donnee)).nom) + 1) * sizeof(unsigned char))) == NULL) { - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) + if (pthread_mutex_unlock(&((*s_etat_processus) + .mutex_pile_processus)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return(NULL); @@ -3435,7 +3779,8 @@ copie_etat_processus(struct_processus *s if ((*s_etat_processus).nombre_instructions_externes != 0) { if (((*s_nouvel_etat_processus).s_instructions_externes = - malloc((*s_etat_processus).nombre_instructions_externes * + rpl_malloc(s_nouvel_etat_processus, ((size_t) + (*s_etat_processus).nombre_instructions_externes) * sizeof(struct_instruction_externe))) == NULL) { (*s_etat_processus).erreur_systeme = d_es_processus; @@ -3445,7 +3790,8 @@ copie_etat_processus(struct_processus *s for(i = 0; i < (*s_etat_processus).nombre_instructions_externes; i++) { if (((*s_nouvel_etat_processus).s_instructions_externes[i].nom = - malloc((strlen((*s_etat_processus).s_instructions_externes + rpl_malloc(s_nouvel_etat_processus, + (strlen((*s_etat_processus).s_instructions_externes [i].nom) + 1) * sizeof(unsigned char))) == NULL) { (*s_etat_processus).erreur_systeme = d_es_processus; @@ -3456,9 +3802,9 @@ copie_etat_processus(struct_processus *s (*s_etat_processus).s_instructions_externes[i].nom); if (((*s_nouvel_etat_processus).s_instructions_externes[i] - .nom_bibliotheque = malloc((strlen((*s_etat_processus) - .s_instructions_externes[i].nom_bibliotheque) + 1) * - sizeof(unsigned char))) == NULL) + .nom_bibliotheque = rpl_malloc(s_nouvel_etat_processus, + (strlen((*s_etat_processus).s_instructions_externes[i] + .nom_bibliotheque) + 1) * sizeof(unsigned char))) == NULL) { (*s_etat_processus).erreur_systeme = d_es_processus; return(NULL); @@ -3480,10 +3826,29 @@ copie_etat_processus(struct_processus *s pthread_mutexattr_init(&attributs_mutex); pthread_mutexattr_settype(&attributs_mutex, PTHREAD_MUTEX_NORMAL); - pthread_mutex_init(&((*s_nouvel_etat_processus).mutex), &attributs_mutex); + pthread_mutex_init(&((*s_nouvel_etat_processus).mutex_pile_processus), + &attributs_mutex); + pthread_mutexattr_destroy(&attributs_mutex); + + pthread_mutexattr_init(&attributs_mutex); + pthread_mutexattr_settype(&attributs_mutex, PTHREAD_MUTEX_NORMAL); + pthread_mutex_init(&((*s_nouvel_etat_processus).mutex_interruptions), + &attributs_mutex); + pthread_mutexattr_destroy(&attributs_mutex); + + pthread_mutexattr_init(&attributs_mutex); + pthread_mutexattr_settype(&attributs_mutex, PTHREAD_MUTEX_NORMAL); + pthread_mutex_init(&((*s_nouvel_etat_processus).mutex_signaux), + &attributs_mutex); pthread_mutexattr_destroy(&attributs_mutex); - if (pthread_mutex_unlock(&((*s_etat_processus).mutex)) != 0) + pthread_mutexattr_init(&attributs_mutex); + pthread_mutexattr_settype(&attributs_mutex, PTHREAD_MUTEX_NORMAL); + pthread_mutex_init(&((*s_nouvel_etat_processus).protection_liste_mutexes), + &attributs_mutex); + pthread_mutexattr_destroy(&attributs_mutex); + + if (pthread_mutex_unlock(&((*s_etat_processus).mutex_pile_processus)) != 0) { (*s_etat_processus).erreur_systeme = d_es_processus; return(NULL); @@ -3494,4 +3859,432 @@ copie_etat_processus(struct_processus *s #undef return } + +/* +================================================================================ + Routines de debug +================================================================================ + entrées : +-------------------------------------------------------------------------------- + sorties : +-------------------------------------------------------------------------------- + effets de bord : néant +================================================================================ +*/ + +#ifdef DEBUG_MEMOIRE + +#undef malloc +#undef realloc +#undef free +#undef fork + +#ifdef return +# undef return +#endif + +#ifdef __BACKTRACE +#define PROFONDEUR_PILE 64 +#define return(a) { if (a == NULL) \ + { BACKTRACE(PROFONDEUR_PILE); \ + fprintf(stderr, ">>> MEDITATION %d\n", __LINE__); } \ + return(a); } while(0) +#endif + +#undef fprintf +#define check(a, b) ((strcmp(#a, fonction) == 0) && (ligne == b)) +#undef CORE_DUMP + +typedef struct memoire +{ + void *pointeur; + unsigned char *fonction; + unsigned char *argument; + unsigned long ligne; + size_t taille; + unsigned long long ordre; +# ifdef __BACKTRACE + void *pile[PROFONDEUR_PILE]; + int profondeur; +# endif + struct memoire *suivant; +} struct_memoire; + +static struct_memoire *debug = NULL; +static unsigned long long ordre = 0; +static pthread_mutex_t mutex_allocation; + +void +debug_memoire_initialisation() +{ + pthread_mutexattr_t attributs_mutex; + + pthread_mutexattr_init(&attributs_mutex); + pthread_mutexattr_settype(&attributs_mutex, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&mutex_allocation, &attributs_mutex); + pthread_mutexattr_destroy(&attributs_mutex); + + return; +} + +void * +debug_memoire_ajout(size_t taille, const unsigned char *fonction, + unsigned long ligne, const unsigned char *argument) +{ + struct_memoire *ancienne_base; + + void *pointeur; + + pthread_mutex_lock(&mutex_allocation); + + ancienne_base = debug; + + if ((debug = malloc(sizeof(struct_memoire))) == NULL) + { + pthread_mutex_unlock(&mutex_allocation); + return(NULL); + } + + if (((*debug).pointeur = malloc(taille)) == NULL) + { + pthread_mutex_unlock(&mutex_allocation); + return(NULL); + } + + (*debug).suivant = ancienne_base; + (*debug).ligne = ligne; + (*debug).taille = taille; + (*debug).ordre = ordre; + + pointeur = (*debug).pointeur; + +# ifdef __BACKTRACE + (*debug).profondeur = backtrace((*debug).pile, PROFONDEUR_PILE); +# endif + + if (((*debug).fonction = malloc((strlen(fonction) + 1) * + sizeof(unsigned char))) == NULL) + { + pthread_mutex_unlock(&mutex_allocation); + + uprintf("[%d-%llu] ILLEGAL POINTER (malloc) $%016X\n", + getpid(), (unsigned long long) pthread_self(), NULL); +# ifdef __BACKTRACE + BACKTRACE(PROFONDEUR_PILE); +# endif + + return(NULL); + } + + if (((*debug).argument = malloc((strlen(argument) + 1) * + sizeof(unsigned char))) == NULL) + { + pthread_mutex_unlock(&mutex_allocation); + return(NULL); + } + + strcpy((*debug).fonction, fonction); + strcpy((*debug).argument, argument); + + memset((*debug).pointeur, 0, (*debug).taille); + + pthread_mutex_unlock(&mutex_allocation); + ordre++; + + return(pointeur); +} + +void * +debug_memoire_modification(void *pointeur, size_t taille, + const unsigned char *fonction, unsigned long ligne, + const unsigned char *argument) +{ + struct_memoire *element_courant; + + if (pointeur != NULL) + { + if (taille == 0) + { + // Revient à free(). Il n'y a pas de parenthèses car on ne veut + // pas utiliser la macro return(). + + debug_memoire_retrait(pointeur); + return NULL ; + } + else + { + // Réallocation réelle + + pthread_mutex_lock(&mutex_allocation); + + element_courant = debug; + + while(element_courant != NULL) + { + if ((*element_courant).pointeur == pointeur) + { + break; + } + + element_courant = (*element_courant).suivant; + } + + if (element_courant == NULL) + { + pthread_mutex_unlock(&mutex_allocation); + + uprintf("[%d-%llu] ILLEGAL POINTER (realloc) $%016X\n", + getpid(), (unsigned long long) pthread_self(), + pointeur); +# ifdef __BACKTRACE + BACKTRACE(PROFONDEUR_PILE); +# endif + + return(realloc(pointeur, taille)); + } + else + { + if (((*element_courant).pointeur = realloc(pointeur, taille)) + == NULL) + { + pthread_mutex_unlock(&mutex_allocation); + return(NULL); + } + + (*element_courant).ligne = ligne; + (*element_courant).taille = taille; + free((*element_courant).fonction); + free((*element_courant).argument); + + if (((*element_courant).fonction = malloc((strlen(fonction) + + 1) * sizeof(unsigned char))) == NULL) + { + pthread_mutex_unlock(&mutex_allocation); + return(NULL); + } + + if (((*element_courant).argument = malloc((strlen(argument) + + 1) * sizeof(unsigned char))) == NULL) + { + pthread_mutex_unlock(&mutex_allocation); + return(NULL); + } + + strcpy((*element_courant).fonction, fonction); + strcpy((*element_courant).argument, argument); + + pthread_mutex_unlock(&mutex_allocation); + + return((*element_courant).pointeur); + } + } + } + else + { + // Revient à malloc() + pointeur = debug_memoire_ajout(taille, fonction, ligne, argument); + return(pointeur); + } +} + +void +debug_memoire_retrait(void *pointeur) +{ + struct_memoire *element_courant; + struct_memoire *element_precedent; + + pthread_mutex_lock(&mutex_allocation); + + element_courant = debug; + element_precedent = NULL; + + while(element_courant != NULL) + { + if ((*element_courant).pointeur == pointeur) + { + if (element_precedent == NULL) + { + debug = (*debug).suivant; + } + else + { + (*element_precedent).suivant = (*element_courant).suivant; + } + + if (pointeur != NULL) + { + memset(pointeur, 0, (*element_courant).taille); + } + + free((*element_courant).fonction); + free((*element_courant).argument); + free(element_courant); + + break; + } + + element_precedent = element_courant; + element_courant = (*element_courant).suivant; + } + + pthread_mutex_unlock(&mutex_allocation); + + if (element_courant == NULL) + { + uprintf("[%d-%llu] ILLEGAL POINTER (free) $%016X\n", + getpid(), (unsigned long long) pthread_self(), pointeur); +# ifdef __BACKTRACE + BACKTRACE(PROFONDEUR_PILE); +# endif + } + + free(pointeur); + return; +} + +void +debug_memoire_verification() +{ +# ifdef __BACKTRACE + char **appels; + + int j; +# endif + + integer8 i; + + struct_memoire *element_courant; + struct_memoire *element_suivant; + + fprintf(stderr, "[%d-%llu] LIST OF MEMORY LEAKS\n", + getpid(), (unsigned long long) pthread_self()); + + pthread_mutex_lock(&mutex_allocation); + + element_courant = debug; + i = 1; + + while(element_courant != NULL) + { + fprintf(stderr, "[%d-%llu] MEDITATION %lld (%llu)\n", getpid(), + (unsigned long long) pthread_self(), i, + (*element_courant).ordre); + fprintf(stderr, "[%d-%llu] P: %p, F: %s(), L: %lu, S: %d\n", + getpid(), (unsigned long long) pthread_self(), + (*element_courant).pointeur, + (*element_courant).fonction, (*element_courant).ligne, + (int) (*element_courant).taille); + fprintf(stderr, "[%d-%llu] A: %s\n", getpid(), + (unsigned long long) pthread_self(), + (*element_courant).argument); + + if (strstr((*element_courant).argument, "sizeof(unsigned char)") + != NULL) + { + fprintf(stderr, "[%d-%llu] ", getpid(), + (unsigned long long) pthread_self()); + fprintf(stderr, "O: %s\n", (unsigned char *) + (*element_courant).pointeur); + } + else if (strcmp((*element_courant).argument, "sizeof(struct_objet)") + == 0) + { + fprintf(stderr, "[%d-%llu] ", getpid(), + (unsigned long long) pthread_self()); + fprintf(stderr, "O: %d\n", (*((struct_objet *) + (*element_courant).pointeur)).type); + } + else if (strcmp((*element_courant).argument, + "sizeof(struct_liste_chainee)") == 0) + { + fprintf(stderr, "[%d-%llu] ", getpid(), + (unsigned long long) pthread_self()); + fprintf(stderr, "O: data=%p next=%p\n", (*((struct_liste_chainee *) + (*element_courant).pointeur)).donnee, + (*((struct_liste_chainee *) (*element_courant).pointeur)) + .suivant); + } + +# ifdef __BACKTRACE + appels = backtrace_symbols((*element_courant).pile, + (*element_courant).profondeur); + + fprintf(stderr, "[%d-%llu] BACKTRACE\n", + getpid(), (unsigned long long) pthread_self()); + + if (appels != NULL) + { + for(j = 0; j < (*element_courant).profondeur; j++) + { + fprintf(stderr, "[%d-%llu] %s\n", getpid(), + (unsigned long long) pthread_self(), appels[j]); + } + + free(appels); + } +# endif + + fprintf(stderr, "\n"); + + i++; + + element_suivant = (*element_courant).suivant; + +# ifndef CORE_DUMP + free((*element_courant).fonction); + free((*element_courant).argument); + free(element_courant); +# endif + + element_courant = element_suivant; + } + + pthread_mutex_unlock(&mutex_allocation); + pthread_mutex_destroy(&mutex_allocation); + + fprintf(stderr, "[%d-%llu] END OF LIST\n", getpid(), + (unsigned long long) pthread_self()); + + return; +} + +pid_t +debug_fork(struct_processus *s_etat_processus) +{ + pid_t pid; + + pthread_mutex_lock(&mutex_allocation); + pid = fork(); + + if (pid == 0) + { + liberation_queue_signaux(s_etat_processus); + creation_queue_signaux(s_etat_processus); + + pthread_mutex_destroy(&mutex_allocation); + debug_memoire_initialisation(); + } + else + { + pthread_mutex_unlock(&mutex_allocation); + } + + // Pas de parenthèses pour ne pas remplacer return par sa macro. + return pid; +} + +void +analyse_post_mortem() +{ +# ifdef CORE_DUMP + BUG(debug != NULL, uprintf("[%d-%llu] CREATE CORE DUMP FILE FOR " + "POST MORTEM ANALYZE\n", getpid(), + (unsigned long long) pthread_self())); +# endif + + return; +} + +#endif + // vim: ts=4