File:  [local] / rpl / src / gestion_pile.c
Revision 1.74: download - view: text, annotated - select for diffs - revision graph
Fri Jan 10 11:15:42 2020 UTC (4 years, 3 months ago) by bertrand
Branches: MAIN
CVS tags: rpl-4_1_32, HEAD
Modification du copyright.

    1: /*
    2: ================================================================================
    3:   RPL/2 (R) version 4.1.32
    4:   Copyright (C) 1989-2020 Dr. BERTRAND Joël
    5: 
    6:   This file is part of RPL/2.
    7: 
    8:   RPL/2 is free software; you can redistribute it and/or modify it
    9:   under the terms of the CeCILL V2 License as published by the french
   10:   CEA, CNRS and INRIA.
   11:  
   12:   RPL/2 is distributed in the hope that it will be useful, but WITHOUT
   13:   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   14:   FITNESS FOR A PARTICULAR PURPOSE.  See the CeCILL V2 License
   15:   for more details.
   16:  
   17:   You should have received a copy of the CeCILL License
   18:   along with RPL/2. If not, write to info@cecill.info.
   19: ================================================================================
   20: */
   21: 
   22: 
   23: #include "rpl-conv.h"
   24: 
   25: 
   26: /*
   27: ================================================================================
   28:   Procédure d'estimation de la longueur du tampon
   29: ================================================================================
   30:   Entrée :
   31: --------------------------------------------------------------------------------
   32:   Sortie :
   33: --------------------------------------------------------------------------------
   34:   Effets de bord : néant
   35: ================================================================================
   36: */
   37: 
   38: static inline void
   39: estimation_taille_pile(struct_processus *s_etat_processus)
   40: {
   41:     /*
   42:      * Cette fonction permet d'estimer un volant de structures de maillons
   43:      * de liste chaînée pour le programme courant et évite un certain nombre
   44:      * d'allocations de mémoire lors des manipulations de la pile. Cette taille
   45:      * est estimée au travers d'une chaîne de Markov.
   46:      */
   47: 
   48:     if ((*s_etat_processus).hauteur_pile_operationnelle >
   49:             (*s_etat_processus).estimation_taille_pile_tampon)
   50:     {
   51:         (*s_etat_processus).estimation_taille_pile_tampon =
   52:                 (*s_etat_processus).estimation_taille_pile_tampon;
   53:     }
   54:     else
   55:     {
   56:         (*s_etat_processus).estimation_taille_pile_tampon =
   57:                 (((double) (*s_etat_processus).estimation_taille_pile_tampon) *
   58:                 ((double) 0.95)) + (((double) (*s_etat_processus)
   59:                 .hauteur_pile_operationnelle) * ((double) 0.05));
   60:     }
   61: 
   62:     return;
   63: }
   64: 
   65: 
   66: /*
   67: ================================================================================
   68:   Procédure d'empilement d'un nouvel élément
   69: ================================================================================
   70:   Entrée :
   71: --------------------------------------------------------------------------------
   72:   Sortie :
   73: --------------------------------------------------------------------------------
   74:   Effets de bord : néant
   75: ================================================================================
   76: */
   77: 
   78: logical1
   79: empilement(struct_processus *s_etat_processus,
   80:         struct_liste_chainee **l_base_pile, struct_objet *s_objet)
   81: {
   82:     struct_liste_chainee        *l_ancienne_base_liste;
   83:     struct_liste_chainee        *l_nouvelle_base_liste;
   84: 
   85:     logical1                    erreur;
   86: 
   87:     l_ancienne_base_liste = *l_base_pile;
   88: 
   89:     if ((*s_etat_processus).pile_tampon == NULL)
   90:     {
   91:         // Tampon vide, on alloue un élément.
   92: 
   93:         if ((l_nouvelle_base_liste = malloc(sizeof(struct_liste_chainee)))
   94:                 == NULL)
   95:         {
   96:             (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
   97:             return(d_erreur);
   98:         }
   99:     }
  100:     else
  101:     {
  102:         // Tampon utilisable, on retire un élément du tampon.
  103: 
  104:         l_nouvelle_base_liste = (*s_etat_processus).pile_tampon;
  105:         (*s_etat_processus).pile_tampon = (*l_nouvelle_base_liste).suivant;
  106:         (*s_etat_processus).taille_pile_tampon--;
  107:     }
  108: 
  109:     *l_base_pile = l_nouvelle_base_liste;
  110:     (**l_base_pile).donnee = s_objet;
  111:     (**l_base_pile).suivant = l_ancienne_base_liste;
  112: 
  113:     erreur = d_absence_erreur;
  114: 
  115: /*
  116: -- Ne considère que la pile opérationnelle -------------------------------------
  117: */
  118: 
  119:     if ((*s_etat_processus).l_base_pile == *l_base_pile)
  120:     {
  121:         (*s_etat_processus).hauteur_pile_operationnelle++;
  122:         estimation_taille_pile(s_etat_processus);
  123: 
  124:         if ((*s_etat_processus).debug == d_vrai)
  125:             if (((*s_etat_processus).type_debug &
  126:                     d_debug_pile_utilisateur) != 0)
  127:         {
  128:             if ((*s_etat_processus).langue == 'F')
  129:             {
  130:                 printf("[%d] Empilement de type %d "
  131:                         "(profondeur %lld)\n", (int) getpid(),
  132:                         (*s_objet).type,
  133:                         (*s_etat_processus).hauteur_pile_operationnelle);
  134:             }
  135:             else
  136:             {
  137:                 printf("[%d] Pushing a type %d object "
  138:                         "(depth %lld)\n", (int) getpid(), (*s_objet).type,
  139:                         (*s_etat_processus).hauteur_pile_operationnelle);
  140:             }
  141: 
  142:             fflush(stdout);
  143:         }
  144:     }
  145: 
  146:     return erreur;
  147: }
  148: 
  149: 
  150: /*
  151: ================================================================================
  152:   Procédure de dépilement d'un élément. L'emplacement est libéré dans la pile.
  153: ================================================================================
  154:   Entrée :
  155: --------------------------------------------------------------------------------
  156:   Sortie :
  157: --------------------------------------------------------------------------------
  158:   Effets de bord : néant
  159: ================================================================================
  160: */
  161: 
  162: logical1
  163: depilement(struct_processus *s_etat_processus,
  164:         struct_liste_chainee **l_base_pile, struct_objet **s_objet)
  165: {
  166:     struct_liste_chainee        *l_ancienne_base_liste;
  167:     struct_liste_chainee        *l_nouvelle_base_liste;
  168: 
  169:     logical1                    erreur;
  170: 
  171:     if (*l_base_pile == NULL)
  172:     {
  173:         (*s_etat_processus).erreur_execution = d_ex_pile_vide;
  174:         erreur = d_erreur;
  175:     }
  176:     else
  177:     {
  178: 
  179: /*
  180: -- Ne considère que la pile opérationnelle -------------------------------------
  181: */
  182: 
  183:         l_ancienne_base_liste = *l_base_pile;
  184:         *s_objet = (*l_ancienne_base_liste).donnee;
  185: 
  186:         if ((*s_etat_processus).l_base_pile == *l_base_pile)
  187:         {
  188:             if ((*s_etat_processus).debug == d_vrai)
  189:                 if (((*s_etat_processus).type_debug &
  190:                         d_debug_pile_utilisateur) != 0)
  191:             {
  192:                 if ((*s_etat_processus).langue == 'F')
  193:                 {
  194:                     printf("[%d] Dépilement de type %d "
  195:                             "(profondeur %lld)\n", (int) getpid(),
  196:                             (*(*s_objet)).type,
  197:                             (*s_etat_processus).hauteur_pile_operationnelle);
  198:                 }
  199:                 else
  200:                 {
  201:                     printf("[%d] Pulling a type %d object "
  202:                             "(depth %lld)\n", (int) getpid(),
  203:                             (*(*s_objet)).type,
  204:                             (*s_etat_processus).hauteur_pile_operationnelle);
  205:                 }
  206: 
  207:                 fflush(stdout);
  208:             }
  209: 
  210:             (*s_etat_processus).hauteur_pile_operationnelle--;
  211:             estimation_taille_pile(s_etat_processus);
  212:         }
  213: 
  214:         l_nouvelle_base_liste = (*l_ancienne_base_liste).suivant;
  215: 
  216:         *l_base_pile = l_nouvelle_base_liste;
  217:         erreur = d_absence_erreur;
  218: 
  219:         if ((*s_etat_processus).taille_pile_tampon <= (10 * ((*s_etat_processus)
  220:                 .estimation_taille_pile_tampon + 1)))
  221:         {
  222:             // Enregistrement de la structure pour usage ultérieur.
  223: 
  224:             (*l_ancienne_base_liste).donnee = NULL;
  225:             (*l_ancienne_base_liste).suivant = (*s_etat_processus).pile_tampon;
  226:             (*s_etat_processus).pile_tampon = l_ancienne_base_liste;
  227:             (*s_etat_processus).taille_pile_tampon++;
  228:         }
  229:         else
  230:         {
  231:             // Libération car le tampon est plein.
  232: 
  233:             free(l_ancienne_base_liste);
  234:         }
  235:     }
  236: 
  237:     return erreur;
  238: }
  239: 
  240: 
  241: /*
  242: ================================================================================
  243:   Procédures affichant la pile opérationnelle
  244: ================================================================================
  245:   Entrée :
  246: --------------------------------------------------------------------------------
  247:   Sortie :
  248: --------------------------------------------------------------------------------
  249:   Effets de bord : néant
  250: ================================================================================
  251: */
  252: 
  253: void
  254: affichage_pile(struct_processus *s_etat_processus, struct_liste_chainee
  255:         *l_element_courant, integer8 niveau_courant)
  256: {
  257:     unsigned char           registre;
  258: 
  259:     registre = (*s_etat_processus).autorisation_conversion_chaine;
  260:     (*s_etat_processus).autorisation_conversion_chaine = 'N';
  261: 
  262:     routine_recursive = 1;
  263:     ecriture_pile(s_etat_processus, stdout, l_element_courant, niveau_courant);
  264:     routine_recursive = 0;
  265: 
  266:     (*s_etat_processus).autorisation_conversion_chaine = registre;
  267:     return;
  268: }
  269: 
  270: // Bug de gcc à partir de gcc 4.6 (bug 48544)
  271: #pragma GCC diagnostic push
  272: #pragma GCC diagnostic ignored "-Wclobbered"
  273: 
  274: void
  275: ecriture_pile(struct_processus *s_etat_processus, file *flux,
  276:         struct_liste_chainee *l, integer8 niveau_courant)
  277: {
  278:     unsigned char               *chaine;
  279:     unsigned char               *registre;
  280:     unsigned char               tampon[32 + 1];
  281: 
  282:     // Évite le warning : argument l_element_courant might be clobbered by
  283:     // longjmp or vfork
  284:     volatile struct_liste_chainee   *l_element_courant;
  285: 
  286:     l_element_courant = l;
  287: 
  288:     if (l_element_courant != NULL)
  289:     {
  290:         if (setjmp(contexte_ecriture) == 0)
  291:         {
  292:             (*s_etat_processus).var_volatile_recursivite = -1;
  293:             ecriture_pile(s_etat_processus, flux,
  294:                     (*l_element_courant).suivant, niveau_courant + 1);
  295: 
  296:             if ((*s_etat_processus).var_volatile_recursivite > 0)
  297:             {
  298:                 (*s_etat_processus).var_volatile_recursivite--;
  299: 
  300:                 if ((*s_etat_processus).var_volatile_recursivite == 0)
  301:                 {
  302:                     if (fprintf(flux, "%lld: ...\n", niveau_courant) < 0)
  303:                     {
  304:                         (*s_etat_processus).erreur_systeme =
  305:                                 d_es_erreur_fichier;
  306:                         return;
  307:                     }
  308: 
  309:                     while(l_element_courant != NULL)
  310:                     {
  311:                         l_element_courant = (*l_element_courant).suivant;
  312:                     }
  313:                 }
  314: 
  315:                 return;
  316:             }
  317: 
  318:             (*s_etat_processus).var_volatile_recursivite = 0;
  319:         }
  320:         else
  321:         {
  322:             // Libération de n appels de la pile système qui permet de
  323:             // terminer la récursion sans autre dépassement de pile.
  324: 
  325:             (*s_etat_processus).var_volatile_recursivite = 64;
  326:             return;
  327:         }
  328: 
  329:         sprintf(tampon, "%lld: ", niveau_courant);
  330: 
  331:         if ((chaine = formateur(s_etat_processus, (long) strlen(tampon),
  332:                 (*l_element_courant).donnee)) == NULL)
  333:         {
  334:             (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
  335:             return;
  336:         }
  337: 
  338:         if ((*(*l_element_courant).donnee).type == CHN)
  339:         {
  340:             registre = chaine;
  341: 
  342:             if ((chaine = (unsigned char *) malloc((strlen(registre) + 3) *
  343:                     sizeof(unsigned char))) == NULL)
  344:             {
  345:                 (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
  346:                 return;
  347:             }
  348: 
  349:             sprintf(chaine, "\"%s\"", registre);
  350:             free(registre);
  351:         }
  352: 
  353:         if (fprintf(flux, "%lld: %s\n", niveau_courant, chaine) < 0)
  354:         {
  355:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  356:             return;
  357:         }
  358: 
  359:         free(chaine);
  360:     }
  361: 
  362:     return;
  363: }
  364: 
  365: 
  366: /*
  367: ================================================================================
  368:   Procédure imprimant la pile opérationnelle
  369: ================================================================================
  370:   Entrée : méthode 'C' = compacte, 'E' = étendue
  371: --------------------------------------------------------------------------------
  372:   Sortie :
  373: --------------------------------------------------------------------------------
  374:   Effets de bord : néant
  375: ================================================================================
  376: */
  377: 
  378: void
  379: impression_pile(struct_processus *s_etat_processus,
  380:         struct_liste_chainee *l, unsigned char methode, integer8 niveau_courant)
  381: {
  382:     struct_objet                s_objet;
  383: 
  384:     unsigned char               *chaine;
  385:     unsigned char               *registre;
  386:     unsigned char               tampon[32 + 1];
  387: 
  388:     // Évite le warning : argument l_element_courant might be clobbered by
  389:     // longjmp or vfork
  390:     volatile struct_liste_chainee   *l_element_courant;
  391: 
  392:     l_element_courant = l;
  393: 
  394:     if (l_element_courant != NULL)
  395:     {
  396:         if (setjmp(contexte_impression) == 0)
  397:         {
  398:             (*s_etat_processus).var_volatile_recursivite = -1;
  399:             impression_pile(s_etat_processus, (*l_element_courant).suivant,
  400:                     methode, niveau_courant + 1);
  401: 
  402:             if ((*s_etat_processus).var_volatile_recursivite > 0)
  403:             {
  404:                 (*s_etat_processus).var_volatile_recursivite--;
  405: 
  406:                 if ((*s_etat_processus).var_volatile_recursivite == 0)
  407:                 {
  408:                     while(l_element_courant != NULL)
  409:                     {
  410:                         l_element_courant = (*l_element_courant).suivant;
  411:                     }
  412:                 }
  413: 
  414:                 return;
  415:             }
  416: 
  417:             (*s_etat_processus).var_volatile_recursivite = 0;
  418:         }
  419:         else
  420:         {
  421:             (*s_etat_processus).var_volatile_recursivite = 16;
  422:             return;
  423:         }
  424: 
  425:         if (methode == 'C')
  426:         {
  427:             s_objet.type = CHN;
  428:             sprintf(tampon, "%lld: ", niveau_courant);
  429: 
  430:             if ((chaine = formateur(s_etat_processus, (long) strlen(tampon),
  431:                     (*l_element_courant).donnee)) == NULL)
  432:             {
  433:                 (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
  434:                 return;
  435:             }
  436: 
  437:             if ((*(*l_element_courant).donnee).type == CHN)
  438:             {
  439:                 registre = chaine;
  440: 
  441:                 if ((chaine = (unsigned char *) malloc((strlen(registre) + 3) *
  442:                         sizeof(unsigned char))) == NULL)
  443:                 {
  444:                     (*s_etat_processus).erreur_systeme =
  445:                             d_es_allocation_memoire;
  446:                     return;
  447:                 }
  448: 
  449:                 sprintf(chaine, "\"%s\"", registre);
  450:                 free(registre);
  451:             }
  452: 
  453:             if ((s_objet.objet = malloc((strlen(chaine) + 64) *
  454:                     sizeof(unsigned char))) == NULL)
  455:             {
  456:                 (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
  457:                 return;
  458:             }
  459: 
  460:             sprintf((unsigned char *) s_objet.objet,
  461:                     "\n\\noindent\\begin{verbatim}\n%lld: %s\n\\end{verbatim}",
  462:                     niveau_courant, chaine);
  463:             free(chaine);
  464: 
  465:             formateur_tex(s_etat_processus, &s_objet, 'V');
  466:             free(s_objet.objet);
  467:         }
  468:         else
  469:         {
  470:             formateur_tex(s_etat_processus, (*l_element_courant).donnee, 'N');
  471:         }
  472:     }
  473: 
  474:     return;
  475: }
  476: 
  477: #pragma GCC diagnostic pop
  478: 
  479: // vim: ts=4

CVSweb interface <joel.bertrand@systella.fr>