Diff for /rpl/src/interruptions.c between versions 1.35 and 1.36

version 1.35, 2010/08/25 09:06:49 version 1.36, 2010/08/25 16:40:57
Line 1724  deverrouillage_gestionnaire_signaux() Line 1724  deverrouillage_gestionnaire_signaux()
     return;      return;
 }  }
   
 #ifdef _BROKEN_SIGINFO  
   
 #define longueur_queue  256  
 #define nombre_queues   13  
   
 static int              *fifos;  
 static int              markov;  
 static int              segment;  
 static sem_t            *semaphores[nombre_queues];  
 static sem_t            *semaphore_global;  
   
 #ifdef IPCS_SYSV  
 static unsigned char    *chemin = NULL;  
 #endif  
   
 unsigned char *  
 nom_segment(unsigned char *chemin, pid_t pid)  
 {  
     unsigned char               *fichier;  
   
 #   ifdef IPCS_SYSV  
     if ((fichier = malloc((strlen(chemin) + 1 + 256 + 1) *  
             sizeof(unsigned char))) == NULL)  
     {  
         return(NULL);  
     }  
   
     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);  
 }  
   
 unsigned char *  
 nom_semaphore(pid_t pid, int queue)  
 {  
     unsigned char               *fichier;  
   
     if ((fichier = malloc((256 + 1) * sizeof(unsigned char))) == NULL)  
     {  
         return(NULL);  
     }  
   
     sprintf(fichier, "/RPL-SIGESMAPHORES-%d-%d", (int) pid, queue);  
   
     return(fichier);  
 }  
   
 inline int  
 queue_de_signal(int signal)  
 {  
     switch(signal)  
     {  
         case SIGINT:  
             return(0);  
         case SIGTSTP:  
             return(1);  
         case SIGCONT:  
             return(2);  
         case SIGURG:  
             return(3);  
         case SIGPIPE:  
             return(4);  
         case SIGALRM:  
             return(5);  
         case SIGFSTOP:  
             return(6);  
         case SIGSTART:  
             return(7);  
         case SIGINJECT:  
             return(8);  
         case SIGABORT:  
             return(9);  
         case SIGFABORT:  
             return(10);  
         case SIGSEGV:  
             return(11);  
         case SIGBUS:  
             return(12);  
     }  
   
     return(-1);  
 }  
   
 void  
 creation_fifos_signaux(struct_processus *s_etat_processus)  
 {  
     /*  
      * Signaux utilisés  
      * SIGINT, SIGTSTP, SIGCONT, SIGURG, SIGPIPE, SIGALRM, SIGFSTOP,  
      * SIGSTART, SIGINJECT, SIGABORT, SIGFABORT  
      */  
   
     int                             i;  
   
     unsigned char                   *nom;  
   
 #   ifndef IPCS_SYSV // POSIX  
   
     if ((nom = nom_segment((*s_etat_processus).chemin_fichiers_temporaires,  
             getpid())) == NULL)  
     {  
         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;  
         return;  
     }  
   
     if ((segment = shm_open(nom, O_RDWR | O_CREAT | O_EXCL,  
             S_IRUSR | S_IWUSR)) == -1)  
     {  
         free(nom);  
         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;  
         return;  
     }  
   
     if (ftruncate(segment, nombre_queues * ((2 * longueur_queue) + 4) *  
             sizeof(int)) == -1)  
     {  
         free(nom);  
         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;  
         return;  
     }  
   
     fifos = mmap(NULL, nombre_queues * ((2 * longueur_queue) + 4) * sizeof(int),  
             PROT_READ | PROT_WRITE, MAP_SHARED, segment, 0);  
     close(segment);  
   
     if (((void *) fifos) == ((void *) -1))  
     {  
         if (shm_unlink(nom) == -1)  
         {  
             free(nom);  
             (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;  
             return;  
         }  
   
         free(nom);  
         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;  
         return;  
     }  
   
     free(nom);  
   
 #   else // SystemV  
   
     file                            *desc;  
   
     key_t                           clef;  
   
     // Création d'un segment de données associé au PID du processus courant  
   
     chemin = (*s_etat_processus).chemin_fichiers_temporaires;  
   
     if ((nom = nom_segment((*s_etat_processus).chemin_fichiers_temporaires,  
             getpid())) == NULL)  
     {  
         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;  
         return;  
     }  
   
     if ((desc = fopen(nom, "w")) == NULL)  
     {  
         (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;  
         return;  
     }  
   
     fclose(desc);  
   
     if ((clef = ftok(nom, 1)) == -1)  
     {  
         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;  
         return;  
     }  
   
     free(nom);  
   
     if ((segment = shmget(clef,  
             nombre_queues * ((2 * longueur_queue) + 4) * sizeof(int),  
             IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR)) == -1)  
     {  
         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;  
         return;  
     }  
   
     fifos = shmat(segment, NULL, 0);  
   
     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;  
         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)  
      * 4 + (2) + 1 ) 4 + 2 * (2) : horodatage en centième de secondes.  
      */  
   
     for(i = 0; i < nombre_queues; i++)  
     {  
         fifos[(i * (longueur_queue + 4))] = 0;  
         fifos[(i * (longueur_queue + 4)) + 1] = 0;  
         fifos[(i * (longueur_queue + 4)) + 2] = longueur_queue;  
         fifos[(i * (longueur_queue + 4)) + 3] = longueur_queue;  
     }  
   
     // Création des sémaphores : un sémaphore par signal et par queue  
     // plus un sémaphore global pour tous les threads.  
   
     for(i = 0; i < nombre_queues; i++)  
     {  
         if ((nom = nom_semaphore(getpid(), i)) == NULL)  
         {  
             (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;  
             return;  
         }  
   
         // 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 ((semaphores[i] = sem_open(nom, O_CREAT, S_IRUSR | S_IWUSR,  
                 1)) == SEM_FAILED)  
         {  
             (*s_etat_processus).erreur_systeme = d_es_semaphore;  
             return;  
         }  
   
         free(nom);  
     }  
   
   
     if ((nom = nom_semaphore(getpid(), nombre_queues)) == NULL)  
     {  
         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;  
         return;  
     }  
   
     if ((semaphore_global = sem_open(nom, O_CREAT, S_IRUSR | S_IWUSR,  
             1)) == SEM_FAILED)  
     {  
         (*s_etat_processus).erreur_systeme = d_es_semaphore;  
         return;  
     }  
   
     free(nom);  
   
     markov = 0;  
   
     return;  
 }  
   
 void  
 liberation_fifos_signaux(struct_processus *s_etat_processus)  
 {  
     int                 i;  
   
 #   ifdef IPCS_SYSV // SystemV  
   
     if (shmdt(fifos) == -1)  
     {  
         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;  
         return;  
     }  
   
 #   else // POSIX  
   
     if (munmap(fifos, nombre_queues * ((2 * longueur_queue) + 4) * sizeof(int))  
             != 0)  
     {  
         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;  
         return;  
     }  
   
 #   endif  
   
     for(i = 0; i < nombre_queues; i++)  
     {  
         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;  
 }  
   
 void  
 destruction_fifos_signaux(struct_processus *s_etat_processus)  
 {  
     int                 i;  
   
     unsigned char       *nom;  
   
 #   ifdef IPCS_SYSV // SystemV  
   
     if (shmdt(fifos) == -1)  
     {  
         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;  
         return;  
     }  
   
     if (shmctl(segment, IPC_RMID, 0) == -1)  
     {  
         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;  
         return;  
     }  
   
     if ((nom = nom_segment((*s_etat_processus).chemin_fichiers_temporaires,  
             getpid())) == NULL)  
     {  
         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;  
         return;  
     }  
   
     unlink(nom);  
     free(nom);  
   
 #   else // POSIX  
   
     if (munmap(fifos, nombre_queues * ((2 * longueur_queue) + 4) * sizeof(int))  
             != 0)  
     {  
         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;  
         return;  
     }  
   
     if ((nom = nom_segment(NULL, getpid())) == NULL)  
     {  
         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;  
         return;  
     }  
   
     if (shm_unlink(nom) != 0)  
     {  
         free(nom);  
         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;  
         return;  
     }  
   
     free(nom);  
   
 #   endif  
   
     for(i = 0; i < nombre_queues; i++)  
     {  
         if ((nom = nom_semaphore(getpid(), i)) == NULL)  
         {  
             (*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_semaphore(getpid(), nombre_queues)) == NULL)  
     {  
         (*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);  
   
     return;  
 }  
   
 inline int  
 horodatage()  
 {  
     int             ts;  
   
     struct timeval  tv;  
   
     gettimeofday(&tv, NULL);  
     ts = (int) ((tv.tv_sec * 100) + (tv.tv_usec / 10000));  
   
     return(ts);  
 }  
   
 int  
 queue_in(pid_t pid, int signal)  
 {  
     int             queue;  
     int             *base;  
     int             *buffer;  
     int             horodatage_initial;  
     int             identifiant;  
     int             *projection_fifos;  
   
     sem_t           *semaphore;  
   
     queue = queue_de_signal(signal);  
   
     unsigned char   *nom;  
   
 #   ifndef IPCS_SYSV  
   
     // Ouverture des projections  
   
     if ((nom = nom_segment(NULL, pid)) == NULL)  
     {  
         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)  
     {  
         horodatage_initial = horodatage();  
   
         while((identifiant = shm_open(nom, O_RDWR, S_IRUSR | S_IWUSR)) == -1)  
         {  
             if (abs(horodatage_initial - horodatage()) > 500)  
             {  
                 return(-1);  
             }  
         }  
     }  
     else  
     {  
         if ((identifiant = shm_open(nom, O_RDWR, S_IRUSR | S_IWUSR)) == -1)  
         {  
             return(-1);  
         }  
     }  
   
     projection_fifos = mmap(NULL, nombre_queues * ((2 * longueur_queue) + 4)  
             * sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, identifiant, 0);  
     close(identifiant);  
   
     if (((void *) projection_fifos) == ((void *) -1))  
     {  
         return(-1);  
     }  
   
 #   else // Traitement à l'aide d'IPCS SystemV  
   
     key_t           clef;  
   
     struct stat     s_stat;  
   
     // Ouverture des projections  
   
     if ((nom = nom_segment(chemin, pid)) == NULL)  
     {  
         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  
   
         horodatage_initial = horodatage();  
   
         while(stat(nom, &s_stat) != 0)  
         {  
             if (abs(horodatage_initial - horodatage()) > 500)  
             {  
                 return(-1);  
             }  
         }  
     }  
   
     if ((clef = ftok(nom, 1)) == -1)  
     {  
         return(-1);  
     }  
   
     free(nom);  
   
     if (signal == SIGSTART)  
     {  
         while((identifiant = shmget(clef,  
                 nombre_queues * ((2 * longueur_queue) + 4) * sizeof(int),  
                 S_IRUSR | S_IWUSR)) == -1);  
     }  
     else  
     {  
         if ((identifiant = shmget(clef,  
                 nombre_queues * ((2 * longueur_queue) + 4) * sizeof(int),  
                 S_IRUSR | S_IWUSR)) == -1)  
         {  
             return(-1);  
         }  
     }  
   
     projection_fifos = shmat(identifiant, NULL, 0);  
   
     if (((void *) projection_fifos) == ((void *) -1))  
     {  
         return(-1);  
     }  
   
 #   endif  
   
     if ((nom = nom_semaphore(pid, queue)) == NULL)  
     {  
 #       ifdef IPCS_SYSV  
         shmdt(projection_fifos);  
 #       else  
         munmap(projection_fifos, nombre_queues * ((2 * longueur_queue) + 4)  
                 * sizeof(int));  
 #       endif  
         return(-1);  
     }  
   
     while((semaphore = sem_open(nom, 0)) == SEM_FAILED);  
     free(nom);  
   
     while(sem_wait(semaphore) != 0)  
     {  
         if (errno != EINTR)  
         {  
 #           ifdef IPCS_SYSV  
             shmdt(projection_fifos);  
 #           else  
             munmap(projection_fifos, nombre_queues * ((2 * longueur_queue) + 4)  
                     * sizeof(int));  
 #           endif  
             return(-1);  
         }  
     }  
   
     base = &(projection_fifos[(longueur_queue + 4) * queue]);  
     buffer = &(base[4]);  
   
     // base[3] contient le nombre d'éléments restants  
   
     if (base[3] <= 0)  
     {  
         sem_post(semaphore);  
         sem_close(semaphore);  
 #       ifdef IPCS_SYSV  
         shmdt(projection_fifos);  
 #       else  
         munmap(projection_fifos, nombre_queues * ((2 * longueur_queue) + 4)  
                 * sizeof(int));  
 #       endif  
         return(-1);  
     }  
   
     base[3]--;  
   
     // base[1] contient le prochain élément à écrire  
   
     buffer[base[1] + (nombre_queues * base[2])] = horodatage();  
     buffer[base[1]++] = (int) pid;  
     base[1] %= base[2];  
   
     if (sem_post(semaphore) != 0)  
     {  
 #       ifdef IPCS_SYSV  
         shmdt(projection_fifos);  
 #       else  
         munmap(projection_fifos, nombre_queues * ((2 * longueur_queue) + 4)  
                 * sizeof(int));  
 #       endif  
         sem_close(semaphore);  
         return(-1);  
     }  
   
     sem_close(semaphore);  
   
     // Fermeture des projections  
 #   ifdef IPCS_SYSV  
     shmdt(projection_fifos);  
 #   else  
     munmap(projection_fifos, nombre_queues * ((2 * longueur_queue) + 4)  
             * sizeof(int));  
 #   endif  
   
     return(0);  
 }  
   
 inline int  
 chaine_markov(int markov, int delta)  
 {  
     double      memoire = 0.9;  
     int         valeur;  
   
     valeur = (int) ((memoire * markov) + ((1 - memoire) * delta));  
     valeur = (valeur < 10) ? 10 : valeur;  
   
     return(valeur);  
 }  
   
 pid_t  
 origine_signal(int signal)  
 {  
     logical1        drapeau;  
   
     int             *base;  
     int             *buffer;  
     int             delta;  
     int             pid;  
     int             queue;  
   
     queue = queue_de_signal(signal);  
   
     BUG(queue == -1, uprintf("[%d] Unknown signal %d in this context\n",  
             (int) getpid(), signal));  
   
     while(sem_wait(semaphores[queue]) != 0)  
     {  
         if (errno != EINTR)  
         {  
             return(-1);  
         }  
     }  
   
     // On retire les interruptions anciennes qui ont été ratées sauf s'il  
     // s'agit de la dernière dans la queue.  
   
     base = &(fifos[(longueur_queue + 4) * queue]);  
     buffer = &(base[4]);  
   
     if (base[3] == (base[2] - 1))  
     {  
         delta = abs(horodatage() -  
                  buffer[base[0] + (nombre_queues * base[2])]);  
         // Une seule interruption dans la queue.  
         pid = buffer[base[0]++];  
         base[0] %= base[2];  
         base[3]++;  
   
         markov = chaine_markov(markov, delta);  
     }  
     else if (base[3] >= base[2])  
     {  
         // Aucune interruption n'est dans la queue.  
         // On a retiré trop d'interruptions de la queue.  
   
         // (base[3] - base[2]) + 1 : nombre d'interruptions manquantes  
         // base[0] - 1             : dernière interruption lue  
         pid = buffer[((((base[0] + base[2] - 1) % base[2])  
                 - ((base[3] - base[2]) + 1)) + base[2]) % base[2]];  
     }  
     else  
     {  
         // Plusieurs interruptions à distribuer.  
         drapeau = d_vrai;  
   
         do  
         {  
             delta = abs(horodatage() -  
                      buffer[base[0] + (nombre_queues * base[2])]);  
             pid = buffer[base[0]++];  
             base[0] %= base[2];  
             base[3]++;  
   
             if ((delta > (2 * markov)) && (base[3] < base[2]))  
             {  
                 drapeau = d_vrai;  
             }  
             else  
             {  
                 drapeau = d_faux;  
             }  
         } while(drapeau == d_vrai);  
   
         markov = chaine_markov(markov, delta);  
     }  
   
     if (sem_post(semaphores[queue]) != 0)  
     {  
         return(-1);  
     }  
   
     return((pid_t) pid);  
 }  
   
 #endif  
   
 void  void
 interruption1(SIGHANDLER_ARGS)  interruption1(SIGHANDLER_ARGS)
 {  {
Line 3169  traitement_exceptions_gsl(const char *re Line 2449  traitement_exceptions_gsl(const char *re
     return;      return;
 }  }
   
 #ifdef _BROKEN_SIGINFO  
   
 #undef kill  
 #undef pthread_kill  
   
 int  
 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  
      * correspondant au processus en question et ou ajoute le pid dans la  
      * 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);  
     }  
   
     while((semaphore = sem_open(nom, 0)) == SEM_FAILED);  
     free(nom);  
   
     while(sem_wait(semaphore) != 0)  
     {  
         if (errno != EINTR)  
         {  
             return(-1);  
         }  
     }  
   
     if ((signal != 0) && (signal != SIGINT))  
     {  
         if (queue_in(pid, signal) != 0)  
         {  
             sem_post(semaphore);  
             sem_close(semaphore);  
             return(-1);  
         }  
     }  
   
     ios = kill(pid, signal);  
   
     // Sémaphore relâché  
   
     sem_post(semaphore);  
     sem_close(semaphore);  
   
     return(ios);  
 }  
   
 int  
 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);  
     }  
   
     while((semaphore = sem_open(nom, 0)) == SEM_FAILED);  
     free(nom);  
   
     while(sem_wait(semaphore) != 0)  
     {  
         if (errno != EINTR)  
         {  
             return(-1);  
         }  
     }  
   
     if ((signal != 0) && (signal != SIGINT))  
     {  
         if (queue_in(getpid(), signal) != 0)  
         {  
             sem_post(semaphore);  
             sem_close(semaphore);  
             return(-1);  
         }  
     }  
   
     ios = pthread_kill(tid, signal);  
   
     sem_post(semaphore);  
     sem_close(semaphore);  
   
     return(ios);  
 }  
   
 #endif  
   
 // vim: ts=4  // vim: ts=4

Removed from v.1.35  
changed lines
  Added in v.1.36


CVSweb interface <joel.bertrand@systella.fr>