Diff for /rpl/src/interruptions.c between versions 1.32 and 1.33

version 1.32, 2010/08/18 12:56:55 version 1.33, 2010/08/22 16:38:36
Line 1726  deverrouillage_gestionnaire_signaux() Line 1726  deverrouillage_gestionnaire_signaux()
   
 #ifdef _BROKEN_SIGINFO  #ifdef _BROKEN_SIGINFO
   
   // Remplacer les mutexes par des sémaphores SysV
   
   #define longueur_queue  256
   #define nombre_queues   13
   
 static int              *fifos;  static int              *fifos;
 static int              segment;  static int              segment;
 static int              segment_mutexes;  static sem_t            *semaphores[nombre_queues];
 static int              longueur_queue;  static sem_t            *semaphore_global;
 static int              nombre_queues;  
   
 static pthread_mutex_t  *mutexes;  
   
   #ifdef IPCS_SYSV
 static unsigned char    *chemin = NULL;  static unsigned char    *chemin = NULL;
   #endif
   
 unsigned char *  unsigned char *
 nom_segment(unsigned char *chemin, pid_t pid)  nom_segment(unsigned char *chemin, pid_t pid)
 {  {
     unsigned char               *fichier;      unsigned char               *fichier;
   
   #   ifdef IPCS_SYSV
     if ((fichier = malloc((strlen(chemin) + 1 + 256 + 1) *      if ((fichier = malloc((strlen(chemin) + 1 + 256 + 1) *
             sizeof(unsigned char))) == NULL)              sizeof(unsigned char))) == NULL)
     {      {
Line 1748  nom_segment(unsigned char *chemin, pid_t Line 1753  nom_segment(unsigned char *chemin, pid_t
     }      }
   
     sprintf(fichier, "%s/RPL-SIGQUEUES-%d", chemin, (int) pid);      sprintf(fichier, "%s/RPL-SIGQUEUES-%d", chemin, (int) pid);
   #   else
       if ((fichier = malloc((1 + 256 + 1) *
               sizeof(unsigned char))) == NULL)
       {
           return(NULL);
       }
   
       sprintf(fichier, "/RPL-SIGQUEUES-%d", (int) pid);
   #   endif
   
     return(fichier);      return(fichier);
 }  }
   
 unsigned char *  unsigned char *
 nom_segment_mutexes(unsigned char *chemin, pid_t pid)  nom_semaphore(pid_t pid, int queue)
 {  {
     unsigned char               *fichier;      unsigned char               *fichier;
   
     if ((fichier = malloc((strlen(chemin) + 1 + 256 + 1) *      if ((fichier = malloc((256 + 1) * sizeof(unsigned char))) == NULL)
             sizeof(unsigned char))) == NULL)  
     {      {
         return(NULL);          return(NULL);
     }      }
   
     sprintf(fichier, "%s/RPL-SIGMUTEXES-%d", chemin, (int) pid);      sprintf(fichier, "/RPL-SIGESMAPHORES-%d-%d", (int) pid, queue);
   
     return(fichier);      return(fichier);
 }  }
   
 int  inline int
 queue_de_signal(int signal)  queue_de_signal(int signal)
 {  {
     switch(signal)      switch(signal)
     {      {
         case SIGINT:          case SIGINT:
             BUG(1, uprintf("SIGINT is not queued as it does not "  
                     "come from program itself !\n"));  
             return(0);              return(0);
         case SIGTSTP:          case SIGTSTP:
             return(1);              return(1);
Line 1797  queue_de_signal(int signal) Line 1808  queue_de_signal(int signal)
             return(9);              return(9);
         case SIGFABORT:          case SIGFABORT:
             return(10);              return(10);
           case SIGSEGV:
               return(11);
           case SIGBUS:
               return(12);
     }      }
   
     return(-1);      return(-1);
Line 1805  queue_de_signal(int signal) Line 1820  queue_de_signal(int signal)
 void  void
 creation_fifos_signaux(struct_processus *s_etat_processus)  creation_fifos_signaux(struct_processus *s_etat_processus)
 {  {
       /*
        * Signaux utilisés
        * SIGINT, SIGTSTP, SIGCONT, SIGURG, SIGPIPE, SIGALRM, SIGFSTOP,
        * SIGSTART, SIGINJECT, SIGABORT, SIGFABORT
        */
   
   #   ifndef IPCS_SYSV // POSIX
   #   else // SystemV
   
     file                            *desc;      file                            *desc;
   
     int                             i;      int                             i;
   
     key_t                           clef;      key_t                           clef;
   
     pthread_mutexattr_t             attributs_mutex;  
   
     unsigned char                   *nom;      unsigned char                   *nom;
   
     /*  
      * Signaux utilisés  
      * SIGINT, SIGTSTP, SIGCONT, SIGURG, SIGPIPE, SIGALRM, SIGFSTOP,  
      * SIGSTART, SIGINJECT, SIGABORT, SIGFABORT  
      */  
   
     // Création d'un segment de données associé au PID du processus courant      // Création d'un segment de données associé au PID du processus courant
   
     chemin = (*s_etat_processus).chemin_fichiers_temporaires;      chemin = (*s_etat_processus).chemin_fichiers_temporaires;
Line 1832  creation_fifos_signaux(struct_processus Line 1848  creation_fifos_signaux(struct_processus
         return;          return;
     }      }
   
     /*  
      * Structure d'une queue  
      * 0 : pointeur en lecture sur le premier emplacement libre (int)  
      * 1 : pointeur en écriture sur le premier emplacement à lire (int)  
      * 2 : longueur de la queue (int)  
      * 3 : éléments restants (int)  
      * 4 à 4 + (2) : queue (int)  
      * 5 : mutex  
      */  
   
     nombre_queues = 11;  
     longueur_queue = 256;  
   
     if ((desc = fopen(nom, "w")) == NULL)      if ((desc = fopen(nom, "w")) == NULL)
     {      {
         (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;          (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
Line 1873  creation_fifos_signaux(struct_processus Line 1876  creation_fifos_signaux(struct_processus
   
     if (((void *) fifos) == ((void *) -1))      if (((void *) fifos) == ((void *) -1))
     {      {
           if (shmctl(segment, IPC_RMID, 0) == -1)
           {
               (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
               return;
           }
   
         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;          (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
         return;          return;
     }      }
   
   #   endif
   
       /*
        * Structure d'une queue
        * 0 : pointeur en lecture sur le premier emplacement libre (int)
        * 1 : pointeur en écriture sur le premier emplacement à lire (int)
        * 2 : longueur de la queue (int)
        * 3 : éléments restants (int)
        * 4 à 4 + (2) : queue (int)
        */
   
     for(i = 0; i < nombre_queues; i++)      for(i = 0; i < nombre_queues; i++)
     {      {
         fifos[(i * (longueur_queue + 4))] = 0;          fifos[(i * (longueur_queue + 4))] = 0;
Line 1885  creation_fifos_signaux(struct_processus Line 1905  creation_fifos_signaux(struct_processus
         fifos[(i * (longueur_queue + 4)) + 3] = longueur_queue;          fifos[(i * (longueur_queue + 4)) + 3] = longueur_queue;
     }      }
   
     if ((nom = nom_segment_mutexes((*s_etat_processus)      // Création des sémaphores : un sémaphore par signal et par queue
             .chemin_fichiers_temporaires, getpid())) == NULL)      // plus un sémaphore global pour tous les threads.
     {  
         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;  
         return;  
     }  
   
     if ((desc = fopen(nom, "w")) == NULL)      for(i = 0; i < nombre_queues; i++)
     {      {
         (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;          if ((nom = nom_semaphore(getpid(), i)) == NULL)
         return;          {
     }              (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
               return;
           }
   
     fclose(desc);          // Le sémaphore est créé en écrasant si nécessaire un sémaphore
           // préexistant. Comme le nom du sémaphore contient l'identifiant du
           // processus, il est anormal d'avoir un sémaphore de même nom
           // préexistant.
   
     if ((clef = ftok(nom, 1)) == -1)          if ((semaphores[i] = sem_open(nom, O_CREAT, S_IRUSR | S_IWUSR,
     {                  1)) == SEM_FAILED)
         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;          {
         return;              (*s_etat_processus).erreur_systeme = d_es_semaphore;
               return;
           }
   
           free(nom);
     }      }
   
     free(nom);  
   
     if ((segment_mutexes = shmget(clef,      if ((nom = nom_semaphore(getpid(), nombre_queues)) == NULL)
             nombre_queues * sizeof(pthread_mutex_t),  
             IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR)) == -1)  
     {      {
         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;          (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
         return;          return;
     }      }
   
     mutexes = shmat(segment_mutexes, NULL, 0);      if ((semaphore_global = sem_open(nom, O_CREAT, S_IRUSR | S_IWUSR,
               1)) == SEM_FAILED)
     if (((void *) mutexes) == ((void *) -1))  
     {      {
         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;          (*s_etat_processus).erreur_systeme = d_es_semaphore;
         return;          return;
     }      }
   
     /*      free(nom);
      * Création et initialisation d'un mutex par queue. Ce mutex n'est pas  
      * dans le premier segment parce qu'il peut y avoir des problèmes  
      * d'alignements sur certaines architectures.  
      */  
   
     pthread_mutexattr_init(&attributs_mutex);  
     pthread_mutexattr_settype(&attributs_mutex, PTHREAD_MUTEX_RECURSIVE);  
   
     for(i = 0; i < nombre_queues; i++)  
     {  
         pthread_mutex_init(&(mutexes[i]), &attributs_mutex);  
     }  
   
     pthread_mutexattr_destroy(&attributs_mutex);  
     return;      return;
 }  }
   
 void  void
 liberation_fifos_signaux(struct_processus *s_etat_processus)  liberation_fifos_signaux(struct_processus *s_etat_processus)
 {  {
       int                 i;
   
     if (shmdt(fifos) == -1)      if (shmdt(fifos) == -1)
     {      {
         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;          (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
         return;          return;
     }      }
   
     if (shmdt(mutexes) == -1)      for(i = 0; i < nombre_queues; i++)
     {      {
         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;          if (sem_close(semaphores[i]) != 0)
           {
               (*s_etat_processus).erreur_systeme = d_es_semaphore;
               return;
           }
       }
   
       if (sem_close(semaphore_global) != 0)
       {
           (*s_etat_processus).erreur_systeme = d_es_semaphore;
         return;          return;
     }      }
   
Line 1979  destruction_fifos_signaux(struct_process Line 1998  destruction_fifos_signaux(struct_process
         return;          return;
     }      }
   
     for(i = 0; i < nombre_queues; i++)      if ((nom = nom_segment((*s_etat_processus).chemin_fichiers_temporaires,
     {              getpid())) == NULL)
         pthread_mutex_destroy(&(mutexes[i]));  
     }  
   
     if (shmdt(mutexes) == -1)  
     {      {
         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;          (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
         return;          return;
     }      }
   
     if (shmctl(segment_mutexes, IPC_RMID, 0) == -1)      unlink(nom);
       free(nom);
   
       for(i = 0; i < nombre_queues; i++)
     {      {
         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;          if ((nom = nom_semaphore(getpid(), i)) == NULL)
         return;          {
               (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
               return;
           }
   
           if (sem_unlink(nom) != 0)
           {
               (*s_etat_processus).erreur_systeme = d_es_semaphore;
               return;
           }
   
           free(nom);
     }      }
   
     if ((nom = nom_segment_mutexes((*s_etat_processus)      if ((nom = nom_semaphore(getpid(), nombre_queues)) == NULL)
             .chemin_fichiers_temporaires, getpid())) == NULL)  
     {      {
         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;          (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
         return;          return;
     }      }
   
     unlink(nom);      if (sem_unlink(nom) != 0)
     free(nom);  
   
     if ((nom = nom_segment((*s_etat_processus).chemin_fichiers_temporaires,  
             getpid())) == NULL)  
     {      {
         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;          (*s_etat_processus).erreur_systeme = d_es_semaphore;
         return;          return;
     }      }
   
     unlink(nom);  
     free(nom);      free(nom);
   
     return;      return;
Line 2022  destruction_fifos_signaux(struct_process Line 2045  destruction_fifos_signaux(struct_process
 int  int
 queue_in(pid_t pid, int signal)  queue_in(pid_t pid, int signal)
 {  {
   #undef printf
   // Transformer ce truc en POSIX ! On ne fait du SysV que si on n'a pas le choix
   
   #   ifndef IPCS_SYSV
   #   else // Traitement à l'aide d'IPCS SystemV
   
     int             *base;      int             *base;
     int             *buffer;      int             *buffer;
     int             *projection_fifos;      int             *projection_fifos;
Line 2030  queue_in(pid_t pid, int signal) Line 2059  queue_in(pid_t pid, int signal)
   
     key_t           clef;      key_t           clef;
   
     pthread_mutex_t *projection_mutexes;      sem_t           *semaphore;
   
       struct stat     s_stat;
   
     unsigned char   *nom;      unsigned char   *nom;
   
Line 2043  queue_in(pid_t pid, int signal) Line 2074  queue_in(pid_t pid, int signal)
         return(-1);          return(-1);
     }      }
   
       // Dans le cas de SIGSTART, premier signal envoyé à un processus fils,
       // il convient d'attendre que le fichier support soit effectivement
       // accessible. Dans tous les autres cas, ce fichier doit exister. S'il
       // n'existe plus, le processus associé n'existe plus.
   
       if (signal == SIGSTART)
       {
           // On attend que le fichier sois présent
   
           while(stat(nom, &s_stat) != 0);
       }
   
     if ((clef = ftok(nom, 1)) == -1)      if ((clef = ftok(nom, 1)) == -1)
     {      {
         free(nom);  
         return(-1);          return(-1);
     }      }
   
     free(nom);      free(nom);
   
     while((identifiant = shmget(clef,      if (signal == SIGSTART)
             nombre_queues * (longueur_queue + 4) * sizeof(int),      {
             S_IRUSR | S_IWUSR)) == -1);          while((identifiant = shmget(clef,
                   nombre_queues * (longueur_queue + 4) * sizeof(int),
                   S_IRUSR | S_IWUSR)) == -1);
       }
       else
       {
           if ((identifiant = shmget(clef,
                   nombre_queues * (longueur_queue + 4) * sizeof(int),
                   S_IRUSR | S_IWUSR)) == -1)
           {
               return(-1);
           }
       }
   
     projection_fifos = shmat(identifiant, NULL, 0);      projection_fifos = shmat(identifiant, NULL, 0);
   
     if ((nom = nom_segment_mutexes(chemin, pid)) == NULL)      if (((void *) projection_fifos) == ((void *) -1))
     {      {
         return(-1);          return(-1);
     }      }
   
     if ((clef = ftok(nom, 1)) == -1)      if ((nom = nom_semaphore(pid, queue)) == NULL)
     {      {
         free(nom);          shmdt(projection_fifos);
         return(-1);          return(-1);
     }      }
   
     free(nom);      while((semaphore = sem_open(nom, 0)) == SEM_FAILED);
   
     while((identifiant = shmget(clef,  
             nombre_queues * sizeof(pthread_mutex_t),  
             S_IRUSR | S_IWUSR)) == -1);  
   
     projection_mutexes = shmat(identifiant, NULL, 0);      if (sem_wait(semaphore) != 0)
   
     if (pthread_mutex_lock(&(projection_mutexes[queue])) != 0)  
     {      {
           shmdt(projection_fifos);
         return(-1);          return(-1);
     }      }
   
       // Il ne faut pas empiler plusieurs SIGSTART car SIGSTART peut provenir
       // de l'instruction SWI. Plusieurs threads peuvent interrompre de façon
       // asynchrone le processus père durant une phase de signaux masqués.
   
     base = &(projection_fifos[(longueur_queue + 4) * queue]);      base = &(projection_fifos[(longueur_queue + 4) * queue]);
     buffer = &(base[4]);      buffer = &(base[4]);
   
     // base[1] contient le prochain élément à écrire      // base[3] contient le nombre d'éléments restants
     buffer[base[1]++] = (int) pid;  
     base[1] %= base[2];  
   
     // base[3] contient le nombre d'éléments non lus  
     if (base[3] <= 0)      if (base[3] <= 0)
     {      {
         pthread_mutex_unlock(&(projection_mutexes[queue]));          sem_post(semaphore);
         shmdt(projection_mutexes);          sem_close(semaphore);
         shmdt(projection_fifos);          shmdt(projection_fifos);
         return(-1);          return(-1);
     }      }
   
     base[3]--;      base[3]--;
   
     if (pthread_mutex_unlock(&(projection_mutexes[queue])) != 0)      // base[1] contient le prochain élément à écrire
       buffer[base[1]++] = (int) pid;
       base[1] %= base[2];
   
       if (sem_post(semaphore) != 0)
     {      {
         shmdt(projection_mutexes);  
         shmdt(projection_fifos);          shmdt(projection_fifos);
           sem_close(semaphore);
         return(-1);          return(-1);
     }      }
   
       sem_close(semaphore);
   
     // Fermeture des projections      // Fermeture des projections
     shmdt(projection_mutexes);  
     shmdt(projection_fifos);      shmdt(projection_fifos);
   
   #   endif
   
     return(0);      return(0);
 }  }
   
Line 2125  origine_signal(int signal) Line 2183  origine_signal(int signal)
     BUG(queue == -1, uprintf("[%d] Unknown signal %d in this context\n",      BUG(queue == -1, uprintf("[%d] Unknown signal %d in this context\n",
             (int) getpid(), signal));              (int) getpid(), signal));
   
     if (pthread_mutex_lock(&(mutexes[queue])) != 0)      if (sem_wait(semaphores[queue]) != 0)
     {      {
         return(-1);          return(-1);
     }      }
   
     base = &(fifos[(longueur_queue + 4) * queue]);      // Le signal SIGCONT peut être envoyé de façon totalement asynchrone.
     buffer = &(base[4]);      // Il peut y avoir plus de signaux envoyés que d'interruptions traitées.
     pid = buffer[base[0]++];      // Il convient donc de rectifier la queue lors du traitement de
     base[0] %= base[2];      // l'interruption correspondante. Le gestionnaire étant installé sans
     base[3]++;      // l'option NODEFER, la queue reste cohérente.
   
       if (signal == SIGCONT)
       {
           base = &(fifos[(longueur_queue + 4) * queue]);
           buffer = &(base[4]);
           base[0] = (base[1] - 1) % base[2];
           pid = buffer[base[0]++];
           base[3] = base[2];
       }
       else
       {
           base = &(fifos[(longueur_queue + 4) * queue]);
           buffer = &(base[4]);
           pid = buffer[base[0]++];
           base[0] %= base[2];
           base[3]++;
       }
   
     if (base[3] > base[2])      if (base[3] > base[2])
     {      {
         pthread_mutex_unlock(&(mutexes[queue]));          sem_post(semaphores[queue]);
         return(-1);          return(-1);
     }      }
     if (pthread_mutex_unlock(&(mutexes[queue])) != 0)  
       if (sem_post(semaphores[queue]) != 0)
     {      {
         perror("unlock");  
         return(-1);          return(-1);
     }      }
   
Line 2152  origine_signal(int signal) Line 2227  origine_signal(int signal)
   
 #endif  #endif
   
   #ifdef printf
   #   undef printf
   #endif
   
 void  void
 interruption1(SIGHANDLER_ARGS)  interruption1(SIGHANDLER_ARGS)
 {  {
Line 2883  traitement_exceptions_gsl(const char *re Line 2962  traitement_exceptions_gsl(const char *re
 #undef pthread_kill  #undef pthread_kill
   
 int  int
 rpl_kill(pid_t pid, int signal)  kill_broken_siginfo(pid_t pid, int signal)
 {  {
       int                 ios;
   
       sem_t               *semaphore;
   
       unsigned char       *nom;
   
     /*      /*
      * Lorsqu'on veut interrompre le processus pid, on ouvre le segment       * Lorsqu'on veut interrompre le processus pid, on ouvre le segment
      * correspondant au processus en question et ou ajoute le pid dans la       * correspondant au processus en question et ou ajoute le pid dans la
      * queue.       * queue.
        *
        * Le sémaphore global à tous les threads d'un même processus sert
        * à garantir que les signaux seront traités dans l'ordre de ce qui est
        * effectivement mis dans la queue.
      */       */
   
       // Sémaphore acquis
   
       if ((nom = nom_semaphore(getpid(), nombre_queues)) == NULL)
       {
           return(-1);
       }
   
       if ((semaphore = sem_open(nom, 0)) == SEM_FAILED)
       {
           free(nom);
           return(-1);
       }
   
       free(nom);
   
       if (sem_wait(semaphore) == -1)
       {
           return(-1);
       }
   
     if ((signal != 0) && (signal != SIGINT))      if ((signal != 0) && (signal != SIGINT))
     {      {
         if (queue_in(pid, signal) != 0)          if (queue_in(pid, signal) != 0)
         {          {
               sem_post(semaphore);
               sem_close(semaphore);
             return(-1);              return(-1);
         }          }
     }      }
   
     return(kill(pid, signal));      ios = kill(pid, signal);
   
       // Sémaphore relâché
   
       sem_post(semaphore);
       sem_close(semaphore);
   
       return(ios);
 }  }
   
 int  int
 rpl_pthread_kill(pthread_t tid, int signal)  pthread_kill_broken_siginfo(pthread_t tid, int signal)
 {  {
       int                 ios;
   
       sem_t               *semaphore;
   
       unsigned char       *nom;
   
       if ((nom = nom_semaphore(getpid(), nombre_queues)) == NULL)
       {
           return(-1);
       }
   
       if ((semaphore = sem_open(nom, 0)) == SEM_FAILED)
       {
           free(nom);
           return(-1);
       }
   
       free(nom);
   
       if (sem_wait(semaphore) == -1)
       {
           return(-1);
       }
   
     if ((signal != 0) && (signal != SIGINT))      if ((signal != 0) && (signal != SIGINT))
     {      {
         if (queue_in(getpid(), signal) != 0)          if (queue_in(getpid(), signal) != 0)
         {          {
               sem_post(semaphore);
               sem_close(semaphore);
             return(-1);              return(-1);
         }          }
     }      }
   
     return(pthread_kill(tid, signal));      ios = pthread_kill(tid, signal);
   
       sem_post(semaphore);
       sem_close(semaphore);
   
       return(ios);
 }  }
   
 #endif  #endif

Removed from v.1.32  
changed lines
  Added in v.1.33


CVSweb interface <joel.bertrand@systella.fr>