Advertisement
KsaneK

Projekt Systemy Operacyjne

Jan 19th, 2018
140
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 11.09 KB | None | 0 0
  1. #include <sys/types.h>
  2. #include <sys/ipc.h>
  3. #include <sys/sem.h>
  4. #include <sys/shm.h>
  5. #include <sys/msg.h>
  6. #include <stdlib.h>
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <fcntl.h>
  10. #include <unistd.h>
  11. #include <signal.h>
  12.  
  13. int process_num;
  14. int pids[2];
  15. int semid1;
  16. int semid2;
  17. int semid3;
  18. int semid4;
  19. int semid5;
  20. int semid6;
  21. int queue;
  22. char* shm;
  23. int shmid;
  24.  
  25. /* --------------------------------------- */
  26. /*            Funkcje semaforów            */
  27. /* --------------------------------------- */
  28.  
  29. int sem_utworz(int keynb){
  30.     // Generowanie klucza
  31.     key_t semkey = ftok(".", keynb);
  32.     // Tworzenie semafora
  33.     int semid = semget(semkey, 1, IPC_CREAT | 0666);
  34.     // Zwracanie id semafora
  35.     return semid;
  36. }
  37. void sem_usun(int semid){
  38.     // Usuwanie semafora
  39.     semctl(semid, 0, IPC_RMID);
  40. }
  41. void sem_podnies(int semid){
  42.     // Struktura operacji na semaforze
  43.     struct sembuf podnies = { 0, 1, 0 };
  44.     // Podnoszenie semafora o 1
  45.     semop(semid, &podnies, 1);
  46. }
  47. void sem_opusc(int semid){
  48.     // Struktura operacji na semaforze
  49.     struct sembuf opusc = { 0, -1, 0 };
  50.     // Opuszczanie semafora o 1
  51.     semop(semid, &opusc, 1);
  52. }
  53.  
  54. /* --------------------------------------- */
  55. /* Struktura i funkcje kolejki komunikatów */
  56. /* --------------------------------------- */
  57.  
  58. struct message {
  59.     // Typ wiadomości (adresowanie do danego procesu)
  60.     long type;
  61.     // Przesyłany numer sygnału
  62.     int signum;
  63. };
  64.  
  65. int msg_utworz()
  66. {
  67.     // Generowanie klucza
  68.     int key = ftok(".", 100);
  69.     // Tworzenie kolejki komunikatów
  70.     int queue = msgget(key, IPC_CREAT | 0666);
  71.     // Zwracanie id kolejki komunikatów
  72.     return queue;
  73. }
  74.  
  75. int msg_usun(int queue)
  76. {
  77.     // Usuwanie kolejki komunikatów
  78.     msgctl(queue, IPC_RMID, NULL);
  79. }
  80.  
  81. /* --------------------------------------- */
  82. /*    Funkcje dla pamięci współdzielonej   */
  83. /* --------------------------------------- */
  84.  
  85. int shm_utworz(char **shm){
  86.     // Tworzenie klucza
  87.     key_t shmkey = ftok(".", 200);
  88.     // Tworzenie pamięci współdzielonej
  89.     int shmid = shmget(shmkey, 100, IPC_CREAT | 0666);
  90.     // Podłączanie pamięci współdzielonej
  91.     *shm = shmat(shmid, NULL, 0);
  92.     // Zwracanie id pamięci współdzielonej
  93.     return shmid;
  94. }
  95.  
  96. void shm_usun(char **shm, int shmid){
  97.     // Odłączanie pamięci współdzielonej
  98.     shmdt(shm);
  99.     // Nullowanie wskaźnika na pamięć
  100.     shm = NULL;
  101.     // Usuwanie pamięci
  102.     shmctl(shmid, IPC_RMID, NULL);
  103. }
  104.  
  105. void czytaj(char* shm, char* data, size_t size){
  106.     // Kopiowanie zawartości shm do bufora
  107.     memcpy(data, shm, size);
  108. }
  109.  
  110. void pisz(char* shm, char* data, size_t size){
  111.     // Kopiowanie zawartości bufora do shm
  112.     memcpy(shm, data, size);
  113. }
  114.  
  115. /* --------------------------------------- */
  116. /*            Obsługa sygnałów             */
  117. /* --------------------------------------- */
  118.  
  119. void killProcess()
  120. {
  121.     fprintf(stderr, "KILL %d\n", process_num);
  122.     if(process_num == 2)
  123.     {
  124.         unlink("plik_komunikacji");
  125.         shmdt(&shm);
  126.         sem_usun(semid1);
  127.         sem_usun(semid2);
  128.     }
  129.     else if(process_num == 3)
  130.     {
  131.         shm_usun(&shm, shmid);
  132.         sem_usun(semid3);
  133.         sem_usun(semid4);
  134.         msg_usun(queue);
  135.     }
  136.     exit(0);
  137. }
  138.  
  139. void stopProcess()
  140. {
  141.     fprintf(stderr, "STOP %d\n", process_num);
  142.     sigset_t mask;
  143.     sigfillset(&mask);
  144.     sigdelset(&mask, SIGCONT);
  145.     sigdelset(&mask, SIGUSR1);
  146.     sigsuspend(&mask);
  147. }
  148.  
  149. void resumeProcess()
  150. {
  151.     fprintf(stderr, "RESUME %d\n", process_num);
  152. }
  153.  
  154. void sigAction(int signum)
  155. {
  156.     switch(signum)
  157.     {
  158.         case SIGINT:
  159.         {
  160.             killProcess();
  161.             break;
  162.         }
  163.         case SIGUSR2:
  164.         {
  165.             stopProcess();
  166.             break;
  167.         }
  168.         case SIGCONT:
  169.         {
  170.             resumeProcess();
  171.             break;
  172.         }
  173.     }
  174. }
  175.  
  176. void handleSig(int signum)
  177. {
  178.     int i = 1;
  179.     struct message m;
  180.     m.signum = signum;
  181.     for(i; i < 4; i++)
  182.     {
  183.         if(i != process_num)
  184.         {
  185.             m.type = i;
  186.             msgsnd(queue, &m, sizeof(m), IPC_NOWAIT);
  187.         }
  188.     }
  189.  
  190.     kill(pids[0], SIGUSR1);
  191.     kill(pids[1], SIGUSR1);
  192.     sigAction(signum);
  193. }
  194.  
  195. void sigMessage(int signum)
  196. {
  197.     struct message m;
  198.     msgrcv(queue, &m, sizeof(m), process_num, 0);
  199.     sigAction(m.signum);
  200. }
  201.  
  202. /* --------------------------------------- */
  203. /*                Proces 1                 */
  204. /* Odczytuje dane ze standardowego wejścia */
  205. /* i przekazuje je w niezmienionej formie  */
  206. /*          do procesu numer 2             */
  207. /* --------------------------------------- */
  208.  
  209. void proces1()
  210. {
  211.     process_num = 1;
  212.     // Sygnał do zakończenia pracy programu
  213.     signal(SIGINT, handleSig);
  214.     signal(SIGCONT, handleSig);
  215.     signal(SIGUSR2, handleSig);
  216.     signal(SIGUSR1, sigMessage);
  217.     // Tworzenie semaforów i kolejki komunikatów
  218.     semid1 = sem_utworz(0);
  219.     semid2 = sem_utworz(1);
  220.     queue = msg_utworz();
  221.  
  222.     // Tworzenie wiadomości i wysłanie swojego pida pozostałym procesom
  223.     struct message m;
  224.     m.type = 2;
  225.     m.signum = getpid();
  226.     msgsnd(queue, &m, sizeof(m), IPC_NOWAIT);
  227.     m.type = 3;
  228.     msgsnd(queue, &m, sizeof(m), IPC_NOWAIT);
  229.  
  230.     // Odbranie pidów pozostałych procesów
  231.     msgrcv(queue, &m, sizeof(m), 1, 0);
  232.     pids[0] = m.signum;
  233.     msgrcv(queue, &m, sizeof(m), 1, 0);
  234.     pids[1] = m.signum;
  235.  
  236.     // Bufor dla danych
  237.     char bufor[101];
  238.  
  239.     // Ilość odczytanych bajtów z stdina
  240.     ssize_t bytes_read;
  241.  
  242.     // Otwieranie pliku do komunikacji
  243.     int fd = open("plik_komunikacji", O_WRONLY, 0666);
  244.  
  245.     // Dopóki ze standardowego wejścia odczytujemy więcej niż 0 bajtów
  246.     while((bytes_read = read(STDIN_FILENO, bufor+1, 100)) > 0)
  247.     {
  248.         // Opuszczamy semafor 1
  249.         sem_opusc(semid1);
  250.         // W pierwszym bajcie zapisujemy ilość odczytanych bajtów z stdin
  251.         bufor[0] = bytes_read;
  252.         // Zapisujemy ilość bajtów i odczytane dane do pliku
  253.         write(fd, bufor, bytes_read+1);
  254.         // Przechodzimy na początek pliku
  255.         lseek(fd, 0, SEEK_SET);
  256.         // Podnosimy semafor 2 (pozwalamy drugiemu procesowy odczytać dane)
  257.         sem_podnies(semid2);
  258.     }
  259.     // Koniec danych, zapisujemy w pliku 0 jako ilość bajtów odczytanych
  260.     // Drugi proces po odczytaniu zera zakończy swoje działanie
  261.     sem_opusc(semid1);
  262.     write(fd,"\0", 1);
  263.     sem_podnies(semid2);
  264.  
  265.     // Zamykamy deskryptor pliku
  266.     close(fd);
  267.  
  268.     // Proces kończy swoje działanie
  269.     exit(0);
  270. }
  271.  
  272. /* --------------------------------------- */
  273. /*                Proces 2                 */
  274. /*  Pobiera dane przesłane przez pierwszy  */
  275. /*  proces, wyświetla liczbę odczytanych   */
  276. /*   bajtów i przesyła dane do procesu 3   */
  277. /* --------------------------------------- */
  278.  
  279. void proces2()
  280. {
  281.     process_num = 2;
  282.     // Sygnał do zakończenia pracy programu
  283.     signal(SIGINT, handleSig);
  284.     signal(SIGCONT, handleSig);
  285.     signal(SIGUSR2, handleSig);
  286.     signal(SIGUSR1, sigMessage);
  287.     // Tworzenie semaforów i kolejki komunikatów
  288.     semid1 = sem_utworz(0);
  289.     semid2 = sem_utworz(1);
  290.     semid3 = sem_utworz(2);
  291.     semid4 = sem_utworz(3);
  292.     queue = msg_utworz();
  293.  
  294.     // Tworzenie pamięci współdzielonej
  295.     shm_utworz(&shm);
  296.  
  297.     // Tworzenie wiadomości i wysłanie swojego pida pozostałym procesom
  298.     struct message m;
  299.     m.type = 1;
  300.     m.signum = getpid();
  301.     msgsnd(queue, &m, sizeof(m), IPC_NOWAIT);
  302.     m.type = 3;
  303.     msgsnd(queue, &m, sizeof(m), IPC_NOWAIT);
  304.  
  305.     // Odbranie pidów pozostałych procesów
  306.     msgrcv(queue, &m, sizeof(m), 2, 0);
  307.     pids[0] = m.signum;
  308.     msgrcv(queue, &m, sizeof(m), 2, 0);
  309.     pids[1] = m.signum;
  310.     // Bufor dla danych
  311.     char bufor[102];
  312.     bufor[101] = 0;
  313.  
  314.     // Otwieranie pliku w trybie do odczytu
  315.     int fd = open("plik_komunikacji", O_RDONLY);
  316.     int bytes_read;
  317.  
  318.     // Podnosimy semafor 1 (proces 1 może zacząć pracę)
  319.     sem_podnies(semid1);
  320.     while(1)
  321.     {
  322.         // Opuszczamy semafor 2
  323.         sem_opusc(semid2);
  324.         // Czytamy 100 bajtów z pliku
  325.         read(fd, bufor, 101);
  326.         // Pierwszy bajt mówi nam ile bajtów z stdin zostało przesłane
  327.         bytes_read = bufor[0];
  328.         // Jeżeli zostało odczytane 0 bajtów to wychodzimy z pętli
  329.         if(bytes_read == 0) break;
  330.         // Jeżeli odczytano mniej niż 99 bajtów to dodajemy znak pusty
  331.         if(bytes_read < 100) bufor[bytes_read+1] = 0;
  332.         // Wyświetlamy liczbę odczytanych bajtów
  333.         fprintf(stderr, "Odczytano %d bajtow\n", (int)bytes_read);
  334.         // Przechodzimy na początek pliku
  335.         lseek(fd, 0 , SEEK_SET);
  336.         // Podnosimy semafor 1 (proces 1 zacznie zapisywać kolejne dane)
  337.         sem_podnies(semid1);
  338.         // Opuszczamy semafor 3
  339.         sem_opusc(semid3);
  340.         // Zapisujemy bufor do pamięci współdzielonej
  341.         pisz(shm, bufor, bytes_read + 1);
  342.         // Podnosimy semafor 4 (proces 3 zacznie odczytywać dane z shm)
  343.         sem_podnies(semid4);
  344.     }
  345.  
  346.     // Zapisujemy do pamięci współdzielonej pierwszy bajt jako 0
  347.     // dzięki temu trzeci proces wie, kiedy zakończyć pracę
  348.     sem_opusc(semid3);
  349.     pisz(shm, "\0", 1);
  350.     sem_podnies(semid4);
  351.  
  352.     // Zamykamy deskryptor pliku i usuwamy plik
  353.     close(fd);
  354.     unlink("plik_komunikacji");
  355.  
  356.     // Odłączamy pamięć współdzieloną
  357.     shmdt(&shm);
  358.  
  359.     // Usuwamy semafory, aby nie zostały w systemie
  360.     sem_usun(semid1);
  361.     sem_usun(semid2);
  362.  
  363.     // Kończymy pracę procesu
  364.     exit(0);
  365. }
  366.  
  367. /* ---------------------------------------- */
  368. /*                Proces 3                  */
  369. /*    Pobiera dane przesłane przez drugi    */
  370. /*   proces i wyświetla je na standardowym  */
  371. /*                 wyjściu                  */
  372. /* ---------------------------------------- */
  373.  
  374. void proces3()
  375. {
  376.     process_num = 3;
  377.     // Sygnały
  378.     signal(SIGINT, handleSig);
  379.     signal(SIGCONT, handleSig);
  380.     signal(SIGUSR2, handleSig);
  381.     signal(SIGUSR1, sigMessage);
  382.     // Tworzenie semaforów i kolejki komunikatów
  383.     semid3 = sem_utworz(2);
  384.     semid4 = sem_utworz(3);
  385.     queue = msg_utworz();
  386.  
  387.     // Tworzenie pamięci współdzielonej
  388.     shmid = shm_utworz(&shm);
  389.  
  390.     // Tworzenie wiadomości i wysłanie swojego pida pozostałym procesom
  391.     struct message m;
  392.     m.type = 1;
  393.     m.signum = getpid();
  394.     msgsnd(queue, &m, sizeof(m), IPC_NOWAIT);
  395.     m.type = 2;
  396.     msgsnd(queue, &m, sizeof(m), IPC_NOWAIT);
  397.  
  398.     // Odbranie pidów pozostałych procesów
  399.     msgrcv(queue, &m, sizeof(m), 3, 0);
  400.     pids[0] = m.signum;
  401.     msgrcv(queue, &m, sizeof(m), 3, 0);
  402.     pids[1] = m.signum;
  403.  
  404.     // Tworzenie bufora dla danych
  405.     char bufor[102];
  406.     bufor[101] = 0;
  407.  
  408.     // Zmienna w której będzie przechowywana ilość odczytanych bajtów
  409.     int bytes_read;
  410.  
  411.     // Podnosimy semafor 3, aby drugi proces mógł zapisać dane
  412.     sem_podnies(semid3);
  413.     while(1)
  414.     {
  415.         // Opuszczamy semafor 1
  416.         sem_opusc(semid4);
  417.         // Odczytujemy 100 bajtów z pamięci współdzielonej
  418.         czytaj(shm, bufor, 101);
  419.         // Ilość odczytanych bajtów
  420.         bytes_read = bufor[0];
  421.         // Jeżeli odczytano 0 bajtów wychodzimy z pętli
  422.         if(bytes_read == 0) break;
  423.         // Jeżeli odczytało mniej niż 100 bajtów właściwych danych
  424.         // To dodajemy pusty znak na końcu
  425.         if(bytes_read < 100) bufor[bytes_read + 1] = 0;
  426.         // Przekazujemy dane na standardowy strumień wyjściowy
  427.         write(STDOUT_FILENO, bufor+1, bytes_read);
  428.         // Podnosimy semafor 3
  429.         // (pozwalamy drugiemu procesowi na zapisanie kolejnych danych)
  430.         sem_podnies(semid3);
  431.     }
  432.  
  433.     // Usuwanie pamięci współdzielonej
  434.     shm_usun(&shm, shmid);
  435.  
  436.     // Usuwanie semaforów
  437.     sem_usun(semid3);
  438.     sem_usun(semid4);
  439.  
  440.     // Usuwamy kolejkę komunikatów
  441.     msg_usun(queue);
  442.  
  443.     // Kończymy pracę procesu
  444.     exit(0);
  445. }
  446.  
  447. int main()
  448. {
  449.     int fd = open("plik_komunikacji", O_CREAT | O_WRONLY, 0666);
  450.     close(fd);
  451.     if(fork())
  452.         proces1();
  453.     else if(fork())
  454.         proces2();
  455.     else if(fork())
  456.         proces3();
  457.     return 0;
  458. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement