Advertisement
KsaneK

Projekt2 Systemy Operacyjne

Jan 22nd, 2018
148
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 10.85 KB | None | 0 0
  1. #include <sys/types.h>
  2. #include <sys/ipc.h>
  3. #include <sys/msg.h>
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include <fcntl.h>
  8. #include <unistd.h>
  9. #include <signal.h>
  10.  
  11. int process_num; // Numer procesu (1,2,3)
  12. int pids[2]; // Każdy proces przetrzymuje pidy dwóch pozostałych procesów
  13. int queue; // Kolejka komunikatów
  14. int fd_pipe1[2]; // Tworzymy potok 1
  15. int fd_pipe2[2]; // Tworzymy potok 2
  16. int fd_pipe3[2]; // Tworzymy potok 3
  17. int resumed = 0; // Po otrzymaniu sygnału ustawiamy na 1, aby wyświetlić drugi raz tej samej wiadomości
  18.  
  19. // SYGNAŁY
  20. int S1 = SIGINT; // Zakończenie działania procesów
  21. int S2 = SIGUSR1; // Zatrzymanie działania procesów
  22. int S3 = SIGCONT; // Przywrócenie działania procesów
  23. int S4 = SIGUSR2; // Powiadomienie pozostałych procesów o odebranym sygnale
  24.  
  25. int sprawdzPoprawnosc(char text[1000])
  26. {
  27.     // Długość tekstu - 1 (ostatni jest pusty znak '\0', więc go pomijamy)
  28.     int length = strlen(text)-1;
  29.     int i = 0;
  30.     int czyLiczba = 0;
  31.     // Sprawdzamy czy ostatni znak jest cyfrą, jeżeli nie to od razu zwracamy 0
  32.     if(!isdigit(text[length-1])) return 0;
  33.     // W pętli przechodzimy po każdym znaku
  34.     for(i; i < length; i++)
  35.     {
  36.         // Jeżeli nie było wcześniej żadnej cyfry i odczytany znak nie jest cyfrą to zwracamy 0
  37.         if(czyLiczba == 0 && !isdigit(text[i])) return 0;
  38.         // Jeżeli odczytany znak to '+', ustawiamy zmienną czyLiczba na 0
  39.         if(text[i] == '+') czyLiczba = 0;
  40.         // Jeżeli odczytany znak jest cyfrą to ustawiamy czyLiczba na 1
  41.         else if(isdigit(text[i])) czyLiczba = 1;
  42.         // Jeżeli żaden z powyższych warunków nie został spełniony
  43.         // to znaczy że odczytano inny znak niż '+' i cyfrę
  44.         // a więc nie spełnia to wymagań i zwracamy 0
  45.         else return 0;
  46.     }
  47.     // Jeżeli funkcja nie zwróciła 0, to znaczy, że przesłany ciąg jest poprawny
  48.     return 1;
  49. }
  50.  
  51. unsigned long policzLinie(char text[1000])
  52. {
  53.     // Długość tekstu - 1 (ostatni jest pusty znak '\0', więc go pomijamy)
  54.     int length = strlen(text)-1;
  55.     // i - przechodzenie po kolejnych znakach
  56.     // j - przechodzenie po buforze dla odczytywanej liczby
  57.     int i = 0, j = 0;
  58.     // bufor, który będziemy konwertować na int i dodawać do sumy
  59.     char num_bufor[12];
  60.     // ustawiamy zmienną suma na 0
  61.     unsigned long suma = 0;
  62.     // przechodzimy po wszystkich znakach linii
  63.     for(i; i < length; i++)
  64.     {
  65.         // jeżeli wcześniej nie było cyfry i odczytany znak nie jest cyfrą
  66.         // to ciąg jest nieprawidłowy i zwracamy 0
  67.         if(j == 0 && !isdigit(text[i])) return 0;
  68.         // jeżeli odczytany znak to '+'
  69.         if(text[i] == '+')
  70.         {
  71.             // dodajemy znak pusty na koniec bufora
  72.             num_bufor[j] = 0;
  73.             // konwertujemy bufor znaków na int i dodajemy do sumy
  74.             suma += atoi(num_bufor);
  75.             // resetujemy indeks od jakiego zapisujemy znaki do bufora
  76.             j = 0;
  77.         }
  78.         // jeżeli nie został odczytany '+' to znaczy, że odczytano cyfrę
  79.         // dodajemy ją do bufora i inkrementujemy j
  80.         else num_bufor[j++] = text[i];
  81.     }
  82.     // gdy doszło do końca znaków to ustawiamy kolejny znak jako pusty
  83.     num_bufor[j] = 0;
  84.     // konwertujemy bufor na int i dodajemy do sumy
  85.     suma += atoi(num_bufor);
  86.     // zwracamy obliczoną sumę linii
  87.     return suma;
  88. }
  89.  
  90. /* --------------------------------------- */
  91. /* Struktura i funkcje kolejki komunikatów */
  92. /* --------------------------------------- */
  93.  
  94. struct message {
  95.     // Typ wiadomości (adresowanie do danego procesu)
  96.     long type;
  97.     // Przesyłany tekst
  98.     char text[1000];
  99. };
  100.  
  101. int msg_utworz()
  102. {
  103.     // Generowanie klucza
  104.     int key = ftok(".", 100);
  105.     // Tworzenie kolejki komunikatów
  106.     int queue = msgget(key, IPC_CREAT | 0666);
  107.     // Zwracanie id kolejki komunikatów
  108.     return queue;
  109. }
  110.  
  111. int msg_usun(int queue)
  112. {
  113.     // Usuwanie kolejki komunikatów
  114.     msgctl(queue, IPC_RMID, NULL);
  115. }
  116.  
  117. /* --------------------------------------- */
  118. /*            Obsługa sygnałów             */
  119. /* --------------------------------------- */
  120.  
  121. void killProcess()
  122. {
  123.     // Wypisujemy który proces kończy swoje działanie
  124.     fprintf(stderr, "KILL %d\n", process_num);
  125.     if(process_num == 1)
  126.     {
  127.         // Zamykamy pipe 1
  128.         close(fd_pipe1[0]);
  129.         close(fd_pipe1[1]);
  130.     }
  131.     else if(process_num == 2)
  132.     {
  133.         // Zamykamy pipe 2
  134.         close(fd_pipe2[0]);
  135.         close(fd_pipe2[1]);
  136.     }
  137.     else if(process_num == 3)
  138.     {
  139.         // Zamykamy pipe 3
  140.         close(fd_pipe3[0]);
  141.         close(fd_pipe3[1]);
  142.         // Usuwamy kolejkę komunikatów
  143.         msg_usun(queue);
  144.     }
  145.     exit(0);
  146. }
  147.  
  148. void stopProcess()
  149. {
  150.     // Wyświetla który proces zatrzymujemy
  151.     fprintf(stderr, "STOP %d\n", process_num);
  152.     // Tworzymy maskę sygnałów
  153.     sigset_t mask;
  154.     // Wypełniamy maskę (ignorujemy wszystkie sygnały)
  155.     sigfillset(&mask);
  156.     // Usuwamy z maski sygnał S3 (sygnał ten będzie mógł wznowić pracę procesu)
  157.     sigdelset(&mask, S3);
  158.     // Usuwamy z maski sygnał S4 (sygnał ten będzie mógł wznowić pracę procesu)
  159.     sigdelset(&mask, S4);
  160.     // Robimy suspend (proces teraz czeka na sygnał S3 lub S4)
  161.     sigsuspend(&mask);
  162. }
  163.  
  164. void resumeProcess()
  165. {
  166.     // ustawiamy resumed na 1,
  167.     resumed = 1;
  168.     // Wyświetlamy, który proces został wznowiony
  169.     fprintf(stderr, "RESUME %d\n", process_num);
  170. }
  171.  
  172. void sigAction(int signum)
  173. {
  174.     // W zależności od otrzymanego sygnału jaka funkcja ma się wykonać
  175.     if(signum == S1) killProcess();
  176.     else if(signum == S2) stopProcess();
  177.     else if(signum == S3) resumeProcess();
  178. }
  179.  
  180. void handleSig(int signum)
  181. {
  182.     /* ---------------------------------------------- */
  183.     /* Obsługa sygnału przez proces, który go odebrał */
  184.     /* ---------------------------------------------- */
  185.  
  186.     // Zapisanie numeru sygnału do pipe pozostałych procesów
  187.     if(process_num != 1) write(fd_pipe1[1], &signum, sizeof(int));
  188.     if(process_num != 2) write(fd_pipe2[1], &signum, sizeof(int));
  189.     if(process_num != 3) write(fd_pipe3[1], &signum, sizeof(int));
  190.  
  191.     // Powiadamiamy pozostałe procesy o sygnale
  192.     kill(pids[0], S4);
  193.     kill(pids[1], S4);
  194.  
  195.     // Wykonujemy odpowiednią funkcję dla otrzymanego sygnału
  196.     sigAction(signum);
  197. }
  198.  
  199. void sigMessage(int signum)
  200. {
  201.     // Po otrzymaniu Si4 odczytujemy z pipe numer sygnału
  202.     // Każdy proces ma swój osobny potok, w którym adresowane są do niego przesłane sygnały
  203.     int sig;
  204.     if(process_num == 1) read(fd_pipe1[0], &sig, sizeof(int));
  205.     if(process_num == 2) read(fd_pipe2[0], &sig, sizeof(int));
  206.     if(process_num == 3) read(fd_pipe3[0], &sig, sizeof(int));
  207.     // Przesyłamy odczytany sygnał do funkcji sigAction
  208.     sigAction(sig);
  209. }
  210.  
  211. /* WYMIANA PIDAMI PROCESÓW */
  212. void wymiana_pidami(int *queue)
  213. {
  214.     // Tworzenie wiadomości i wysłanie swojego pida pozostałym procesom
  215.     struct message m;
  216.     // Konwertujemy pid procesu na tekst i zapisujemy go w polu text wiadomości
  217.     sprintf(m.text, "%d", getpid());
  218.     int i = 1;
  219.     // Przechodzimy w pętli przez wartości 1,2,3
  220.     for(i; i < 4; i++)
  221.     {
  222.         // Jeżeli aktualny numer w pętli jest równy numerowi procesu
  223.         // to przechodzimy do kolejnego kroku pętli
  224.         if(i == process_num) continue;
  225.         // Ustawiamy typ wiadomości na wartość i (adresujemy wiadomość do pozostałych procesów)
  226.         m.type = i;
  227.         // Wysyłamy wiadomość w kolejce komunikatów
  228.         msgsnd(*queue, &m, sizeof(m), 0);
  229.     }
  230.  
  231.     // Odebranie pidów pozostałych procesów
  232.     msgrcv(*queue, &m, sizeof(m), process_num, 0);
  233.     // Konwersja odczytanego pida w postaci stringa na inta i zapisanie w zmiennej globalnej
  234.     pids[0] = atoi(m.text);
  235.     msgrcv(*queue, &m, sizeof(m), process_num, 0);
  236.     pids[1] = atoi(m.text);
  237. }
  238.  
  239. /* --------------------------------------- */
  240. /*                Proces 1                 */
  241. /* Odczytuje dane ze standardowego wejścia */
  242. /* i przekazuje je w niezmienionej formie  */
  243. /*          do procesu numer 2             */
  244. /* --------------------------------------- */
  245.  
  246. void proces1()
  247. {
  248.     struct message m;
  249.  
  250.     // Ustawienie typu wiadomosci na 2 (adresowanie do drugiego procesu)
  251.     m.type = 2;
  252.     while(fgets(m.text, 1000, stdin) != NULL)
  253.     {
  254.         // Wysyłamy odczytany z stdina tekst kolejką komunikatów
  255.         msgsnd(queue, &m, sizeof(m), 0);
  256.         // Pozostałe procesu potrzebują trochę czasu
  257.         // na sprawdzenie poprawności danych i policzenie sumy
  258.         // więc aby nie przepełnić kolejki czekamy 5ms
  259.         usleep(5000);
  260.     }
  261.     m.text[0] = EOF;
  262.     msgsnd(queue, &m, sizeof(m), 0);
  263.     close(fd_pipe1[0]);
  264.     close(fd_pipe1[1]);
  265. }
  266.  
  267. /* ---------------------------------------- */
  268. /*                 Proces 2                 */
  269. /*  Pobiera dane i sprawdza ich poprawność  */
  270. /* ---------------------------------------- */
  271.  
  272. void proces2()
  273. {
  274.     // Tworzymy zmienną do odczytania wiadomości
  275.     struct message m;
  276.     // Odbiera wiadomość o typie 2 do zmiennej m
  277.     while(msgrcv(queue, &m, sizeof(m), 2, 0))
  278.     {
  279.         // Ustawiamy typ wiadomości na 3 (adresowanie do procesu 3)
  280.         m.type = 3;
  281.         // Jeżeli został wysłany EOF to wysyłamy go do procesu 3 i kończymy pracę
  282.         if(m.text[0] == EOF)
  283.         {
  284.             msgsnd(queue, &m, sizeof(m), 0);
  285.             break;
  286.         }
  287.         // Po otrzymaniu sygnału wznawiającego proces "przeskakuje" oczekiwanie na wiadomość
  288.         // i nie wysyłamy drugi raz poprzedniej wiadomości
  289.         if(resumed)
  290.             resumed = 0;
  291.         // Sprawdzamy czy otrzymane dane mają poprawny format
  292.         // Jeżeli tak to przesyłamy do procesu 3
  293.         else if(sprawdzPoprawnosc(m.text))
  294.             msgsnd(queue, &m, sizeof(m), 0);
  295.     }
  296.     close(fd_pipe2[0]);
  297.     close(fd_pipe2[1]);
  298. }
  299.  
  300. /* ---------------------------------------- */
  301. /*                Proces 3                  */
  302. /* Pobiera dane z procesu 2 i wylicza sumę  */
  303. /*    wyrażenia, następnie obliczoną sumę   */
  304. /*    umieszcza w standardowym strumieniu   */
  305. /*               wyjściowym                 */
  306. /* ---------------------------------------- */
  307.  
  308. void proces3()
  309. {
  310.     // Tworzy zmienną na odebraną wiadomość
  311.     struct message m;
  312.     // Odbiera wiadomość o typie 3 do zmiennej m
  313.     while(msgrcv(queue, &m, sizeof(m), 3, 0))
  314.     {
  315.         // Jeżeli odczytało EOF to kończy działanie
  316.         if(m.text[0] == EOF) break;
  317.         // Po otrzymaniu sygnału wznawiającego pracę proces "przeskakuje"
  318.         // przez odebranie kolejnej wiadomości, więc nie wyświetlamy wyniku obliczeń
  319.         if(resumed)
  320.             resumed = 0;
  321.         else
  322.             printf("%ld\n", policzLinie(m.text));
  323.     }
  324.     close(fd_pipe3[0]);
  325.     close(fd_pipe3[1]);
  326.     msg_usun(queue);
  327. }
  328.  
  329. void proces(int i)
  330. {
  331.     process_num = i;
  332.  
  333.     // Obsługa sygnałów
  334.     signal(S1, handleSig);
  335.     signal(S2, handleSig);
  336.     signal(S3, handleSig);
  337.     signal(S4, sigMessage);
  338.     // Tworzenie kolejki komunikatów
  339.     queue = msg_utworz();
  340.     // Zapisanie pidów pozostałych procesów
  341.     wymiana_pidami(&queue);
  342.  
  343.     if(i == 1) proces1();
  344.     else if(i == 2) proces2();
  345.     else if(i == 3) proces3();
  346.  
  347.     exit(0);
  348. }
  349.  
  350. int main()
  351. {
  352.     // Tworzymy 3 potoki dzięki którym będziemy wysyłać
  353.     // numery odebranych sygnałów
  354.     pipe(fd_pipe1);
  355.     pipe(fd_pipe2);
  356.     pipe(fd_pipe3);
  357.  
  358.     if(fork() == 0)
  359.         proces(1);
  360.     else if(fork() == 0)
  361.         proces(2);
  362.     else if(fork() == 0)
  363.         proces(3);
  364.  
  365.     // Czekamy aż procesy zakończą swoją pracę
  366.     wait(NULL);
  367.     wait(NULL);
  368.     wait(NULL);
  369.     return 0;
  370. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement