Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "stdio.h"
- #include "string.h"
- #include "sys/types.h"
- #include "sys/stat.h"
- #include "sys/wait.h"
- #include "fcntl.h"
- #include "sys/ipc.h"
- #include "sys/msg.h"
- #include "sys/shm.h"
- #include "sys/sem.h"
- #include "unistd.h"
- #include "stdlib.h"
- #include "signal.h"
- #include "errno.h"
- /* Ścieżka Fifo */
- #define FIFO_PATH "/tmp/prusaczyk_p"
- /* Rozmiary poszczególnych buforów i stałych służących do wypisywania */
- #define ROZMIAR_BUFORA 2
- #define ROZMIAR_BUFORA_KONWERSJI 2*ROZMIAR_BUFORA
- #define ILOSC_ZNAKOW_W_LINII 15
- #define ROZMAIR_BUFORA_WYPISYWANIA ILOSC_ZNAKOW_W_LINII * 3 + 2
- int idKolejki;
- int deskryptoryFifo[2];
- int deskryptorWejscia = -1;
- /* Kod procesu 1 */
- void proces1();
- /* Kod procesu 2 */
- void proces2();
- /* Kod procesu 3 */
- void proces3();
- /* Sygnaly 1 2 i 3 z zadnaia wydrano jako s1 sigint ponieważ można go łątwo wywołać z klawiatury czym łatwo kończymy program*/
- #define SYGNAL1 SIGINT
- #define SYGNAL2 SIGUSR1
- #define SYGNAL3 SIGCONT
- /* Obsługa sygnałów 1-3 */
- void obslugaSygnalow123(int numqerSyngalu, siginfo_t* informacjeOSygnale, void* nieuzywane);
- /* Pamięć dzielona zaweirająca pidy procesów p1-p3 potrzeben na potrzeby signal handlerów */
- int *pidyPotomkow;
- /* id zasobów IPC */
- int idPamieciDzielonej;
- int idSemafora;
- int ostatniSygnal;
- /* Tablica do konwersji na hex, działa tak, podstawiaamy wartość liczby 4ro bitowej jako miejsce a w tablicy znajduje
- się na tym miejscu znak odpowiadający tej liczbie w zapisie szesnastowkym*/
- char tablicaKonwersjiHEX[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
- /* Struktura pomocnincza dla funckji sigaction, którą ustawiam procedury obsługi sygnałów */
- struct sigaction strukturaSigaction;
- /* Służy do odczytywania z deskryptora pliku w momencie gdy może wystąpic przerwanie */
- int odczytaj(int zKad, char* doKad, size_t ile) {
- int doZwrotu;
- powtorzCzynnosc:
- doZwrotu = read(zKad, doKad, ile);
- if(doZwrotu == -1 && errno == EINTR)
- goto powtorzCzynnosc;
- return doZwrotu;
- }
- /*Służy do odczytywania z deskrytpora plika wznawiając ten proces gdy nastąpi przerwanie */
- int zapisz(int doKad, char* zKad, size_t ile) {
- int doZwrotu;
- powtorzCzynnosc:
- doZwrotu = write(doKad, zKad, ile);
- if(doZwrotu == -1 && errno == EINTR)
- goto powtorzCzynnosc;
- return doZwrotu;
- }
- /* Ustawiamy handlery dla sygnałów */
- void ustawSygnaly() {
- strukturaSigaction.sa_sigaction = &obslugaSygnalow123;
- sigemptyset(&strukturaSigaction.sa_mask);
- strukturaSigaction.sa_flags = SA_SIGINFO;
- sigaction(SYGNAL1, &strukturaSigaction, NULL);
- strukturaSigaction.sa_sigaction = &obslugaSygnalow123;
- sigaction(SYGNAL2, &strukturaSigaction, NULL);
- strukturaSigaction.sa_sigaction = &obslugaSygnalow123;
- sigaction(SYGNAL3, &strukturaSigaction, NULL);
- }
- /* Bufor operacji na semaforze */
- static struct sembuf buforOperacjiSem;
- /* Struktura wiadomości, zastosowanie określonych pól opisane poniżej */
- struct msgBuf{
- long mtype; /*Typ wiadomości */
- short ileZnakow; /* Czy zakonczyc komunikacje */
- char wiadomosc[ROZMIAR_BUFORA]; /* Tekst do przekazania z wejścia */
- } buforKomunikatu;
- /* Wysyłamy komunikat przez kolejkę komunikatów wznawiając w przyapdku otrzymania sygnału */
- int wyslijKomunikat(int iloscZnakow, char* bufor)
- {
- int wartoscDoZwrocenia;
- buforKomunikatu.ileZnakow = iloscZnakow;
- buforKomunikatu.mtype = 1;
- strncpy(buforKomunikatu.wiadomosc, bufor, iloscZnakow);
- ponowCzynnosc:
- wartoscDoZwrocenia = msgsnd( idKolejki, &buforKomunikatu, sizeof(buforKomunikatu) - sizeof(long), 0);
- if(wartoscDoZwrocenia==-1 && errno == EINTR)
- goto ponowCzynnosc;
- return wartoscDoZwrocenia;
- }
- /* Jak wyżej, odbiera wiadomość przy użyciu kolejki */
- int odbiezKomunikat(long typKomDoOdebrania, long *typOdebrany, int *ileZnakow, char* bufor)
- {
- int wartoscZwracana;
- ponowCzynnosc:
- wartoscZwracana = msgrcv(idKolejki, &buforKomunikatu, sizeof(buforKomunikatu) - sizeof(long), typKomDoOdebrania, 0);
- if(wartoscZwracana==-1 && errno == EINTR)
- goto ponowCzynnosc;
- *typOdebrany = buforKomunikatu.mtype;
- *ileZnakow = buforKomunikatu.ileZnakow;
- strncpy(bufor, buforKomunikatu.wiadomosc, *ileZnakow);
- return wartoscZwracana;
- }
- /* Konwertuje <rozmiarWejscia> znaków z ciągu wejście na 2 razy tyle znaków będacych zapisem heksadecymalnym kolejnych bajtów
- i zapisuje do ciągu wyjście*/
- size_t konwersjaNaSzesna(char* wejscie, char* wyjscie, int rozmiarWejscia);
- /* Podnosi semafor o 3 sygnalizując, że proces inicjalizujący zapisał do odpowiedniej tablicy pidy procesów p1-p3 aby ich
- procedury obsługi sygnałów mogły przesyłać między procesami p1-p3 nawzajem sygnały */
- int zasygnalizujWpisaniePidow() {
- int retValue = 0;
- buforOperacjiSem.sem_num = 0;
- buforOperacjiSem.sem_op = 3;
- buforOperacjiSem.sem_flg = 0;
- retValue = semop(idSemafora, &buforOperacjiSem, 1);
- if(retValue == -1) {
- perror("semop");
- }
- return retValue;
- }
- /* Oczekujemy na semaforze aż proces inicjalizujący zapisze do pamięci dzielonej pidy wszystkich komunikujących się procesów */
- int oczekaujNaWpisuaniePidow() {
- int retValue = 0;
- buforOperacjiSem.sem_num = 0;
- buforOperacjiSem.sem_op = -1;
- buforOperacjiSem.sem_flg = 0;
- retValue = semop(idSemafora, &buforOperacjiSem, 1);
- if(retValue == -1) {
- perror("semop");
- }
- return retValue;
- }
- /* Maska, którą ustawiamy dla funkcji sigsuspend aby oczekiwać w procedurze obsługi sygnału S2 na albo sygnał do wznowienia lub zakończenia pracy
- (lub kolejny sygnał S2, po którym przechodazimy w dokładnie taki sam stan oczekiwania)*/
- sigset_t maskaOczekiwania;
- int main(int argc, char** argv) {
- /*Sprawdzamy jaki tryb pracy wybrał user*/
- if(argc == 1 || (argc == 2 && strlen(argv[1]) >= 2 && strncmp("-l", argv[1], 3) == 0)){
- /* Tryb danych losowych z pliku /dev/urandom, używany jkao tryb domyślny,
- sposoby aktywacji:
- - nie podawanie żadnych flag, tryb domyślny
- - użycie flagi -l
- */
- deskryptorWejscia = open("/dev/urandom", O_RDONLY);
- } else if( argc == 2 && strlen(argv[1]) >= 2 && strncmp("-i", argv[1], 3) == 0) {
- /* Tryb interaktywny, wczytywanie danych z klawiatury, sposoby aktywowania:
- -flaga -i
- */
- deskryptorWejscia = 0;
- } else if ( argc == 3 && strlen(argv[1]) >= 2 && strncmp("-p", argv[1], 3) == 0) {
- /* Tryb wczytywania danych z pliku, sposób aktywowania:
- -flaga -p po której podajemy ścieżkę do pliku
- */
- deskryptorWejscia = open(argv[2], O_RDONLY);
- }
- if(deskryptorWejscia == -1) {
- perror("Nie moge otworzyc pliku");
- exit(1);
- }
- /* Tworzenie kolejki komunikatów do komunikacji między procesami 1 i 2 */
- umask(0);
- idKolejki = msgget(IPC_PRIVATE, 0600 | IPC_CREAT);
- if(idKolejki == -1) {
- close(deskryptorWejscia);
- perror("Nie moge utworzyc kolejki");
- exit(1);
- }
- /* Tworzenie łącza nazwanaego do komunikacji pomiędzy procesami 2 i 3 *
- wcześniej "na wszelki wypadek" usuwam plik jeśli isnieje.*/
- remove(FIFO_PATH);
- if(mkfifo(FIFO_PATH, 0600) == -1) {
- close(deskryptorWejscia);
- msgctl(idKolejki, IPC_RMID, 0);
- perror("Nie moge utworzyc fifo");
- exit(1);
- }
- /* Tworzę pamięć dzieloną aby przekazać procesom p1-p3 pidy wszystkich procesów z tej grupy */
- idPamieciDzielonej = shmget(IPC_PRIVATE, 3*sizeof(int), 0600 | IPC_CREAT);
- if(idPamieciDzielonej == -1) {
- remove(FIFO_PATH);
- close(deskryptorWejscia);
- msgctl(idKolejki, IPC_RMID, 0);
- perror("Nie moge utworzyc pamieci dizelonej");
- exit(1);
- }
- /* Pryzłączam pamięc dzieloną */
- pidyPotomkow = (int*)shmat(idPamieciDzielonej, NULL, 0600 | IPC_CREAT);
- if(pidyPotomkow == NULL) {
- remove(FIFO_PATH);
- close(deskryptorWejscia);
- msgctl(idKolejki, IPC_RMID, 0);
- perror("Nie moge dolaczyc pamieci dzielonej");
- exit(1);
- }
- /* Tworzę semafor do synchornizacji dostępu do teblicy pidów */
- idSemafora = semget(IPC_PRIVATE, 1, 0600 | IPC_CREAT);
- if(idSemafora == -1) {
- shmctl(idPamieciDzielonej, IPC_RMID, 0);
- remove(FIFO_PATH);
- close(deskryptorWejscia);
- msgctl(idKolejki, IPC_RMID, 0);
- perror("Tworzenie semaforow");
- exit(1);
- }
- /* I ustaiwam dla niego wartość domyślną */
- if (semctl(idSemafora, 0, SETVAL, 0) == -1){
- semctl(idSemafora, 0, IPC_RMID, 0);
- shmctl(idPamieciDzielonej, IPC_RMID, 0);
- remove(FIFO_PATH);
- close(deskryptorWejscia);
- msgctl(idKolejki, IPC_RMID, 0);
- perror("Nadanie wartosci semaforowi");
- semctl(idSemafora, 0, IPC_RMID, 0);
- exit(1);
- }
- /* Przygotowuję maskę dla funkcji sigsuspend*/
- sigfillset (&maskaOczekiwania);
- sigdelset(&maskaOczekiwania, SYGNAL1);
- sigdelset(&maskaOczekiwania, SYGNAL2);
- sigdelset(&maskaOczekiwania, SYGNAL3);
- ostatniSygnal = SYGNAL3;
- /* Tworze procesy 1-3 */
- int wartoscZwrocona = fork();
- if ( wartoscZwrocona == 0 ) {
- proces1();
- exit(0);
- }
- if ( wartoscZwrocona == -1 ) {
- semctl(idSemafora, 0, IPC_RMID, 0);
- shmctl(idPamieciDzielonej, IPC_RMID, 0);
- remove(FIFO_PATH);
- close(deskryptorWejscia);
- msgctl(idKolejki, IPC_RMID, 0);
- perror("Tworzenie p1");
- semctl(idSemafora, 0, IPC_RMID, 0);
- }
- pidyPotomkow[0] = wartoscZwrocona;
- wartoscZwrocona = fork();
- if ( wartoscZwrocona == 0 ) {
- proces2();
- exit(0);
- }
- if ( wartoscZwrocona == -1 ) {
- kill(SIGTERM, pidyPotomkow[0]);
- semctl(idSemafora, 0, IPC_RMID, 0);
- shmctl(idPamieciDzielonej, IPC_RMID, 0);
- remove(FIFO_PATH);
- close(deskryptorWejscia);
- msgctl(idKolejki, IPC_RMID, 0);
- perror("Tworzenie P2");
- semctl(idSemafora, 0, IPC_RMID, 0);
- }
- pidyPotomkow[1] = wartoscZwrocona;
- wartoscZwrocona = fork();
- if ( wartoscZwrocona == 0 ) {
- proces3();
- exit(0);
- }
- if ( wartoscZwrocona == -1 ) {
- kill(SIGTERM, pidyPotomkow[0]);
- kill(SIGTERM, pidyPotomkow[1]);
- semctl(idSemafora, 0, IPC_RMID, 0);
- shmctl(idPamieciDzielonej, IPC_RMID, 0);
- remove(FIFO_PATH);
- close(deskryptorWejscia);
- msgctl(idKolejki, IPC_RMID, 0);
- perror("Tworzenie P2");
- semctl(idSemafora, 0, IPC_RMID, 0);
- }
- pidyPotomkow[2] = wartoscZwrocona;
- printf("Pid procesu P1:%d, pid procesu P2:%d, pid procesu P3:%d\n", pidyPotomkow[0], pidyPotomkow[1], pidyPotomkow[2]);
- fflush(stdout);
- zasygnalizujWpisaniePidow();
- /* Czekam na zakończenie procesów 1-3 */
- wait(0);
- wait(0);
- wait(0);
- /* Usuwam utworzone mechanizmy komunkacji */
- if(msgctl(idKolejki, IPC_RMID, 0)== -1) {
- perror("Uuswanie kolejki komunikatow");
- }
- /* Usuwanie fifo */
- if(remove(FIFO_PATH) == -1) {
- perror("Usuwanie fifo");
- }
- /*Usuwam zestaw semaforów */
- if(semctl(idSemafora, 0, IPC_RMID, 0) == -1) {
- perror("Usuwanie semafora");
- }
- /*Usuwam pamieci dzielonej */
- if(shmdt(pidyPotomkow) == -1) {
- perror("shmdt");
- }
- if(shmctl(idSemafora, IPC_RMID, 0) == -1) {
- perror("Usuwanie pamieci dzielonej");
- }
- close(deskryptoryFifo[0]);
- close(deskryptoryFifo[1]);
- }
- void proces1() {
- size_t odczyantchZnakow;
- char bufor[ROZMIAR_BUFORA];
- /* Oczekujemy na podniesienie semafora przez proces inicjalizujący i ustawiam procedury obsługi przerwań */
- oczekaujNaWpisuaniePidow();
- ustawSygnaly();
- for(;1;) {
- /* Odczytujemy do bufora zanki z deskryptora wejścia oraz ich ilosc*/
- odczyantchZnakow = odczytaj(deskryptorWejscia, bufor, ROZMIAR_BUFORA);
- /* I przekazujemy do prcoesu 2 przy użyciu kolejki komunikatów*/
- wyslijKomunikat(odczyantchZnakow, bufor);
- if(odczyantchZnakow<=0)
- break;
- }
- exit(0);
- }
- void proces2() {
- long typ;
- int ile;
- char bufor[ROZMIAR_BUFORA];
- char buforKonwersji[ROZMIAR_BUFORA_KONWERSJI];
- /* Oczekujemy na podniesienie semafora przez proces inicjalizujący i ustawiam procedury obsługi przerwań */
- oczekaujNaWpisuaniePidow();
- ustawSygnaly();
- /* Otwieramy łącze nazwane do zapisu w celu przezywania danych po konwersji ich na postać szesnastkowa*/
- deskryptoryFifo[1] = open(FIFO_PATH, O_WRONLY);
- if(deskryptoryFifo[1] == -1){
- perror("otwieranie fifo zapis");
- kill(getpid(), SYGNAL1);
- }
- for(;1;) {
- /* Odbieramy komunikat od procesu 1, zawiera dane pobrane przez ten proces oraz ilość znaków w pobrnaym ciągu */
- odbiezKomunikat(1, &typ, &ile, bufor);
- /* Dokonujmey konwersji na zapis heksadecymalny */
- ile = konwersjaNaSzesna(buforKonwersji, bufor, ile);
- /* I zapisuje do łącza nazwanego zapisując najpierw ilość znaków w tym ciągu a następnie same te znaki */
- zapisz(deskryptoryFifo[1], (char *)(&ile), sizeof(int));
- zapisz(deskryptoryFifo[1], buforKonwersji, ile);
- if(ile == 0)
- break;
- }
- exit(0);
- }
- void proces3() {
- int ile;
- char bufor[ROZMIAR_BUFORA_KONWERSJI];
- char buforWypisywania[ILOSC_ZNAKOW_W_LINII * 3 + 2];
- int ileWWypisywania = 0;
- int i;
- /* Oczekujemy na podniesienie semafora przez proces inicjalizujący i ustawiam procedury obsługi przerwań */
- oczekaujNaWpisuaniePidow();
- ustawSygnaly();
- /* Otwieram łącze nazwane do oczytu skonwertowanych danych z procesu 2*/
- deskryptoryFifo[0] = open(FIFO_PATH, O_RDONLY);
- if(deskryptoryFifo[0] == -1){
- perror("otwieranie fifo odczyt");
- kill(getpid(), SYGNAL1);
- }
- for(;1;) {
- /* Odczytuje dname z fifo w formacie opisaym w procesie 2 przy ich zapisie */
- odczytaj(deskryptoryFifo[0], (char *)(&ile), sizeof(int));
- odczytaj(deskryptoryFifo[0], bufor, ile);
- /* Formatuje dane zgodnie z treścią polecenia i wypisuje po 15 */
- for(i=0; i<ile; i+=2) {
- buforWypisywania[3*ileWWypisywania] = bufor[i];
- buforWypisywania[3*ileWWypisywania+1] = bufor[i + 1];
- buforWypisywania[3*ileWWypisywania+2] = ' ';
- /* Za każdym razem dodaję znak nowej linii, potem nadpisuywany przy zapisie następnego znaku, służy to przygotwaniu
- bufora linii na kolejny zapis wynikający z końca pliku a nie zapełnieniea bufra linii */
- buforWypisywania[3*ileWWypisywania+3] = '\n';
- ileWWypisywania++;
- /* Wypisuje linię jeśli jest w niej 15 znaków */
- if(ileWWypisywania >= ILOSC_ZNAKOW_W_LINII) {
- zapisz(1, buforWypisywania,ileWWypisywania*3+1);
- ileWWypisywania = 0;
- }
- }
- /* Lub gdy został zasygnalizowqany koniec wejścia */
- if(ile <= 0) {
- zapisz(1, buforWypisywania,ileWWypisywania*3+1);
- ileWWypisywania = 0;
- break;
- }
- }
- exit(0);
- }
- /* Prosta funkcja konwertująca ciąg znaków na zapis kolejnych bajtów w postaci heksadecymalnej opisanej przy deklarqacji */
- size_t konwersjaNaSzesna(char* wyjscie, char* wejscie, int rozmiarWejscia)
- {
- int i = 0;
- for(i = 0; i < rozmiarWejscia; i++)
- {
- wyjscie[2*i] = tablicaKonwersjiHEX[(wejscie[i] & 0xFF) >> 4];
- wyjscie[2*i + 1] = tablicaKonwersjiHEX[(wejscie[i] & 0x0F)];
- }
- return 2*rozmiarWejscia;
- }
- /* Procedura obsługi sygnału*/
- void obslugaSygnalow123(int numerSyngalu, siginfo_t* informacjeOSygnale, void* nieuzywane) {
- int mojPid = getpid();
- int pidNadawcy = informacjeOSygnale -> si_pid;
- fprintf(stderr, "%d:Odebrano sygnal %d\n", mojPid, numerSyngalu);
- /* Jeśli nadawcą nie jest proces ze zbioru p1-p3 to rozsyłamy ten sam sygnał do pozostałych procesów z tej grupy,
- jeśli jest to jeden z tych procesów to nie rozsyłam daleej sygnału, bo oznacza to, że ten sygnał powestał w wyniku opisanego
- powyżej działania */
- if(!(pidNadawcy == pidyPotomkow[0] || pidNadawcy == pidyPotomkow[1] || pidNadawcy == pidyPotomkow[2])) {
- if(mojPid != pidyPotomkow[0])
- kill(pidyPotomkow[0], numerSyngalu);
- if(mojPid != pidyPotomkow[1])
- kill(pidyPotomkow[1], numerSyngalu);
- if(mojPid != pidyPotomkow[2])
- kill(pidyPotomkow[2], numerSyngalu);
- }
- /* Rekcja na sygnał odpowiednia dla konkretnego sygnału */
- switch (numerSyngalu)
- {
- case SYGNAL1:
- exit(0);
- break;
- case SYGNAL2:
- sigsuspend(&maskaOczekiwania);
- break;
- case SYGNAL3:
- break;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement