1: /*
2: ================================================================================
3: RPL/2 (R) version 4.0.19
4: Copyright (C) 1989-2010 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: #define __BROKEN_SIGINFO_ROUTINES__
24: #include "rpl-conv.h"
25:
26: #ifdef _BROKEN_SIGINFO
27:
28: #define longueur_queue 256
29: #define nombre_queues 13
30:
31: static int *fifos;
32: static int markov;
33: static int segment;
34: static sem_t *semaphores[nombre_queues];
35: static sem_t *semaphore_global;
36:
37: #ifdef IPCS_SYSV
38: static unsigned char *chemin = NULL;
39: #endif
40:
41: static unsigned char *
42: nom_segment(unsigned char *chemin, pid_t pid)
43: {
44: unsigned char *fichier;
45:
46: # ifdef IPCS_SYSV
47: if ((fichier = malloc((strlen(chemin) + 1 + 256 + 1) *
48: sizeof(unsigned char))) == NULL)
49: {
50: return(NULL);
51: }
52:
53: sprintf(fichier, "%s/RPL-SIGQUEUES-%d", chemin, (int) pid);
54: # else
55: if ((fichier = malloc((1 + 256 + 1) *
56: sizeof(unsigned char))) == NULL)
57: {
58: return(NULL);
59: }
60:
61: sprintf(fichier, "/RPL-SIGQUEUES-%d", (int) pid);
62: # endif
63:
64: return(fichier);
65: }
66:
67: static unsigned char *
68: nom_semaphore(pid_t pid, int queue)
69: {
70: unsigned char *fichier;
71:
72: if ((fichier = malloc((256 + 1) * sizeof(unsigned char))) == NULL)
73: {
74: return(NULL);
75: }
76:
77: sprintf(fichier, "/RPL-SIGESMAPHORES-%d-%d", (int) pid, queue);
78:
79: return(fichier);
80: }
81:
82: static inline int
83: queue_de_signal(int signal)
84: {
85: switch(signal)
86: {
87: case SIGINT:
88: return(0);
89: case SIGTSTP:
90: return(1);
91: case SIGCONT:
92: return(2);
93: case SIGURG:
94: return(3);
95: case SIGPIPE:
96: return(4);
97: case SIGALRM:
98: return(5);
99: case SIGFSTOP:
100: return(6);
101: case SIGSTART:
102: return(7);
103: case SIGINJECT:
104: return(8);
105: case SIGABORT:
106: return(9);
107: case SIGFABORT:
108: return(10);
109: case SIGSEGV:
110: return(11);
111: case SIGBUS:
112: return(12);
113: }
114:
115: return(-1);
116: }
117:
118: void
119: creation_fifos_signaux(struct_processus *s_etat_processus)
120: {
121: /*
122: * Signaux utilisés
123: * SIGINT, SIGTSTP, SIGCONT, SIGURG, SIGPIPE, SIGALRM, SIGFSTOP,
124: * SIGSTART, SIGINJECT, SIGABORT, SIGFABORT
125: */
126:
127: int i;
128:
129: unsigned char *nom;
130:
131: # ifndef IPCS_SYSV // POSIX
132:
133: if ((nom = nom_segment((*s_etat_processus).chemin_fichiers_temporaires,
134: getpid())) == NULL)
135: {
136: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
137: return;
138: }
139:
140: if ((segment = shm_open(nom, O_RDWR | O_CREAT | O_EXCL,
141: S_IRUSR | S_IWUSR)) == -1)
142: {
143: free(nom);
144: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
145: return;
146: }
147:
148: if (ftruncate(segment, nombre_queues * ((2 * longueur_queue) + 4) *
149: sizeof(int)) == -1)
150: {
151: free(nom);
152: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
153: return;
154: }
155:
156: fifos = mmap(NULL, nombre_queues * ((2 * longueur_queue) + 4) * sizeof(int),
157: PROT_READ | PROT_WRITE, MAP_SHARED, segment, 0);
158: close(segment);
159:
160: if (((void *) fifos) == ((void *) -1))
161: {
162: if (shm_unlink(nom) == -1)
163: {
164: free(nom);
165: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
166: return;
167: }
168:
169: free(nom);
170: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
171: return;
172: }
173:
174: free(nom);
175:
176: # else // SystemV
177:
178: file *desc;
179:
180: key_t clef;
181:
182: // Création d'un segment de données associé au PID du processus courant
183:
184: chemin = (*s_etat_processus).chemin_fichiers_temporaires;
185:
186: if ((nom = nom_segment((*s_etat_processus).chemin_fichiers_temporaires,
187: getpid())) == NULL)
188: {
189: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
190: return;
191: }
192:
193: if ((desc = fopen(nom, "w")) == NULL)
194: {
195: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
196: return;
197: }
198:
199: fclose(desc);
200:
201: if ((clef = ftok(nom, 1)) == -1)
202: {
203: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
204: return;
205: }
206:
207: free(nom);
208:
209: if ((segment = shmget(clef,
210: nombre_queues * ((2 * longueur_queue) + 4) * sizeof(int),
211: IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR)) == -1)
212: {
213: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
214: return;
215: }
216:
217: fifos = shmat(segment, NULL, 0);
218:
219: if (((void *) fifos) == ((void *) -1))
220: {
221: if (shmctl(segment, IPC_RMID, 0) == -1)
222: {
223: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
224: return;
225: }
226:
227: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
228: return;
229: }
230:
231: # endif
232:
233: /*
234: * Structure d'une queue
235: * 0 : pointeur en lecture sur le premier emplacement libre (int)
236: * 1 : pointeur en écriture sur le premier emplacement à lire (int)
237: * 2 : longueur de la queue (int)
238: * 3 : éléments restants (int)
239: * 4 à 4 + (2) : queue (int)
240: * 4 + (2) + 1 ) 4 + 2 * (2) : horodatage en centième de secondes.
241: */
242:
243: for(i = 0; i < nombre_queues; i++)
244: {
245: fifos[(i * (longueur_queue + 4))] = 0;
246: fifos[(i * (longueur_queue + 4)) + 1] = 0;
247: fifos[(i * (longueur_queue + 4)) + 2] = longueur_queue;
248: fifos[(i * (longueur_queue + 4)) + 3] = longueur_queue;
249: }
250:
251: // Création des sémaphores : un sémaphore par signal et par queue
252: // plus un sémaphore global pour tous les threads.
253:
254: for(i = 0; i < nombre_queues; i++)
255: {
256: if ((nom = nom_semaphore(getpid(), i)) == NULL)
257: {
258: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
259: return;
260: }
261:
262: // Le sémaphore est créé en écrasant si nécessaire un sémaphore
263: // préexistant. Comme le nom du sémaphore contient l'identifiant du
264: // processus, il est anormal d'avoir un sémaphore de même nom
265: // préexistant.
266:
267: if ((semaphores[i] = sem_open(nom, O_CREAT, S_IRUSR | S_IWUSR,
268: 1)) == SEM_FAILED)
269: {
270: (*s_etat_processus).erreur_systeme = d_es_semaphore;
271: return;
272: }
273:
274: free(nom);
275: }
276:
277:
278: if ((nom = nom_semaphore(getpid(), nombre_queues)) == NULL)
279: {
280: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
281: return;
282: }
283:
284: if ((semaphore_global = sem_open(nom, O_CREAT, S_IRUSR | S_IWUSR,
285: 1)) == SEM_FAILED)
286: {
287: (*s_etat_processus).erreur_systeme = d_es_semaphore;
288: return;
289: }
290:
291: free(nom);
292:
293: markov = 0;
294:
295: return;
296: }
297:
298: void
299: liberation_fifos_signaux(struct_processus *s_etat_processus)
300: {
301: int i;
302:
303: # ifdef IPCS_SYSV // SystemV
304:
305: if (shmdt(fifos) == -1)
306: {
307: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
308: return;
309: }
310:
311: # else // POSIX
312:
313: if (munmap(fifos, nombre_queues * ((2 * longueur_queue) + 4) * sizeof(int))
314: != 0)
315: {
316: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
317: return;
318: }
319:
320: # endif
321:
322: for(i = 0; i < nombre_queues; i++)
323: {
324: if (sem_close(semaphores[i]) != 0)
325: {
326: (*s_etat_processus).erreur_systeme = d_es_semaphore;
327: return;
328: }
329: }
330:
331: if (sem_close(semaphore_global) != 0)
332: {
333: (*s_etat_processus).erreur_systeme = d_es_semaphore;
334: return;
335: }
336:
337: return;
338: }
339:
340: void
341: destruction_fifos_signaux(struct_processus *s_etat_processus)
342: {
343: int i;
344:
345: unsigned char *nom;
346:
347: # ifdef IPCS_SYSV // SystemV
348:
349: if (shmdt(fifos) == -1)
350: {
351: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
352: return;
353: }
354:
355: if (shmctl(segment, IPC_RMID, 0) == -1)
356: {
357: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
358: return;
359: }
360:
361: if ((nom = nom_segment((*s_etat_processus).chemin_fichiers_temporaires,
362: getpid())) == NULL)
363: {
364: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
365: return;
366: }
367:
368: unlink(nom);
369: free(nom);
370:
371: # else // POSIX
372:
373: if (munmap(fifos, nombre_queues * ((2 * longueur_queue) + 4) * sizeof(int))
374: != 0)
375: {
376: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
377: return;
378: }
379:
380: if ((nom = nom_segment(NULL, getpid())) == NULL)
381: {
382: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
383: return;
384: }
385:
386: if (shm_unlink(nom) != 0)
387: {
388: free(nom);
389: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
390: return;
391: }
392:
393: free(nom);
394:
395: # endif
396:
397: for(i = 0; i < nombre_queues; i++)
398: {
399: if ((nom = nom_semaphore(getpid(), i)) == NULL)
400: {
401: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
402: return;
403: }
404:
405: if (sem_unlink(nom) != 0)
406: {
407: (*s_etat_processus).erreur_systeme = d_es_semaphore;
408: return;
409: }
410:
411: free(nom);
412: }
413:
414: if ((nom = nom_semaphore(getpid(), nombre_queues)) == NULL)
415: {
416: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
417: return;
418: }
419:
420: if (sem_unlink(nom) != 0)
421: {
422: (*s_etat_processus).erreur_systeme = d_es_semaphore;
423: return;
424: }
425:
426: free(nom);
427:
428: return;
429: }
430:
431: static inline int
432: horodatage()
433: {
434: int ts;
435:
436: struct timeval tv;
437:
438: gettimeofday(&tv, NULL);
439: ts = (int) ((tv.tv_sec * 100) + (tv.tv_usec / 10000));
440:
441: return(ts);
442: }
443:
444: int
445: queue_in(pid_t pid, int signal)
446: {
447: int queue;
448: int *base;
449: int *buffer;
450: int horodatage_initial;
451: int identifiant;
452: int *projection_fifos;
453:
454: sem_t *semaphore;
455:
456: queue = queue_de_signal(signal);
457:
458: unsigned char *nom;
459:
460: # ifndef IPCS_SYSV
461:
462: // Ouverture des projections
463:
464: if ((nom = nom_segment(NULL, pid)) == NULL)
465: {
466: return(-1);
467: }
468:
469: // Dans le cas de SIGSTART, premier signal envoyé à un processus fils,
470: // il convient d'attendre que le fichier support soit effectivement
471: // accessible. Dans tous les autres cas, ce fichier doit exister. S'il
472: // n'existe plus, le processus associé n'existe plus.
473:
474: if (signal == SIGSTART)
475: {
476: horodatage_initial = horodatage();
477:
478: while((identifiant = shm_open(nom, O_RDWR, S_IRUSR | S_IWUSR)) == -1)
479: {
480: if (abs(horodatage_initial - horodatage()) > 500)
481: {
482: return(-1);
483: }
484: }
485: }
486: else
487: {
488: if ((identifiant = shm_open(nom, O_RDWR, S_IRUSR | S_IWUSR)) == -1)
489: {
490: return(-1);
491: }
492: }
493:
494: projection_fifos = mmap(NULL, nombre_queues * ((2 * longueur_queue) + 4)
495: * sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, identifiant, 0);
496: close(identifiant);
497:
498: if (((void *) projection_fifos) == ((void *) -1))
499: {
500: return(-1);
501: }
502:
503: # else // Traitement à l'aide d'IPCS SystemV
504:
505: key_t clef;
506:
507: struct stat s_stat;
508:
509: // Ouverture des projections
510:
511: if ((nom = nom_segment(chemin, pid)) == NULL)
512: {
513: return(-1);
514: }
515:
516: // Dans le cas de SIGSTART, premier signal envoyé à un processus fils,
517: // il convient d'attendre que le fichier support soit effectivement
518: // accessible. Dans tous les autres cas, ce fichier doit exister. S'il
519: // n'existe plus, le processus associé n'existe plus.
520:
521: if (signal == SIGSTART)
522: {
523: // On attend que le fichier sois présent
524:
525: horodatage_initial = horodatage();
526:
527: while(stat(nom, &s_stat) != 0)
528: {
529: if (abs(horodatage_initial - horodatage()) > 500)
530: {
531: return(-1);
532: }
533: }
534: }
535:
536: if ((clef = ftok(nom, 1)) == -1)
537: {
538: return(-1);
539: }
540:
541: free(nom);
542:
543: if (signal == SIGSTART)
544: {
545: while((identifiant = shmget(clef,
546: nombre_queues * ((2 * longueur_queue) + 4) * sizeof(int),
547: S_IRUSR | S_IWUSR)) == -1);
548: }
549: else
550: {
551: if ((identifiant = shmget(clef,
552: nombre_queues * ((2 * longueur_queue) + 4) * sizeof(int),
553: S_IRUSR | S_IWUSR)) == -1)
554: {
555: return(-1);
556: }
557: }
558:
559: projection_fifos = shmat(identifiant, NULL, 0);
560:
561: if (((void *) projection_fifos) == ((void *) -1))
562: {
563: return(-1);
564: }
565:
566: # endif
567:
568: if ((nom = nom_semaphore(pid, queue)) == NULL)
569: {
570: # ifdef IPCS_SYSV
571: shmdt(projection_fifos);
572: # else
573: munmap(projection_fifos, nombre_queues * ((2 * longueur_queue) + 4)
574: * sizeof(int));
575: # endif
576: return(-1);
577: }
578:
579: while((semaphore = sem_open(nom, 0)) == SEM_FAILED);
580: free(nom);
581:
582: while(sem_wait(semaphore) != 0)
583: {
584: if (errno != EINTR)
585: {
586: # ifdef IPCS_SYSV
587: shmdt(projection_fifos);
588: # else
589: munmap(projection_fifos, nombre_queues * ((2 * longueur_queue) + 4)
590: * sizeof(int));
591: # endif
592: return(-1);
593: }
594: }
595:
596: base = &(projection_fifos[(longueur_queue + 4) * queue]);
597: buffer = &(base[4]);
598:
599: // base[3] contient le nombre d'éléments restants
600:
601: if (base[3] <= 0)
602: {
603: sem_post(semaphore);
604: sem_close(semaphore);
605: # ifdef IPCS_SYSV
606: shmdt(projection_fifos);
607: # else
608: munmap(projection_fifos, nombre_queues * ((2 * longueur_queue) + 4)
609: * sizeof(int));
610: # endif
611: return(-1);
612: }
613:
614: base[3]--;
615:
616: // base[1] contient le prochain élément à écrire
617:
618: buffer[base[1] + (nombre_queues * base[2])] = horodatage();
619: buffer[base[1]++] = (int) pid;
620: base[1] %= base[2];
621:
622: if (sem_post(semaphore) != 0)
623: {
624: # ifdef IPCS_SYSV
625: shmdt(projection_fifos);
626: # else
627: munmap(projection_fifos, nombre_queues * ((2 * longueur_queue) + 4)
628: * sizeof(int));
629: # endif
630: sem_close(semaphore);
631: return(-1);
632: }
633:
634: sem_close(semaphore);
635:
636: // Fermeture des projections
637: # ifdef IPCS_SYSV
638: shmdt(projection_fifos);
639: # else
640: munmap(projection_fifos, nombre_queues * ((2 * longueur_queue) + 4)
641: * sizeof(int));
642: # endif
643:
644: return(0);
645: }
646:
647: static inline int
648: chaine_markov(int markov, int delta)
649: {
650: double memoire = 0.9;
651: int valeur;
652:
653: valeur = (int) ((memoire * markov) + ((1 - memoire) * delta));
654: valeur = (valeur < 10) ? 10 : valeur;
655:
656: return(valeur);
657: }
658:
659: pid_t
660: origine_signal(int signal)
661: {
662: logical1 drapeau;
663:
664: int *base;
665: int *buffer;
666: int delta;
667: int pid;
668: int queue;
669:
670: queue = queue_de_signal(signal);
671:
672: BUG(queue == -1, uprintf("[%d] Unknown signal %d in this context\n",
673: (int) getpid(), signal));
674:
675: while(sem_wait(semaphores[queue]) != 0)
676: {
677: if (errno != EINTR)
678: {
679: return(-1);
680: }
681: }
682:
683: // On retire les interruptions anciennes qui ont été ratées sauf s'il
684: // s'agit de la dernière dans la queue.
685:
686: base = &(fifos[(longueur_queue + 4) * queue]);
687: buffer = &(base[4]);
688:
689: if (base[3] == (base[2] - 1))
690: {
691: delta = abs(horodatage() -
692: buffer[base[0] + (nombre_queues * base[2])]);
693: // Une seule interruption dans la queue.
694: pid = buffer[base[0]++];
695: base[0] %= base[2];
696: base[3]++;
697:
698: markov = chaine_markov(markov, delta);
699: }
700: else if (base[3] >= base[2])
701: {
702: // Aucune interruption n'est dans la queue.
703: // On a retiré trop d'interruptions de la queue.
704:
705: // (base[3] - base[2]) + 1 : nombre d'interruptions manquantes
706: // base[0] - 1 : dernière interruption lue
707: pid = buffer[((((base[0] + base[2] - 1) % base[2])
708: - ((base[3] - base[2]) + 1)) + base[2]) % base[2]];
709:
710: if (kill(pid, 0) != 0)
711: {
712: pid = getpid();
713: }
714: }
715: else
716: {
717: // Plusieurs interruptions à distribuer.
718: drapeau = d_vrai;
719:
720: do
721: {
722: delta = abs(horodatage() -
723: buffer[base[0] + (nombre_queues * base[2])]);
724: pid = buffer[base[0]++];
725: base[0] %= base[2];
726: base[3]++;
727:
728: if ((delta > (2 * markov)) && (base[3] < base[2]))
729: {
730: drapeau = d_vrai;
731: }
732: else
733: {
734: drapeau = d_faux;
735: }
736: } while(drapeau == d_vrai);
737:
738: markov = chaine_markov(markov, delta);
739: }
740:
741: if (sem_post(semaphores[queue]) != 0)
742: {
743: return(-1);
744: }
745:
746: return((pid_t) pid);
747: }
748:
749: int
750: kill_broken_siginfo(pid_t pid, int signal)
751: {
752: int ios;
753:
754: sem_t *semaphore;
755:
756: unsigned char *nom;
757:
758: /*
759: * Lorsqu'on veut interrompre le processus pid, on ouvre le segment
760: * correspondant au processus en question et ou ajoute le pid dans la
761: * queue.
762: *
763: * Le sémaphore global à tous les threads d'un même processus sert
764: * à garantir que les signaux seront traités dans l'ordre de ce qui est
765: * effectivement mis dans la queue.
766: */
767:
768: // Sémaphore acquis
769:
770: if ((nom = nom_semaphore(getpid(), nombre_queues)) == NULL)
771: {
772: return(-1);
773: }
774:
775: while((semaphore = sem_open(nom, 0)) == SEM_FAILED);
776: free(nom);
777:
778: while(sem_wait(semaphore) != 0)
779: {
780: if (errno != EINTR)
781: {
782: return(-1);
783: }
784: }
785:
786: if ((signal != 0) && (signal != SIGINT))
787: {
788: if (queue_in(pid, signal) != 0)
789: {
790: sem_post(semaphore);
791: sem_close(semaphore);
792: return(-1);
793: }
794: }
795:
796: ios = kill(pid, signal);
797:
798: // Sémaphore relâché
799:
800: sem_post(semaphore);
801: sem_close(semaphore);
802:
803: return(ios);
804: }
805:
806: int
807: pthread_kill_broken_siginfo(pthread_t tid, int signal)
808: {
809: int ios;
810:
811: sem_t *semaphore;
812:
813: unsigned char *nom;
814:
815: if ((nom = nom_semaphore(getpid(), nombre_queues)) == NULL)
816: {
817: return(-1);
818: }
819:
820: while((semaphore = sem_open(nom, 0)) == SEM_FAILED);
821: free(nom);
822:
823: while(sem_wait(semaphore) != 0)
824: {
825: if (errno != EINTR)
826: {
827: return(-1);
828: }
829: }
830:
831: if ((signal != 0) && (signal != SIGINT))
832: {
833: if (queue_in(getpid(), signal) != 0)
834: {
835: sem_post(semaphore);
836: sem_close(semaphore);
837: return(-1);
838: }
839: }
840:
841: ios = pthread_kill(tid, signal);
842:
843: sem_post(semaphore);
844: sem_close(semaphore);
845:
846: return(ios);
847: }
848:
849: #endif
850:
851: // vim: ts=4
CVSweb interface <joel.bertrand@systella.fr>