Problème de signaux

Problème de signaux - C - Programmation

Marsh Posté le 17-08-2014 à 01:15:35    

   Bonjour tous,
 
    J’écris un logiciel qui émule une machine qui a existé il y a maintenant plus de 25 ans. Il s’agit d’un ordinateur à base de MC6801/3 (un ancien processeur / microcontroleur 8 bits de Motorola) qui opérait l’OS Flex2.
 
    Un bout de code de duplique fork() puis chaque branche ouvre un terminal (xterm, urxvt ou autre konsole), l’un exécutant l’émulateur avec son moniteur-débugger et l’autre simulant simplement une VT52. J’usqu’à maintenant, pas de problème, et le projet est bien avancé, bien qu'il reste beaucoup à faire. Il existe une commande du débogeur/moniteur qui permet de générer une interruption du processeur émulé (NMI ou IRQ), et cette partie fonctionne bien.
 
    J’ai voulu être interrompu régulièrement (comme le matériel d’antan) et ai utilisé setitimer() pour ça. Mode ITIMER_REAL → SIGALRM. Tout fonctionne bien (!) si ce n’est que le programme d’émulation s’arrête. J’ai beau chercher à savoir pourquoi, rien n’y fait : je ne trouve pas. Je ne sais pas où me mettre (avec le débogeur DDD) pour voir d’où vient le problème. J’imagine qu’un autre signal (d’erreur, probablement) est généré et que le handler par défaut de ce signal provoque l’abandon, mais je n’imagine pas de solution pour intercepter afin de débugger.
 
    Notez qu'à un moment, j'ai essayé de faire envoyer des signaux SIGUSR1 à la partie debugger-moniteur, par la partie VT52, qui n'a guère que ça à faire, et j'ai eu le même problème. Il s'agit certainement de quelque chose de bien connu par ceux qui ont chatouillé les signaux, mais suis trop tarte, sans doute : Je ne sais pas d'où ça vient et ne sais pas comment faire pour le trouver, et donc y remédier !
 
extraits:
 
 

Code :
  1. pthread_mutex_t tiMut=PTHREAD_MUTEX_INITIALIZER;
  2.   sig_atomic_t mSC=0;
  3.   static void EmuEndPeriod (void) { // void (and !int sig) To escape the warning
  4.   /// **************************************************************************
  5.   /* The handler is invoqued with SIGALRM (|SIGPROF|SIGVTALRM) signa. The
  6.   kBitIRQ of _6303.IrqFlgs or kBitNMI of _6303.IrqFlgs will be set to initiate
  7.   an interrution while stepping. As in the real word, it is the responsability
  8.   of the emulated program to "acknowledge" the concerned bit. */
  9.   pthread_mutex_lock(&tiMut); //sig=0; // To escape the warning
  10.   mSC+=1; // EmuIsGone ? _6303.IrqFlgs|=kBitNMI :0; // Sets the bit NMI
  11.   pthread_mutex_unlock(&tiMut);
  12.   }
  13.   int EmuStep (void) {
  14.   /// **************************************************************************
  15.   // Returns 0 if the opcode [_EmuGetMem(_6303.Pc)] is invalide
  16.   pthread_mutex_lock(&tiMut);
  17.   if ((i=mSC))
  18.     mSC=0;
  19.   pthread_mutex_unlock(&tiMut);
  20.     if (i) {
  21.       if (gTimer2_NMI) {
  22.         if(!(gRunner2-=i) || gRunner2&kBit(15)) { // Expiration if virtualy <0
  23.           gRunner2=gTimer2_NMI+gRunner2; // Re-init the timer
  24.           _6303.IrqFlgs|=kBitNMI; // Sets the bit NMI
  25.         }
  26.       }
  27.       if (gTimer4_IRQ) {
  28.         if(!(gRunner4-=i) || gRunner4&kBit(15)) { // Expiration if 0
  29.           gRunner4=gTimer4_IRQ+gRunner4; // Re-init the timer
  30.           _6303.IrqFlgs|=kBitIRQ; // Sets the bit IRQ
  31.         }
  32.       }
  33.     }
  34. /** Interruption treatment is placed here to permit the execution of at least
  35.     one instruction after the registers had been pushed in stack.
  36.     One of the 10 bits corresponding to the IRQ is set somewhere in this function
  37.     (see EmuSpcActLeave(), above). See IrqFlgs definition NOTE */
  38.     if (_6303.IrqFlgs) { // All bits
  39.       if (_6303.IrqFlgs&kBitRST) { // Immediat and unconditional action
  40.         _6303.IrqFlgs&=~kBitRST;
  41.         EmuReset();
  42.         return(1);
  43.         }
  44.       else if ((_6303.IrqFlgs&kBitNMI) && // NMInterrupt request
  45.                ((_6303.IrqPre^_6303.IrqFlgs)&kBitNMI)) // Falling edge (&#8593; indeed)
  46.         EmuEnterIt(Vect_NMI);
  47.       else if ((_6303.IrqFlgs&kBitIRQ) && (!(_6303.Cc&kI)))
  48.         EmuEnterIt(Vect_IRQ);
  49.     }
  50.     _6303.IrqPre=_6303.IrqFlgs; // Note of the current state (solely for NMI)


L’"allumage" du timer:

Code :
  1. const struct itimerval gPeriod={{ 2, 10000 }, { 2, 10000 }};
  2.   void SetFreeRunner (void) {
  3.   /// **************************************************************************
  4.   // ITIMER_REAL:SIGALRM | ITIMER_VIRTUAL:SIGVTALRM | ITIMER_PROF:SIGPROF
  5.   static struct sigaction sa;
  6.     memset(&sa, 0, sizeof (sa));
  7.     sa.sa_handler=(void(*)(int))&EmuEndPeriod;
  8.     sigaction(SIGALRM, &sa, NULL);
  9.     if (setitimer(ITIMER_REAL, &gPeriod, NULL)<0) //
  10.       PerrExit("setitimer() a provoqué une erreur", 1);
  11.   }


    Vous aurez probablement compris que ma question est : savez-vous comment je pourrais me sortir de là ?
 
    À noter que je placerai le tout en ligne et sous licence GNU. S'il vous tente de jeter un œil sur le projet, faites le moi savoir.
 
    Je vous remercie pour l'attention que vous aurez porté à ce post.
 
Cordialement

Reply

Marsh Posté le 17-08-2014 à 01:15:35   

Reply

Marsh Posté le 18-08-2014 à 01:57:38    

Bonjour,
 
    J'avais déjà vu ça, mais zappé pour une mauvaise raison. C'est ici que ça quitte, sur le premier exit(). Et silencieusement à cause du EXIT_SUCCESS.
 

Code :
  1. int GetCFrom (IOnum from, char *buff) {
  2.   /// **************************************************************************
  3.   fd_set  set;
  4.   struct timeval tiOut={0};
  5.   int rcvd;
  6.     if (FdIsValid(from)) {
  7.       FD_ZERO(&set); // Effacement de tout descripteur de l'ensemble "set"
  8.       FD_SET(from, &set); // Ajouter le descripteur de cette entrée
  9.       if (select(from+1, &set, NULL, NULL, &tiOut) < 0) // Sélection parmis ceux du jeu "set"
  10.         exit(EXIT_SUCCESS); // Sortie normale (le pipe a été rompu)?
  11.       if (FD_ISSET(from, &set)) { // Si l'entrée du pipe ne bloquera pas
  12.         if ((rcvd=read(from, buff, 1))!=1) // Lire ce qui y est disponible
  13.           exit(EXIT_SUCCESS); // Sortie normale (le pipe a été rompu)?
  14.         return(*buff);
  15.       }
  16.     }
  17.   return(-1);
  18.   }


    Pourquoi l'utilisation de setitimer() causerait cette erreur ? Parce qu'il génère un signal, pour le moins ! Il m'aura suffit de lire cette page.
 
    C'est pas fini. Et je dois sérieusement retoucher mon code. Mais au moins, tout espoir n'est pas perdu!
 
Paulo

Reply

Marsh Posté le 18-08-2014 à 20:59:19    

un signal reçu par un processus interrompt un appel système dans ce même processus. Ton select ( qui est bloquant ) retourne donc -1 , mais errno vaut EINTR. Il faut donc gérer ce cas.

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed