/* ================================================================================ RPL/2 (R) version 4.1.0.prerelease.1 Copyright (C) 1989-2011 Dr. BERTRAND Joël This file is part of RPL/2. RPL/2 is free software; you can redistribute it and/or modify it under the terms of the CeCILL V2 License as published by the french CEA, CNRS and INRIA. RPL/2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL V2 License for more details. You should have received a copy of the CeCILL License along with RPL/2. If not, write to info@cecill.info. ================================================================================ */ #define __BROKEN_SIGINFO_ROUTINES__ #include "rpl-conv.h" #ifdef _BROKEN_SIGINFO #define longueur_queue 256 #define nombre_queues 13 static int *fifos; static int markov; static sem_t *semaphores[nombre_queues]; static sem_t *semaphore_global; #ifdef IPCS_SYSV #ifndef OS2 static unsigned char *chemin = NULL; #endif #endif #ifdef OS2 PVOID ptr_os2; #else static int segment; #endif static unsigned char * nom_segment(unsigned char *chemin, pid_t pid) { unsigned char *fichier; # ifdef IPCS_SYSV # ifndef OS2 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((10 + 256 + 1) * sizeof(unsigned char))) == NULL) { return(NULL); } sprintf(fichier, "\\SHAREMEM\\RPL-SIGQUEUES-%d", (int) pid); # endif # else if ((fichier = malloc((1 + 256 + 1) * sizeof(unsigned char))) == NULL) { return(NULL); } sprintf(fichier, "/RPL-SIGQUEUES-%d", (int) pid); # endif return(fichier); } static 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-SIGSEMAPHORES-%d-%d", (int) pid, queue); return(fichier); } static 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 # ifndef OS2 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; } # else if ((nom = nom_segment(NULL, getpid())) == NULL) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } if (DosAllocSharedMem(&ptr_os2, nom, nombre_queues * ((2 * longueur_queue) + 4) * sizeof(int), PAG_WRITE | PAG_READ | PAG_COMMIT) != 0) { free(nom); (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } free(nom); fifos = ptr_os2; # endif # 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 # ifndef OS2 if (shmdt(fifos) == -1) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } # else if (DosFreeMem(fifos) != 0) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } # endif # 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 # ifndef OS2 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 if (DosFreeMem(fifos) != 0) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } # endif # 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; } static 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; # ifndef OS2 int identifiant; # endif 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 # ifndef OS2 key_t clef; struct stat s_stat; # endif // 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. # ifndef OS2 // Ouverture des projections if ((nom = nom_segment(chemin, pid)) == NULL) { return(-1); } 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); } # else // Ouverture des projections if ((nom = nom_segment(NULL, pid)) == NULL) { return(-1); } if (signal == SIGSTART) { horodatage_initial = horodatage(); while(DosGetNamedSharedMem(&ptr_os2, nom, PAG_READ | PAG_WRITE | PAG_COMMIT) != 0) { if (abs(horodatage_initial - horodatage()) > 500) { return(-1); } } } else { if (DosGetNamedSharedMem(&ptr_os2, nom, PAG_READ | PAG_WRITE) != 0) { return(-1); } } projection_fifos = ptr_os2; # endif # endif if ((nom = nom_semaphore(pid, queue)) == NULL) { # ifdef IPCS_SYSV # ifndef OS2 shmdt(projection_fifos); # else DosFreeMem(projection_fifos); # endif # 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 # ifndef OS2 shmdt(projection_fifos); # else DosFreeMem(projection_fifos); # endif # 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 # ifndef OS2 shmdt(projection_fifos); # else DosFreeMem(projection_fifos); # endif # 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 # ifndef OS2 shmdt(projection_fifos); # else DosFreeMem(projection_fifos); # endif # 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 # ifndef OS2 shmdt(projection_fifos); # else DosFreeMem(projection_fifos); # endif # else munmap(projection_fifos, nombre_queues * ((2 * longueur_queue) + 4) * sizeof(int)); # endif return(0); } static 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]]; if (kill(pid, 0) != 0) { pid = getpid(); } } 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); } 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