Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/sem.h>
- #include <sys/shm.h>
- #include <sys/msg.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <signal.h>
- int process_num;
- int pids[2];
- int semid1;
- int semid2;
- int semid3;
- int semid4;
- int semid5;
- int semid6;
- int queue;
- char* shm;
- int shmid;
- /* --------------------------------------- */
- /* Funkcje semaforów */
- /* --------------------------------------- */
- int sem_utworz(int keynb){
- // Generowanie klucza
- key_t semkey = ftok(".", keynb);
- // Tworzenie semafora
- int semid = semget(semkey, 1, IPC_CREAT | 0666);
- // Zwracanie id semafora
- return semid;
- }
- void sem_usun(int semid){
- // Usuwanie semafora
- semctl(semid, 0, IPC_RMID);
- }
- void sem_podnies(int semid){
- // Struktura operacji na semaforze
- struct sembuf podnies = { 0, 1, 0 };
- // Podnoszenie semafora o 1
- semop(semid, &podnies, 1);
- }
- void sem_opusc(int semid){
- // Struktura operacji na semaforze
- struct sembuf opusc = { 0, -1, 0 };
- // Opuszczanie semafora o 1
- semop(semid, &opusc, 1);
- }
- /* --------------------------------------- */
- /* Struktura i funkcje kolejki komunikatów */
- /* --------------------------------------- */
- struct message {
- // Typ wiadomości (adresowanie do danego procesu)
- long type;
- // Przesyłany numer sygnału
- int signum;
- };
- int msg_utworz()
- {
- // Generowanie klucza
- int key = ftok(".", 100);
- // Tworzenie kolejki komunikatów
- int queue = msgget(key, IPC_CREAT | 0666);
- // Zwracanie id kolejki komunikatów
- return queue;
- }
- int msg_usun(int queue)
- {
- // Usuwanie kolejki komunikatów
- msgctl(queue, IPC_RMID, NULL);
- }
- /* --------------------------------------- */
- /* Funkcje dla pamięci współdzielonej */
- /* --------------------------------------- */
- int shm_utworz(char **shm){
- // Tworzenie klucza
- key_t shmkey = ftok(".", 200);
- // Tworzenie pamięci współdzielonej
- int shmid = shmget(shmkey, 100, IPC_CREAT | 0666);
- // Podłączanie pamięci współdzielonej
- *shm = shmat(shmid, NULL, 0);
- // Zwracanie id pamięci współdzielonej
- return shmid;
- }
- void shm_usun(char **shm, int shmid){
- // Odłączanie pamięci współdzielonej
- shmdt(shm);
- // Nullowanie wskaźnika na pamięć
- shm = NULL;
- // Usuwanie pamięci
- shmctl(shmid, IPC_RMID, NULL);
- }
- void czytaj(char* shm, char* data, size_t size){
- // Kopiowanie zawartości shm do bufora
- memcpy(data, shm, size);
- }
- void pisz(char* shm, char* data, size_t size){
- // Kopiowanie zawartości bufora do shm
- memcpy(shm, data, size);
- }
- /* --------------------------------------- */
- /* Obsługa sygnałów */
- /* --------------------------------------- */
- void killProcess()
- {
- fprintf(stderr, "KILL %d\n", process_num);
- if(process_num == 2)
- {
- unlink("plik_komunikacji");
- shmdt(&shm);
- sem_usun(semid1);
- sem_usun(semid2);
- }
- else if(process_num == 3)
- {
- shm_usun(&shm, shmid);
- sem_usun(semid3);
- sem_usun(semid4);
- msg_usun(queue);
- }
- exit(0);
- }
- void stopProcess()
- {
- fprintf(stderr, "STOP %d\n", process_num);
- sigset_t mask;
- sigfillset(&mask);
- sigdelset(&mask, SIGCONT);
- sigdelset(&mask, SIGUSR1);
- sigsuspend(&mask);
- }
- void resumeProcess()
- {
- fprintf(stderr, "RESUME %d\n", process_num);
- }
- void sigAction(int signum)
- {
- switch(signum)
- {
- case SIGINT:
- {
- killProcess();
- break;
- }
- case SIGUSR2:
- {
- stopProcess();
- break;
- }
- case SIGCONT:
- {
- resumeProcess();
- break;
- }
- }
- }
- void handleSig(int signum)
- {
- int i = 1;
- struct message m;
- m.signum = signum;
- for(i; i < 4; i++)
- {
- if(i != process_num)
- {
- m.type = i;
- msgsnd(queue, &m, sizeof(m), IPC_NOWAIT);
- }
- }
- kill(pids[0], SIGUSR1);
- kill(pids[1], SIGUSR1);
- sigAction(signum);
- }
- void sigMessage(int signum)
- {
- struct message m;
- msgrcv(queue, &m, sizeof(m), process_num, 0);
- sigAction(m.signum);
- }
- /* --------------------------------------- */
- /* Proces 1 */
- /* Odczytuje dane ze standardowego wejścia */
- /* i przekazuje je w niezmienionej formie */
- /* do procesu numer 2 */
- /* --------------------------------------- */
- void proces1()
- {
- process_num = 1;
- // Sygnał do zakończenia pracy programu
- signal(SIGINT, handleSig);
- signal(SIGCONT, handleSig);
- signal(SIGUSR2, handleSig);
- signal(SIGUSR1, sigMessage);
- // Tworzenie semaforów i kolejki komunikatów
- semid1 = sem_utworz(0);
- semid2 = sem_utworz(1);
- queue = msg_utworz();
- // Tworzenie wiadomości i wysłanie swojego pida pozostałym procesom
- struct message m;
- m.type = 2;
- m.signum = getpid();
- msgsnd(queue, &m, sizeof(m), IPC_NOWAIT);
- m.type = 3;
- msgsnd(queue, &m, sizeof(m), IPC_NOWAIT);
- // Odbranie pidów pozostałych procesów
- msgrcv(queue, &m, sizeof(m), 1, 0);
- pids[0] = m.signum;
- msgrcv(queue, &m, sizeof(m), 1, 0);
- pids[1] = m.signum;
- // Bufor dla danych
- char bufor[101];
- // Ilość odczytanych bajtów z stdina
- ssize_t bytes_read;
- // Otwieranie pliku do komunikacji
- int fd = open("plik_komunikacji", O_WRONLY, 0666);
- // Dopóki ze standardowego wejścia odczytujemy więcej niż 0 bajtów
- while((bytes_read = read(STDIN_FILENO, bufor+1, 100)) > 0)
- {
- // Opuszczamy semafor 1
- sem_opusc(semid1);
- // W pierwszym bajcie zapisujemy ilość odczytanych bajtów z stdin
- bufor[0] = bytes_read;
- // Zapisujemy ilość bajtów i odczytane dane do pliku
- write(fd, bufor, bytes_read+1);
- // Przechodzimy na początek pliku
- lseek(fd, 0, SEEK_SET);
- // Podnosimy semafor 2 (pozwalamy drugiemu procesowy odczytać dane)
- sem_podnies(semid2);
- }
- // Koniec danych, zapisujemy w pliku 0 jako ilość bajtów odczytanych
- // Drugi proces po odczytaniu zera zakończy swoje działanie
- sem_opusc(semid1);
- write(fd,"\0", 1);
- sem_podnies(semid2);
- // Zamykamy deskryptor pliku
- close(fd);
- // Proces kończy swoje działanie
- exit(0);
- }
- /* --------------------------------------- */
- /* Proces 2 */
- /* Pobiera dane przesłane przez pierwszy */
- /* proces, wyświetla liczbę odczytanych */
- /* bajtów i przesyła dane do procesu 3 */
- /* --------------------------------------- */
- void proces2()
- {
- process_num = 2;
- // Sygnał do zakończenia pracy programu
- signal(SIGINT, handleSig);
- signal(SIGCONT, handleSig);
- signal(SIGUSR2, handleSig);
- signal(SIGUSR1, sigMessage);
- // Tworzenie semaforów i kolejki komunikatów
- semid1 = sem_utworz(0);
- semid2 = sem_utworz(1);
- semid3 = sem_utworz(2);
- semid4 = sem_utworz(3);
- queue = msg_utworz();
- // Tworzenie pamięci współdzielonej
- shm_utworz(&shm);
- // Tworzenie wiadomości i wysłanie swojego pida pozostałym procesom
- struct message m;
- m.type = 1;
- m.signum = getpid();
- msgsnd(queue, &m, sizeof(m), IPC_NOWAIT);
- m.type = 3;
- msgsnd(queue, &m, sizeof(m), IPC_NOWAIT);
- // Odbranie pidów pozostałych procesów
- msgrcv(queue, &m, sizeof(m), 2, 0);
- pids[0] = m.signum;
- msgrcv(queue, &m, sizeof(m), 2, 0);
- pids[1] = m.signum;
- // Bufor dla danych
- char bufor[102];
- bufor[101] = 0;
- // Otwieranie pliku w trybie do odczytu
- int fd = open("plik_komunikacji", O_RDONLY);
- int bytes_read;
- // Podnosimy semafor 1 (proces 1 może zacząć pracę)
- sem_podnies(semid1);
- while(1)
- {
- // Opuszczamy semafor 2
- sem_opusc(semid2);
- // Czytamy 100 bajtów z pliku
- read(fd, bufor, 101);
- // Pierwszy bajt mówi nam ile bajtów z stdin zostało przesłane
- bytes_read = bufor[0];
- // Jeżeli zostało odczytane 0 bajtów to wychodzimy z pętli
- if(bytes_read == 0) break;
- // Jeżeli odczytano mniej niż 99 bajtów to dodajemy znak pusty
- if(bytes_read < 100) bufor[bytes_read+1] = 0;
- // Wyświetlamy liczbę odczytanych bajtów
- fprintf(stderr, "Odczytano %d bajtow\n", (int)bytes_read);
- // Przechodzimy na początek pliku
- lseek(fd, 0 , SEEK_SET);
- // Podnosimy semafor 1 (proces 1 zacznie zapisywać kolejne dane)
- sem_podnies(semid1);
- // Opuszczamy semafor 3
- sem_opusc(semid3);
- // Zapisujemy bufor do pamięci współdzielonej
- pisz(shm, bufor, bytes_read + 1);
- // Podnosimy semafor 4 (proces 3 zacznie odczytywać dane z shm)
- sem_podnies(semid4);
- }
- // Zapisujemy do pamięci współdzielonej pierwszy bajt jako 0
- // dzięki temu trzeci proces wie, kiedy zakończyć pracę
- sem_opusc(semid3);
- pisz(shm, "\0", 1);
- sem_podnies(semid4);
- // Zamykamy deskryptor pliku i usuwamy plik
- close(fd);
- unlink("plik_komunikacji");
- // Odłączamy pamięć współdzieloną
- shmdt(&shm);
- // Usuwamy semafory, aby nie zostały w systemie
- sem_usun(semid1);
- sem_usun(semid2);
- // Kończymy pracę procesu
- exit(0);
- }
- /* ---------------------------------------- */
- /* Proces 3 */
- /* Pobiera dane przesłane przez drugi */
- /* proces i wyświetla je na standardowym */
- /* wyjściu */
- /* ---------------------------------------- */
- void proces3()
- {
- process_num = 3;
- // Sygnały
- signal(SIGINT, handleSig);
- signal(SIGCONT, handleSig);
- signal(SIGUSR2, handleSig);
- signal(SIGUSR1, sigMessage);
- // Tworzenie semaforów i kolejki komunikatów
- semid3 = sem_utworz(2);
- semid4 = sem_utworz(3);
- queue = msg_utworz();
- // Tworzenie pamięci współdzielonej
- shmid = shm_utworz(&shm);
- // Tworzenie wiadomości i wysłanie swojego pida pozostałym procesom
- struct message m;
- m.type = 1;
- m.signum = getpid();
- msgsnd(queue, &m, sizeof(m), IPC_NOWAIT);
- m.type = 2;
- msgsnd(queue, &m, sizeof(m), IPC_NOWAIT);
- // Odbranie pidów pozostałych procesów
- msgrcv(queue, &m, sizeof(m), 3, 0);
- pids[0] = m.signum;
- msgrcv(queue, &m, sizeof(m), 3, 0);
- pids[1] = m.signum;
- // Tworzenie bufora dla danych
- char bufor[102];
- bufor[101] = 0;
- // Zmienna w której będzie przechowywana ilość odczytanych bajtów
- int bytes_read;
- // Podnosimy semafor 3, aby drugi proces mógł zapisać dane
- sem_podnies(semid3);
- while(1)
- {
- // Opuszczamy semafor 1
- sem_opusc(semid4);
- // Odczytujemy 100 bajtów z pamięci współdzielonej
- czytaj(shm, bufor, 101);
- // Ilość odczytanych bajtów
- bytes_read = bufor[0];
- // Jeżeli odczytano 0 bajtów wychodzimy z pętli
- if(bytes_read == 0) break;
- // Jeżeli odczytało mniej niż 100 bajtów właściwych danych
- // To dodajemy pusty znak na końcu
- if(bytes_read < 100) bufor[bytes_read + 1] = 0;
- // Przekazujemy dane na standardowy strumień wyjściowy
- write(STDOUT_FILENO, bufor+1, bytes_read);
- // Podnosimy semafor 3
- // (pozwalamy drugiemu procesowi na zapisanie kolejnych danych)
- sem_podnies(semid3);
- }
- // Usuwanie pamięci współdzielonej
- shm_usun(&shm, shmid);
- // Usuwanie semaforów
- sem_usun(semid3);
- sem_usun(semid4);
- // Usuwamy kolejkę komunikatów
- msg_usun(queue);
- // Kończymy pracę procesu
- exit(0);
- }
- int main()
- {
- int fd = open("plik_komunikacji", O_CREAT | O_WRONLY, 0666);
- close(fd);
- if(fork())
- proces1();
- else if(fork())
- proces2();
- else if(fork())
- proces3();
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement