Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "stdio.h"
- #include "fcntl.h"
- #include "unistd.h"
- #include "stdlib.h"
- #include "errno.h"
- #include "wait.h"
- #include "signal.h"
- #include "string.h"
- #include "sys/errno.h"
- #include "sys/ipc.h"
- #include "sys/shm.h"
- #include "sys/sem.h"
- #define ROZPIAR_BUFORA 200
- /* Ideks łącza, którym proces 1 przesyła dane do procesu 2 */
- #define PIPE1_2 0
- /* Ideks łącza, którym proces 2 przesyła dane do procesu 3 */
- #define PIPE2_3 1
- /* Ideks FD przeznaczanego do odczytu w tablicy "zwracanej" przez funkcję pipe.*/
- #define FD_DO_ODCZYTU 0
- /* Ideks FD przeznaczanego do zapisu w tablicy "zwracanej" przez funkcję pipe.*/
- #define FD_DO_ZAPISU 1
- /* Definiujemy jakie sygnały używany w roli sygnałów s1-s4 z zadania */
- #define S1 SIGINT
- #define S2 SIGUSR1
- #define S3 SIGCONT
- #define S4 SIGUSR2
- /* Bufor operacji semaforowych */
- static struct sembuf buf;
- /* Tablica pomocnicza przy konwersji wartości bajtów na zapis heksadecymalny */
- char pomocniczaHEX[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
- /* Zamykanie deksryptora pliku ponawiające tą czynność w momencie otrzymania sygnału */
- void zamknijFd(int fd){
- int rc;
- ponow:
- rc = close(fd);
- if(rc == -1 ) {
- if(errno == EINTR)
- goto ponow;
- else
- {
- perror("clode fd");
- exit(1);
- }
- }
- }
- /* Klucz szyfrowania przy użyciu funkcji XOR*/
- #define KLUCZ 1
- /* Podnisznie semafora o n z ponawianiem gdy operacja się nie uda */
- void podniesN(int semid, int semnum, int n)
- {
- buf.sem_num = semnum;
- buf.sem_op = n;
- buf.sem_flg = 0;
- ponow:
- if (semop(semid, &buf, 1) == -1)
- {
- if(errno == EINTR)
- goto ponow;
- else {
- perror("semsignal");
- exit(1);
- }
- }
- }
- /* Pełni funkcję analogiczną do podniesN tylko dla opuszczania a nie podnoszenia seamfora */
- void opuscN(int semid, int semnum, int n)
- {
- buf.sem_num = semnum;
- buf.sem_op = -n;
- buf.sem_flg = 0;
- ponow:
- if (semop(semid, &buf, 1) == -1)
- {
- if(errno == EINTR)
- goto ponow;
- else {
- perror("semwait");
- exit(1);
- }
- }
- }
- /* Podnoszenie semafora(o 1) i ponawianie tej operacji w przypadku gdy przerwie ją sygnal w
- każdym przeciwnym wypadku wyświtlamy błąd */
- void podnies(int semid, int semnum)
- {
- podniesN(semid, semnum, 1);
- }
- /* Opuszczanie semafora z rekacją na sygnał jak w funkcjach powyżej*/
- void opusc(int semid, int semnum)
- {
- opuscN(semid, semnum, -1);
- }
- /* Zamyka podane jako agrmunet łącza nienazwane */
- void zamknijPipy(int fds[2][2])
- {
- zamknijFd(fds[0][0]);
- zamknijFd(fds[0][1]);
- zamknijFd(fds[1][0]);
- zamknijFd(fds[1][1]);
- }
- /* Funckja realizuje zadnia procesu 1 z polecenia */
- void proces1();
- /* Funkcja realizuje zadania procesu 2 z polecenie */
- void proces2();
- /* Funkcja realizuje zadania procesu 3 z polecenia */
- void proces3();
- int fifo12[2], fifo23[2];
- /* Procedura obsługi sygnałów S1-S3*/
- void s123Obsluga(int signum);
- /* Procedura obsługi sygnału S4*/
- void s4Oblusga();
- /* Funkcja realizująca implementację prostego szyfrowania przy użyciu szyfru cesara */
- size_t zaszyfrujCesar(char* wiadomosc, char klucz, size_t rozmiar);
- /* Konwertuje ciąg wejście na zapis jego kolejnych bajtów postaci heksadecymalnej, bajty oddzeilone spacjami
- UWAGA wyjscie musi miec rozmiar minimum rozmiarWejscia*3+1*/
- size_t konwersjaHex(char* wejscie, char* wyjscie, int rozmiarWejscia);
- /* Zapisuje do łącza nienazwanego standardową wiadomocs dla tego programu tj dlugosc ciagu znakow jako typ int
- a nastepnie sam ciąg nie zakończony \0 z uwagi na to, że dane mogą zawierać bajty niedrukwoalne w tym \0, więc
- nie mogę na nim polegać w celu określenia długości ciągu. Funkcja ponawia trasfer jeśli zostanie on przerwany
- przez sygnał */
- void zapiszStandardowaWiadomosc(int fd, char* wejscie, int rozmiar);
- /* Odczytuje wiadomość w postaci opisanej przy funkcji zapiszStandardowaWiadomosc. Reakcja na sygnały analogiczna
- jak wyżej*/
- void odczytajStandardowaWiadomosc(int fd, char* wyjscie, int* rozmiarWyjscia, int rozmiar);
- /* Id pamieci dizelonej przewującej kolejno pidy procesów P1-P3 a następnie stan programu, wartość używaną w celu
- przekazywania między procesami informacji o komendzie operatora */
- int shmid;
- /* Zestaw semaforow do synchornizowania dostępu do opisanej wyzej pamięci */
- int semid;
- /* Pod ten adres przyłączona jest tablica PIDów*/
- int *pidy;
- /* Pod ten adres przyłączamy komunikat o żądanym przez opertora działaniu */
- int *komunikat;
- /* Opis zastosowania kolenych semaforów w zestawie */
- #define S_USTALONO_SHM 0
- #define S_ZAPISZ_KOMUNIKAT 1
- #define S_P1_ODCZYTAJ_KOMUNIKAT 2
- #define S_P2_ODCZYTAJ_KOMUNIKAT 3
- #define S_P3_ODCZYTAJ_KOMUNIKAT 4
- /* Wartości dla pola komunikat w pamięci dzielonej */
- #define K_KONTYNUUJ S3
- #define K_ZATRZYMAJ S2
- #define K_ZAKONCZ S1
- /* Domyślnym stanem jest K_KONTYNUUJ czyli kontyowanie normalnej operacji
- programu */
- int stanProcesu = K_KONTYNUUJ;
- /* Maska sygnałów, na kutórej oczekują procesy, które wstrzymały komunikacje na
- rządanie operatora */
- sigset_t mask;
- int main()
- {
- /* Ignoruję sygnał sigint w procesie inicjalizującym celem tego zabiegu jest to aby jeśli w konsoli nacisniemy ctrl+Z
- sygnał ten został przekazanyc do procesów 1-3 które poprawnie zakończą pracę po czym cały program zakończy prację */
- signal(SIGINT, SIG_IGN);
- /* Tworzę maskę do oczekiwania procesów po otrzymaniu sygnału S2(Wstzymanie komunikacji)*/
- sigfillset (&mask);
- sigdelset(&mask, S1);
- sigdelset(&mask, S2);
- sigdelset(&mask, S3);
- sigdelset(&mask, S4);
- /* Przechowuje deskryptory do pipów utworzonych przez proces inicjalizujący komunikujące się procesy */
- int fifoFds[2][2];
- /* Tworze pipa do komunikacji 1->2 */
- int pid1,pid2,pid3;
- if(pipe(fifoFds[PIPE1_2]) != 0)
- {
- perror("Tworzenie fifo 1->2");
- exit(1);
- }
- /* Tworże pipa do komunikacji 2->2*/
- if(pipe(fifoFds[PIPE2_3]) != 0)
- {
- zamknijFd(fifoFds[PIPE1_2][FD_DO_ODCZYTU]);
- zamknijFd(fifoFds[PIPE1_2][FD_DO_ZAPISU]);
- perror("Tworzenie fifo 2->3");
- exit(1);
- }
- /* Tworzę zestaw semaforów do synchronizacni dostępu do pamięci dzielonej */
- semid = semget(IPC_PRIVATE, 5, 0600 | IPC_CREAT);
- if (semid == -1){
- perror("Uzyskanie identyfikatora tablicy semaforow");
- exit(1);
- }
- /* Tworzę pamięć dzieloną na pidy i komunikat */
- shmid = shmget(IPC_PRIVATE, 4*sizeof(int), 0600 |IPC_CREAT);
- if (shmid == -1){
- perror("Utworzenie segmentu pamieci wspoldzielonej");
- exit(1);
- }
- /* Ustalam wartości domyślne semaforów */
- /* Ten semafor informuje procesy 1-3, że proces inicjalizujący wypełnił już tablicę pidów
- poprawnymi wartościami */
- if (semctl(semid, S_USTALONO_SHM, SETVAL, (int)0) == -1){
- perror("Nadanie wartosci semaforowi 0");
- exit(1);
- }
- /* Następne semafory synchronizują dostęp do komunikatu w pamięci dzielonej,
- nazwy opisują role w tym dostępnie konkretnych semaforóœ */
- if (semctl(semid, S_ZAPISZ_KOMUNIKAT, SETVAL, (int)2) == -1){
- perror("Nadanie wartosci semaforowi 0");
- exit(1);
- }
- if (semctl(semid, S_P1_ODCZYTAJ_KOMUNIKAT, SETVAL, (int)0) == -1){
- perror("Nadanie wartosci semaforowi 0");
- exit(1);
- }
- if (semctl(semid, S_P2_ODCZYTAJ_KOMUNIKAT, SETVAL, (int)0) == -1){
- perror("Nadanie wartosci semaforowi 0");
- exit(1);
- }
- if (semctl(semid, S_P3_ODCZYTAJ_KOMUNIKAT, SETVAL, (int)0) == -1){
- perror("Nadanie wartosci semaforowi 0");
- exit(1);
- }
- /* Przyłączam pamięc dzieloną i ustawiam wskaźniki na odpowiednie adresy */
- pidy = (pid_t*)shmat(shmid, NULL, 0600 | IPC_CREAT);
- if (pidy == NULL){
- perror("Przylaczenie segmentu pamieci wspoldzielonej");
- exit(1);
- }
- komunikat = pidy + 3;
- /* Tworzę procesy 1-3 i uruchamiam odpowiednie funkcje wyousując w razie potrzeby informacje
- o błędach, które wsytąpiły. */
- int zwrFork = fork();
- if(zwrFork < 0)
- {
- zamknijPipy(fifoFds);
- perror("Tworzenie procesu 1");
- exit(1);
- }
- else if (zwrFork == 0)
- {
- proces1(fifoFds[PIPE1_2]);
- return 0;
- }
- else
- {
- pid1 = zwrFork;
- }
- zwrFork = fork();
- if(zwrFork < 0)
- {
- zamknijPipy(fifoFds);
- kill(pid1, SIGTERM);
- perror("Tworzenie procesu 2");
- exit(1);
- } else if (zwrFork == 0)
- {
- proces2(fifoFds[PIPE1_2], fifoFds[PIPE2_3]);
- return 0;
- }
- else
- {
- pid2 = zwrFork;
- }
- zwrFork = fork();
- if(zwrFork < 0)
- {
- zamknijPipy(fifoFds);
- kill(pid1, SIGTERM);
- kill(pid2, SIGTERM);
- perror("Tworzenie procesu 3");
- exit(1);
- } else if (zwrFork == 0)
- {
- proces3(fifoFds[PIPE2_3]);
- return 0;
- }
- else
- {
- pid3 = zwrFork;
- }
- /* Inicjalizuję zawartość pamięci dzielonej zgodnie z opisem wyżej */
- pidy[0] = pid1;
- pidy[1] = pid2;
- pidy[2] = pid3;
- *komunikat = K_KONTYNUUJ;
- /* I informuje o jej uzupełnineiu procesy P1-P3 */
- podniesN(semid, S_USTALONO_SHM, 3);
- /* Czekam na zakończonie procesów 1-3 */
- wait(0);
- wait(0);
- wait(0);
- /* Sprzątam po mechanizmach komunikacji międzyprocesowej */
- close(fifoFds[0][0]);
- close(fifoFds[0][1]);
- close(fifoFds[1][0]);
- close(fifoFds[1][1]);
- /*usuwam zestaw semaforów */
- if(semctl(semid, 0, IPC_RMID, 0) == -1)
- {
- perror("semrm");
- }
- if(shmdt(pidy) == -1) {
- perror("shmdt");
- }
- if(shmctl(shmid, IPC_RMID, 0) == -1) {
- perror("shmrm");
- }
- printf("Wszystkie procesy zakonczyly prace.\n");
- return 0;
- }
- void proces1(int fifo12[2])
- {
- /* Proces startuje i wyspisuje swój pid */
- printf("Proces 1 wystartowal %d\n", getpid());
- fflush(stdout);
- zamknijFd(fifo12[FD_DO_ODCZYTU]);
- char buforOdczytu[ROZPIAR_BUFORA];
- int ileOdczytano;
- /*Oczekujemy na zainicjowanie tablicy w shm poprawnymi wartościami przez proces inicjalizujący */
- opusc(semid, S_USTALONO_SHM);
- /* Ustawiam procedury obsługi sygnałów */
- signal(S1, s123Obsluga);
- signal(S2, s123Obsluga);
- signal(S3, s123Obsluga);
- signal(S4, s4Oblusga);
- while(1)
- {
- /*Odczytuję do bufora dane ze standardowego wejścia(jego deskryptor to 0) używając tej samej
- metody "radzenia sobie" z sygnałami jak dla łączy*/
- ponowOdczyt:
- if(((ileOdczytano=read(0, buforOdczytu, ROZPIAR_BUFORA)))== -1) {
- if(errno == EINTR) {
- goto ponowOdczyt;
- } else {
- perror("write");
- exit(1);
- }
- }
- ;
- /* I przekazuje je przez łącze nienazwane do procesu 2*/
- zapiszStandardowaWiadomosc(fifo12[FD_DO_ZAPISU],buforOdczytu, ileOdczytano);
- }
- exit(0);
- }
- void proces2(int fifo12[2], int fifo23[2])
- {
- /* Zachowanie analogiczne jak proces 1*/
- printf("Proces 2 wystartowal %d\n", getpid());
- fflush(stdout);
- zamknijFd(fifo12[FD_DO_ZAPISU]);
- zamknijFd(fifo23[FD_DO_ODCZYTU]);
- char buforOdczytu[ROZPIAR_BUFORA];
- int ileOdczytano = 0;
- opusc(semid, S_USTALONO_SHM);
- signal(S1, s123Obsluga);
- signal(S2, s123Obsluga);
- signal(S3, s123Obsluga);
- signal(S4, s4Oblusga);
- while(1)
- {
- /* Odczytuje dane od procesu 1 przez pipe */
- odczytajStandardowaWiadomosc(fifo12[FD_DO_ODCZYTU], buforOdczytu, &ileOdczytano, ROZPIAR_BUFORA);
- /* Dokonuję szyforwania przy użyciu funkcji xor zapisując pozycję klucza */
- zaszyfrujCesar(buforOdczytu, KLUCZ, ileOdczytano);
- /* I wynik tego szyfrowania przekuję do procesu przez odpowiednie łącze nienazwane */
- zapiszStandardowaWiadomosc(fifo23[FD_DO_ZAPISU],buforOdczytu, ileOdczytano);
- }
- exit(0);
- }
- void proces3(int fifo23[2])
- {
- /* Działanie analogiczzne do procesów 1 i 2 */
- zamknijFd(fifo23[FD_DO_ZAPISU]);
- printf("Proces 3 wystartowal %d\n", getpid());
- fflush(stdout);
- /* +1 na nową linie */
- char buforOdczytu[ROZPIAR_BUFORA + 1];
- int ileOdczytano;
- opusc(semid, S_USTALONO_SHM);
- signal(S1, s123Obsluga);
- signal(S2, s123Obsluga);
- signal(S3, s123Obsluga);
- signal(S4, s4Oblusga);
- while(1)
- {
- /* Odczytuje zaszyfrowane dane od procesu 2 przez pipe*/
- odczytajStandardowaWiadomosc(fifo23[FD_DO_ODCZYTU], buforOdczytu, &ileOdczytano, ROZPIAR_BUFORA);
- buforOdczytu[ileOdczytano] = '\n';
- ileOdczytano++;
- /* I wypisuję na standardowe wyjście (jego deksrptor to 1) procedura analogiczna co przy oddczycie w procesie 1*/
- ponowZapis:
- if( write(1, buforOdczytu, ileOdczytano)== -1) {
- if(errno == EINTR) {
- goto ponowZapis;
- } else {
- perror("write");
- exit(1);
- }
- }
- }
- exit(0);
- }
- size_t zaszyfrujCesar(char* wiadomosc, char klucz, size_t rozmiar)
- {
- int i;
- char ch;
- for(i = 0; i<rozmiar; i++)
- {
- ch = wiadomosc[i];
- if(ch >= 'a' && ch <= 'z'){
- ch = ch + klucz;
- if(ch > 'z'){
- ch = ch - 'z' + 'a' - 1;
- }
- wiadomosc[i] = ch;
- }
- else if(ch >= 'A' && ch <= 'Z'){
- ch = ch + klucz;
- if(ch > 'Z'){
- ch = ch - 'Z' + 'A' - 1;
- }
- wiadomosc[i] = ch;
- } else {
- ch = '_';
- }
- wiadomosc[i] = ch;
- }
- return rozmiar;
- }
- void zapiszStandardowaWiadomosc(int fd, char* wejscie, int rozmiar)
- {
- /*Zapisujemy do pipe wielkość wiadomości oraz jej treść powtarzając jeśli któryś z tych
- kroków zostanie przerwany przez sygnał */
- ponowZapis:
- if(write(fd, (char*)(&rozmiar), sizeof(int)) == -1) {
- if(errno == EINTR) {
- goto ponowZapis;
- } else {
- perror("write");
- exit(1);
- }
- }
- ponowZapis2:
- if( write(fd, wejscie, rozmiar) == -1) {
- if(errno == EINTR) {
- goto ponowZapis2;
- } else {
- perror("write");
- exit(1);
- }
- }
- }
- void odczytajStandardowaWiadomosc(int fd, char* wyjscie, int* rozmiarWyjscia, int rozmiar)
- {
- /* Jak wyżej tylko zapis*/
- ponowOdczyt:
- if(read(fd, (char*)(rozmiarWyjscia), sizeof(int)) == -1) {
- if(errno == EINTR) {
- goto ponowOdczyt;
- } else {
- perror("write");
- exit(1);
- }
- }
- ponowOdczyt2:
- if(read(fd, wyjscie, *rozmiarWyjscia) == -1) {
- if(errno == EINTR) {
- goto ponowOdczyt2;
- } else {
- perror("write");
- exit(1);
- }
- }
- }
- void s123Obsluga(int signum) {
- /* Jeśli odczytany sygnał jest taki sam jak ostatni odczytany sygnał nie przekazuję
- informacji o nim innym procesom gdyz nie jest to konieczne w przeciwnym wypadku
- zapisuję numer tego syganłu do pamięci dzielonej synchronizujac tą operację odpowiednimy
- semaformai i wysyłam sygnał 4 aby poinformować pozostałe procesy o zapsianiu w pamięci dzielonej
- nowego rządania od operatora */
- if(stanProcesu == signum) {
- // Potencjalnie miejsce do debugowania
- } else {
- opuscN(semid, S_ZAPISZ_KOMUNIKAT, 2);
- *komunikat = signum;
- if(getpid() == pidy[0]) {
- podnies(semid, S_P2_ODCZYTAJ_KOMUNIKAT);
- podnies(semid, S_P3_ODCZYTAJ_KOMUNIKAT);
- kill(pidy[1], S4);
- kill(pidy[2], S4);
- } else if(getpid() == pidy[1]) {
- podnies(semid, S_P1_ODCZYTAJ_KOMUNIKAT);
- podnies(semid, S_P3_ODCZYTAJ_KOMUNIKAT);
- kill(pidy[0], S4);
- kill(pidy[2], S4);
- } else {
- podnies(semid, S_P1_ODCZYTAJ_KOMUNIKAT);
- podnies(semid, S_P2_ODCZYTAJ_KOMUNIKAT);
- kill(pidy[0], S4);
- kill(pidy[1], S4);
- }
- }
- stanProcesu = signum;
- /*Reaguję odpowiednio na odpowiednie sygnały. Na sygnał do kontynuowania nie muszę,
- ponieważ jest on częścią maski użytej w funkcji sigsuspend wiec otrzymanie go obudzi
- proces */
- if(signum == K_ZATRZYMAJ) {
- sigsuspend (&mask);
- }
- if(signum == K_ZAKONCZ) {
- exit(0);
- }
- if(signum == K_KONTYNUUJ) {
- /*Miejsce do debugpwania*/
- }
- }
- void s4Oblusga(int signum) {
- /* Działanie analogiczne do poprzedniej procedury obsługi tylko wartość sygnału, na który
- trzeba zaregować odczytuje z pamięci dzielonej używając odpowiednich semaforów do synchronizacji
- tej operacji oraz nie rozsyłamy dalej tego sygnału */
- int mojPid = getpid();
- int kopiaKomuniaktu = 0;
- if(mojPid == pidy[0]) {
- opusc(semid, S_P1_ODCZYTAJ_KOMUNIKAT);
- } else if(mojPid == pidy[1]) {
- opusc(semid, S_P2_ODCZYTAJ_KOMUNIKAT);
- } else {
- opusc(semid, S_P3_ODCZYTAJ_KOMUNIKAT);
- }
- kopiaKomuniaktu = *komunikat;
- podnies(semid, S_ZAPISZ_KOMUNIKAT);
- stanProcesu = kopiaKomuniaktu;
- if(stanProcesu == K_ZATRZYMAJ) {
- sigsuspend (&mask);
- }
- if(stanProcesu == K_ZAKONCZ) {
- exit(0);
- }
- if(stanProcesu == K_KONTYNUUJ) {
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement