Advertisement
Guest User

Untitled

a guest
Jan 27th, 2020
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 13.20 KB | None | 0 0
  1. /* Długość linii, mechanizmy */
  2.  
  3. #include "stdio.h"
  4. #include "string.h"
  5.  
  6. #include "fcntl.h"
  7. #include "unistd.h"
  8. #include "errno.h"
  9.  
  10. #include "sys/types.h"
  11. #include "sys/stat.h"
  12. #include "stdlib.h"
  13. #include "wait.h"
  14.  
  15. #include "sys/ipc.h"
  16. #include "sys/sem.h"
  17. #include "sys/shm.h"
  18.  
  19. #define PATH_FIFO "/tmp/pieniak_projekt"
  20.  
  21. #define ROZMIAR_BUFORA_LINII 500
  22. #define ROZMIAR_BUFORA_KONWERSJI 2*ROZMIAR_BUFORA_LINII
  23. #define N_W_LINII 15
  24.  
  25. #define S_SHM_READ 0
  26. #define S_SHM_WRITE 1
  27. #define S_PIDS_READ 2
  28. #define S_LAST_SIG_WRITE 3
  29. #define S_LAST_SIG_R1 4
  30. #define S_LAST_SIG_R2 5
  31. #define S_LAST_SIG_R3 6
  32.  
  33. #define SIGNAL1 SIGINT
  34. #define SIGNAL2 SIGUSR1
  35. #define SIGNAL3 SIGCONT
  36. #define SIGNAL4 SIGUSR2
  37.  
  38. void signalHandler(int signum);
  39.  
  40. /* nazwy są dosc opisowe*/
  41. int semId;
  42. int shmId;
  43. /* To obszary pamieci dzielonej kolejno ilosci znakow w buforze(sposob przekazywania jej miedzy p2 i p3)*/
  44. int *nOfChars;
  45. /* To obszary pamieciprzechowuje znaki po konwersji(sposob przekazywania jej miedzy p2 i p3)*/
  46. char *convBuffer;
  47. /* Tablica pidow procesow sluzca im do komunikacji od przeslanych sygnalach */
  48. int *pids;
  49. /* Ostatni odebreany sygnał użyteczne gdy chcemy wiedziec czy musimy rozsylac sygnal od usera czy nie(
  50.     jesli jest taki sam jak ostatni nie zmieni stanu procesow
  51. )*/
  52. int *lastSig;
  53. /* Kopia wartosci z powyzszej pamięci dzialonej  aby nie blokować za długo dostępu do tej pamieci */
  54. int lastSigCopy;
  55.  
  56. /* Deskryptor wejscia*/
  57. int inputDescriptor = -1;
  58.  
  59. /* Maska na ktorej procesu oczekują przy użyciu funkcji sigsuspend po otrzymaniu sygnału 2 */
  60. sigset_t sigsuspendMask;
  61.  
  62. /* Sighandler dla sygnałow 1-3 przesyla do innych procesow przez pamiec dzielona informacje o tym czego żąda operator(jeśli
  63.  to żądniae jest różne od poprzedniego) i sam wykonuje odpowiednie czynnosci */
  64. void normalSigHandler(int signum);
  65. /* Dziala jak wyzje tylko nie rozsyla sygnalu a dzialania podejmuje nie na podstawie numeru sygnalu a zwartosci pamieci dzielonej*/
  66. void comunicationSigHandler(int signum);
  67.  
  68. static struct sembuf semopBuffer;
  69.  
  70. /* Analogiczna do zwyklej funkcji read tylko ponawia w przypadku otrzymania sygnału */
  71. int readFifo(int fd, char *str, size_t len) {
  72.     int toReturn;
  73. repeat:
  74.     toReturn = read(fd, str, len);
  75.     if(toReturn == -1 && errno == EINTR)
  76.         goto repeat;
  77.     return toReturn;
  78. }
  79.  
  80. /*Tablica pomocnicza i funkcja służące do konwersji wartosci bajtów na heksadecymalne */
  81. char hexConversionArray[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
  82.  
  83. size_t hexConvesion(char* in, char* out, int n)
  84. {
  85.     int i = 0;
  86.     for(i = 0; i < n; i++)
  87.     {
  88.         out[2*i] = hexConversionArray[(in[i]  >> 4) & 0x0F];
  89.         out[2*i + 1] = hexConversionArray[(in[i] & 0x0F)];
  90.     }
  91.     return 2*n;
  92. }
  93.  
  94. /* opisuje reakcję na sygnał. Wydzielone do osobnej funkcji ponieważ używam tego w 2 handlerach */
  95. void reactToSignal(int signum);
  96.  
  97. /* Operacja na jednym z semaforow sysV z zestawu */
  98. void sysvSemop(int semid, int semnum, int anmount) {
  99. repeat:
  100.     semopBuffer.sem_num = semnum;
  101.     semopBuffer.sem_op = anmount;
  102.     semopBuffer.sem_flg = 0;
  103.     if (semop(semid, &semopBuffer, 1) == -1)
  104.     {
  105.         if(errno == EINTR)
  106.             goto repeat;
  107.         else {
  108.             perror("semop");
  109.             exit(1);
  110.         }
  111.     }
  112. }
  113.  
  114. /* Analogiczna do zwyklej funkcji read tylko ponawia w przypadku otrzymania sygnału */
  115. int writeFifo(int fd, char *str, size_t len) {
  116.     int toReturn;
  117. repeat:
  118.     toReturn = write(fd, str, len);
  119.     if(toReturn == -1 && errno == EINTR)
  120.         goto repeat;
  121.     return toReturn;
  122. }
  123.  
  124. /* Z uwagi na ilosc semaforow ustawianie domyslnej wartosci semafora wydzieliwem do osobnej funkcji */
  125. int ustawDomyslnaSemafora(int semid, short semnum, int semval) {
  126.     if (semctl(semid, semnum, SETVAL, semval) == -1){
  127.         remove(PATH_FIFO);
  128.         semctl(semid, 0, IPC_RMID, 0);
  129.         perror("semop");
  130.         return -1;
  131.     }
  132.     return 0;
  133. }
  134.  
  135. /* Funkcje wywoływane w procesach 1-3*/
  136. void task1();
  137. void task2();
  138. void task3();
  139.  
  140. int main(int argc, char** argv) {
  141. /* Otworz plik wskazany przez argumenty wywolania */
  142.     if(argc == 2) {
  143.         if(strcmp(argv[1], "-r") == 0) {
  144.             inputDescriptor = open("/dev/urandom", O_RDONLY);
  145.         } else {
  146.             inputDescriptor = open(argv[1], O_RDONLY);
  147.         }
  148.     } else {
  149.         inputDescriptor = 0;
  150.     }
  151.  
  152.     if(inputDescriptor == -1) {
  153.         perror("Otwieranie pliku wejsciowego");
  154.         exit(1);
  155.     }
  156. /* Przygotwuje maske dla sigsuspend */
  157.     sigfillset (&sigsuspendMask);
  158.     sigdelset(&sigsuspendMask, SIGNAL1);
  159.     sigdelset(&sigsuspendMask, SIGNAL2);
  160.     sigdelset(&sigsuspendMask, SIGNAL3);
  161.     sigdelset(&sigsuspendMask, SIGNAL4);
  162. /* Tworze fifo do komunkacji procesów 1 i 2*/
  163.     printf("Tworze fifo 1->2\n");
  164.     umask(0);
  165.     remove(PATH_FIFO);
  166.     if(mkfifo(PATH_FIFO, 0600) == -1) {
  167.         perror("Tworzenie fifo 1->2");
  168.         exit(1);
  169.     }
  170.  
  171. /* Tworze zestaw semaforow */
  172.     semId = semget(IPC_PRIVATE, 7, 0600|IPC_CREAT);
  173.     if(semId == -1) {
  174.         remove(PATH_FIFO);
  175.         perror("Tworzenie semaforow");
  176.     }
  177.    
  178. /* Ustawiam wartosci domyslne semaforow */
  179.     ustawDomyslnaSemafora(semId, S_SHM_READ, 0);
  180.     ustawDomyslnaSemafora(semId, S_SHM_WRITE, 1);
  181.     ustawDomyslnaSemafora(semId, S_PIDS_READ, 0);
  182.     ustawDomyslnaSemafora(semId, S_LAST_SIG_WRITE, 3);
  183.     ustawDomyslnaSemafora(semId, S_LAST_SIG_R1, 0);
  184.     ustawDomyslnaSemafora(semId, S_LAST_SIG_R2, 0);
  185.     ustawDomyslnaSemafora(semId, S_LAST_SIG_R3, 0);
  186.  
  187. /*Tworze pamięc dzieloną */
  188.     shmId = shmget(IPC_PRIVATE,sizeof(int) + ROZMIAR_BUFORA_KONWERSJI * sizeof(char) + 4 * sizeof(int), 0600|IPC_CREAT);
  189.     if(shmId < 0) {
  190.         perror("shmget");
  191.         exit(1);
  192.     }
  193. /* I przyłączma ją pod odpowiednie adresy */
  194.     nOfChars = shmat(shmId, NULL, 0);
  195.     convBuffer = (char*)(nOfChars + 1);
  196.     pids = (int *)(convBuffer + ROZMIAR_BUFORA_KONWERSJI);
  197.     lastSig = pids + 3;
  198.  
  199. /* Tworze 3 procesy tworząc odpowiednie funkcje */
  200.     int rc = fork();
  201.     if(rc == 0) {
  202.         task1();
  203.         exit(0);
  204.     }
  205.     pids[0] = rc;
  206.  
  207.     rc = fork();
  208.     if(rc == 0) {
  209.         task2();
  210.         exit(0);
  211.     }
  212.     pids[1] = rc;
  213.  
  214.     rc = fork();
  215.     if(rc == 0) {
  216.         task3();
  217.         exit(0);
  218.     }
  219.     pids[2] = rc;
  220. /* Ustawiamy, ze startowym poprzednim sygnałem dla procesu jest sygnał do kontynuacji działania */
  221.     *lastSig = SIGNAL3;
  222.     lastSigCopy = SIGNAL3;
  223. /* Wypisuje pidy utworzonych procesów */
  224.     printf("Pid1:%d pid2:%d pid3:%d\n", pids[0], pids[1], pids[2]);
  225.     fflush(stdout);
  226. /* Informuję procesy, ze tablica pidów została poprawnie uzupełniona co jest ważne dla obsługi sygnałów wiec nie włączamy ich przed tym momentem */
  227.     sysvSemop(semId, S_PIDS_READ, 3);
  228. /* Po zakończeniu procesów 1,2 i 3 usuwam dla ich komunikacji zasoby */
  229.     wait(0);
  230.     wait(0);
  231.     wait(0);
  232. /* Program ussuwa utworzone zasoby */
  233.     if(remove(PATH_FIFO) == -1) {
  234.         perror("Usuwanie fifo 1");
  235.     }
  236.  
  237.     if(shmctl(shmId, IPC_RMID, 0) == -1) {
  238.         perror("Usuwanie pamieci dzielonej");
  239.     }
  240.  
  241.     if(semctl(semId, 0, IPC_RMID, 0) == -1) {
  242.         perror("Usuwanie zestawu semaforow");
  243.     }
  244.     printf("Zakończono działanie\n");
  245. }
  246.  
  247.  
  248. void task1() {
  249. /* Tworzę bufor otwieram fifo i po otrzymaniu informacji, że pidy zostały poprawnie uzupełnione włączam obsługę
  250. sygnałów */
  251.     fprintf(stderr, "proces 1 uruchamia sie\n");
  252.     size_t nOfReadChars = 0;
  253.     char lineBuffer[ROZMIAR_BUFORA_LINII];
  254.     int fifoFd = open(PATH_FIFO, O_WRONLY);
  255.     sysvSemop(semId, S_PIDS_READ, -1);
  256.  
  257.     signal(SIGNAL1, normalSigHandler);
  258.     signal(SIGNAL2, normalSigHandler);
  259.     signal(SIGNAL3, normalSigHandler);
  260.     signal(SIGNAL4, comunicationSigHandler);
  261.     do {
  262. /* Pobieram dane ze wskazanego deskryptora i przekazuję je przez fifo poprzedzjaąc je ilościa odczytanych znaków do procesu 2 */
  263.         nOfReadChars = readFifo(inputDescriptor, lineBuffer, ROZMIAR_BUFORA_LINII);
  264.         writeFifo(fifoFd, (char*)(&nOfReadChars), sizeof(size_t));
  265.         writeFifo(fifoFd, lineBuffer, nOfReadChars);
  266.     } while (nOfReadChars > 0);
  267.    
  268. }
  269. void task2() {
  270. /* Tworzę bufor otwieram fifo i po otrzymaniu informacji, że pidy zostały poprawnie uzupełnione włączam obsługę
  271. sygnałów */
  272.     fprintf(stderr, "proces 2 uruchamia sie\n");
  273.     long nOfCharsRead = 0;
  274.     long nCharsConversion = 0;
  275.     char lineBuffer[ROZMIAR_BUFORA_LINII];
  276.     char conversionBuffer[ROZMIAR_BUFORA_KONWERSJI];
  277.     int fifoFd = open(PATH_FIFO, O_RDONLY);
  278.     sysvSemop(semId, S_PIDS_READ, -1);
  279.     int i;
  280.     signal(SIGNAL1, normalSigHandler);
  281.     signal(SIGNAL2, normalSigHandler);
  282.     signal(SIGNAL3, normalSigHandler);
  283.     signal(SIGNAL4, comunicationSigHandler);
  284.     do {
  285. /* Odczytuje linie z fifo ilosc bajtow a nastepnie same bajty do odpowiedniego bufora */
  286.         readFifo(fifoFd, (char*)(&nOfCharsRead), sizeof(size_t));
  287.         readFifo(fifoFd, lineBuffer, nOfCharsRead);
  288. /* Konwertuję te bajty na ich wartości heksadecymalne */
  289.         nCharsConversion = hexConvesion(lineBuffer, conversionBuffer, nOfCharsRead);
  290. /* I przekazuję je przez pamięć dzieloną synchronizując do niej dostęp semaformai */
  291.         sysvSemop(semId, S_SHM_WRITE, -1);
  292.         *nOfChars = nCharsConversion;
  293.         for(i = 0; i<nCharsConversion; i++) {
  294.             convBuffer[i] = conversionBuffer[i];
  295.         }
  296.         sysvSemop(semId, S_SHM_READ, 1);
  297. /* Koncze w warunkach jak wyżej */
  298.     } while (nOfCharsRead > 0);
  299. }
  300.  
  301. void task3() {
  302. /* Tworże bufor i ustawiam obsługę sygnałów jak w poprzednich procesach */
  303.     char recivedBuffer[ROZMIAR_BUFORA_KONWERSJI];
  304.     char lineBuffer[100];
  305.     fprintf(stderr, "proces 3 uruchamia sie\n");
  306.     long lengthToPrint = 0;
  307.     sysvSemop(semId, S_PIDS_READ, -1);
  308.     int i;
  309.     int nCharsInPrintingBuffer = 0;
  310.     signal(SIGNAL1, normalSigHandler);
  311.     signal(SIGNAL2, normalSigHandler);
  312.     signal(SIGNAL3, normalSigHandler);
  313.     signal(SIGNAL4, comunicationSigHandler);
  314.     do {
  315. /* Odczytuję długość bufora przekazaną przez proces 2 oraz znaki powstale w wyniku konwersji. Odczyt synchronizuję przy użycoiu semaforów*/
  316.         sysvSemop(semId, S_SHM_READ, -1);
  317.         lengthToPrint = *nOfChars;
  318.         for(i = 0; i<lengthToPrint; i++) {
  319.             recivedBuffer[i] = convBuffer[i];
  320.         }
  321.         sysvSemop(semId, S_SHM_WRITE, 1);
  322. /* Wypisuję dane zgodnie ze specyfikacją */
  323.         for(int i = 0; i < lengthToPrint/2; i++) {
  324.             if(nCharsInPrintingBuffer == 0) {
  325.                 lineBuffer[0] = 0;
  326.             }
  327.             lineBuffer[3*nCharsInPrintingBuffer] = recivedBuffer[2*i];
  328.             lineBuffer[3*nCharsInPrintingBuffer + 1] = recivedBuffer[2*i + 1];
  329.             lineBuffer[3*nCharsInPrintingBuffer + 2] = ' ';
  330.             nCharsInPrintingBuffer++;
  331.             if(nCharsInPrintingBuffer >= N_W_LINII ) {
  332.                 lineBuffer[3*nCharsInPrintingBuffer] = '\n';
  333.                 lineBuffer[3*nCharsInPrintingBuffer + 1] = '\0';
  334.                 writeFifo(1, lineBuffer, 3*nCharsInPrintingBuffer +1);
  335.                 nCharsInPrintingBuffer = 0;
  336.                 lineBuffer[0] = 0;
  337.             }
  338.         }
  339.         if(lengthToPrint == 0) {
  340.                 lineBuffer[3*nCharsInPrintingBuffer] = '\n';
  341.                 lineBuffer[3*nCharsInPrintingBuffer + 1] = '\0';
  342.                 writeFifo(1, lineBuffer, 3*nCharsInPrintingBuffer +1);
  343.         }
  344. /* Warunek końca taki sam jak ostatnio */
  345.     } while(lengthToPrint > 0);
  346.  
  347. }
  348. /* Działanie opisane przy prototypie */
  349. void normalSigHandler(int signum) {
  350.     fprintf(stderr, "Odebraalem normalny sygnal %d\n", signum);
  351.     int myPid = getpid();
  352.     if(signum != lastSigCopy) {
  353.         sysvSemop(semId, S_LAST_SIG_WRITE, -2);
  354.         *lastSig = signum;
  355.         if(myPid != pids[0]) {
  356.             fprintf(stderr, "Wysylam S4 do P1\n");
  357.             sysvSemop(semId, S_LAST_SIG_R1, 1);
  358.             kill(pids[0], SIGNAL4);
  359.         }
  360.         if(myPid != pids[1]) {
  361.             fprintf(stderr, "Wysylam S4 do P2\n");
  362.             sysvSemop(semId, S_LAST_SIG_R2, 1);
  363.             kill(pids[1], SIGNAL4);
  364.         }
  365.         if(myPid != pids[2]) {
  366.             fprintf(stderr, "Wysylam S4 do P3\n");
  367.             sysvSemop(semId, S_LAST_SIG_R3, 1);
  368.             kill(pids[2], SIGNAL4);
  369.         }
  370.     }
  371.     lastSigCopy = signum;
  372.     reactToSignal(signum);
  373. }
  374. /* Działanie opisane przy prototypie */
  375. void comunicationSigHandler(int signum) {
  376.     int myPid = getpid();
  377.     if(myPid == pids[0]) {
  378.         sysvSemop(semId, S_LAST_SIG_R1, -1);
  379.     } else if(myPid == pids[1]) {
  380.         sysvSemop(semId, S_LAST_SIG_R2, -1);
  381.     } else {
  382.         sysvSemop(semId, S_LAST_SIG_R3, -1);
  383.     }
  384.     lastSigCopy = *lastSig;
  385.     sysvSemop(semId, S_LAST_SIG_WRITE, 1);
  386.     fprintf(stderr, "Odebralem sygnal %d przez pamiec dizelona\n", lastSigCopy);
  387.     reactToSignal(lastSigCopy);
  388.  
  389. }
  390. /* Działanie opisane przy prototypie */
  391. void reactToSignal(int signum) {
  392.     switch (signum)
  393.     {
  394.     case SIGNAL1:
  395.             exit(0);
  396.         break;
  397.  
  398.     case SIGNAL2:
  399.             sigsuspend(&sigsuspendMask);
  400.         break;
  401.    
  402.     default:
  403.         break;
  404.     }
  405. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement