Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <errno.h>
- #include <libgen.h>
- #include <string.h>
- #include <limits.h>
- #include <unistd.h>
- #include <stdbool.h>
- #include <dirent.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/msg.h>
- #include <sys/mman.h>
- #include <stdlib.h>
- #include <fcntl.h>
- #include <wait.h>
- #include <signal.h>
- #define POSPRZATAJ() do{wait(&pids[2]);remove(SCIEZKA_KOLEJKI_1);}while(0)
- #define DEBUGPIRNTF
- #define DLUGOSC_KOMUNIKATU 1024
- #define SCIEZKA_KOLEJKI_1 "/tmp/projekt_so2"
- /* Sygnał, który kończy działanie programu. */
- #define S1 SIGUSR1
- /* Sygnał, który zatrzymuje komunikację procesów. */
- #define S2 SIGUSR2
- /* Sygnał, który wznawia komunikację procesów. */
- #define S3 SIGCONT
- #define ILE_PROCESOW 3
- // Typy wiadomosci (mtype)
- #define WIADOMOSC_OD_MASTERA 1
- // Struktura dla wiadomości typu WIADOMOSC_ARGC
- struct msgcargbuf {
- long mtype; /* typ komunikatu */
- long komunikat;
- } msgCargs;
- // Struktura dla wiadomości typu WIADOMOSC_OD_*
- struct mymsgbuf {
- long mtype; /* typ komunikatu */
- short czyOstatni; /* czy ostatni komunikat (0=nie cokolwiek innego tak) */
- char komunikat[DLUGOSC_KOMUNIKATU]; /* Właściwa przesyłana informacja */
- } msg;
- /* Tablica przechowuje PIDy procesów */
- int *pids;
- /* Czy pierwszy sygnał ma zostać wysłany do wszystkich procesów czy odebraliśmy ten sygnał od innego
- * procesu */
- short *czyPierwszySygnal;
- /* Jak wyżej tylko dla procesu 2. */
- short *czyDrugiSygnal;
- /* Jak wyżej tylko dla procesu 3. */
- short *czyTrzeciSygnal;
- int open_queue( key_t keyval ) {
- int qid;
- if((qid = msgget( keyval, IPC_CREAT | 0660 )) == -1)
- return(-1);
- return(qid);
- }
- int send_message( int qid, struct mymsgbuf *qbuf ){
- int result;
- size_t length;
- /* lenght jest rozmiarem struktury minus sizeof(mtype) */
- length = sizeof(struct mymsgbuf) - sizeof(long);
- if((result = msgsnd( qid, qbuf, length, 0)) == -1)
- return(-1);
- return(result);
- }
- // Z plików z poprzedniego zadania.
- int remove_queue( int qid ){
- if( msgctl( qid, IPC_RMID, 0) == -1)
- return(-1);
- return(0);
- }
- int read_message( int qid, long type, struct mymsgbuf *qbuf ){
- int result, length;
- /* lenght jest rozmiarem struktury minus sizeof(mtype) */
- length = sizeof(struct mymsgbuf) - sizeof(long);
- if((result = msgrcv( qid, qbuf, length, type, 0)) == -1)
- return(-1);
- return(result);
- }
- // Odczytuje komunikat i obsługuje błędy.
- void odczytajKomunikat( int qid, long type, struct mymsgbuf *qbuf )
- {
- /* Wywołanie syscall może być przerwane przez sygnał ale nie chcę blokować sygnałów w tym miejscu,
- * ponieważ w trybie interkatywnym program zatrzymuje się w tej tej funkcji w oczekiwaniu na dane co powodowałoby
- * długie okresy kiedy sygnał nie może być obsłużony.
- * To samo dotyczy sie każdego zapisu i odczytu z mechanizmów komunikacji międzyprocesowej i plików pomimo,
- * że linux raczej nie przerywa na sygnale wywołań read/write. */
- again:
- errno = 0;
- if( read_message(qid, type, qbuf ) == -1)
- {
- if(errno == EINTR)
- {
- goto again;
- }
- else {
- perror("Odbieranie");
- exit(2);
- }
- }
- }
- // Wysyła komunikat i obsługuje błędy.
- void wyslijKomunikat(int qid, struct mymsgbuf *qbuf, long typ, char *wiadomosc, short czyOstatni)
- {
- qbuf -> mtype= typ; /* typ wiadomości musi być dodatni */
- qbuf -> czyOstatni = czyOstatni;
- strcpy(qbuf -> komunikat, wiadomosc);
- /* Wysylamy */
- again:
- errno = 0;
- if((send_message( qid, qbuf )) == -1) {
- if(errno == EINTR)
- {
- goto again;
- }
- else
- {
- perror("Wysylanie");
- exit(1);
- }
- }
- }
- /* W tej funkcji zaimplemntowano działania procesu 1 */
- int proc1(key_t qid, int argc, char** argv);
- /* W tej funkcji zaimplemntowano działania procesu 2 */
- int proc2(key_t qid, char* sciezkaKolejki);
- /* W tej funkcji zaimplemntowano działania procesu 3 */
- int proc3(char* sciezkaKolejki);
- void sigS1Handler(int signal)
- {
- if(*czyPierwszySygnal)
- {
- *czyPierwszySygnal = 0;
- for (int i = 0; i < ILE_PROCESOW; ++i)
- {
- if (pids[i] != getpid()) {
- kill(pids[i], S1);
- }
- }
- }
- exit(0);
- }
- void sigS2Handler(int signal)
- {
- if(*czyDrugiSygnal)
- {
- *czyDrugiSygnal = 0;
- for (int i = 0; i < ILE_PROCESOW; ++i) {
- if (pids[i] != getpid()) {
- kill(pids[i], S2);
- }
- }
- *czyTrzeciSygnal = 1;
- }
- sigset_t mask, oldmask;
- sigfillset (&mask);
- sigdelset(&mask, S1);
- sigdelset(&mask, S2);
- sigdelset(&mask, S3);
- //sigaddset (&mask, SIGCONT);
- /* Oczekiwanie na sygnał do wznowienia komunikacji międzyprocesowej. */
- #ifdef DEBUGPIRNTF
- printf("Przed blokiem\n");
- #endif
- sigsuspend (&mask);
- #ifdef DEBUGPIRNTF
- printf("Po bloku.\n");
- #endif
- }
- void sigS3Handler(int signal)
- {
- if(*czyTrzeciSygnal)
- {
- *czyTrzeciSygnal = 0;
- for (int i = (ILE_PROCESOW - 1); i >= 0 ; --i)
- {
- if (pids[i] != getpid()) {
- kill(pids[i], S3);
- }
- }
- }
- *czyDrugiSygnal = 1;
- #ifdef DEBUGPIRNTF
- printf("S3 HANDLER pid: %d\n", getpid());
- #endif
- }
- int main(int argc, char** argv) {
- /* Tworzymy zmienne w pamięci współdzielonej (mmap służy do mapowania plików w pamięci lub jak w tym przypadku(
- * z argumnetem MAP_ANONYMOUS) do towrzenia zmiennych, do których dostęp mogą mieć procesy potomne. */
- pids = mmap(NULL, 3*sizeof(int),
- PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED,
- -1, 0);
- czyPierwszySygnal = mmap(NULL, sizeof(short),
- PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED,
- -1, 0);
- czyDrugiSygnal = mmap(NULL, sizeof(short),
- PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED,
- -1, 0);
- czyTrzeciSygnal = mmap(NULL, sizeof(short),
- PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED,
- -1, 0);
- if ( !(pids && czyPierwszySygnal && czyDrugiSygnal && czyTrzeciSygnal) )
- {
- printf("Nie udalo sie utworzyc pamieci wspoldzielonej.\n");
- exit(1);
- }
- *czyPierwszySygnal = 1;
- *czyDrugiSygnal = 1;
- *czyTrzeciSygnal = 1;
- pids[0] = 0;
- pids[1] = 0;
- pids[2] = 0;
- int qid;
- key_t msgkey;
- /* tworzymy wartość klucza IPC */
- msgkey = ftok(".", 'l');
- /* otwieramy/tworzymy kolejkę */
- if(( qid = open_queue( msgkey)) == -1) {
- perror("Otwieranie_kolejki");
- POSPRZATAJ();
- exit(1);
- }
- mkfifo(SCIEZKA_KOLEJKI_1, 0666);
- int forkRet = fork();
- if(forkRet == -1)
- {
- perror("Tworzenie procesu:");
- POSPRZATAJ();
- exit(1);
- }
- if(forkRet == 0)
- {
- proc1(qid, argc, argv);
- return 0;
- }
- pids[0] = forkRet;
- forkRet = fork();
- if(forkRet == -1)
- {
- perror("Tworzenie procesu:");
- POSPRZATAJ();
- exit(1);
- }
- if(forkRet == 0)
- {
- proc2(qid, SCIEZKA_KOLEJKI_1);
- return 0;
- }
- pids[1] = forkRet;
- forkRet = fork();
- if(forkRet == -1)
- {
- perror("Tworzenie procesu:");
- POSPRZATAJ();
- exit(1);
- }
- if(forkRet == 0)
- {
- proc3(SCIEZKA_KOLEJKI_1);
- return 0;
- }
- pids[2] = forkRet;
- printf("Pid procesu 1:%d\nPid procesu 2:%d\nPid procesu 3:%d\n", pids[0], pids[1], pids[2]);
- /* Oczekiwanie aż pracę zakończą procesy kożystające z kolejki komunikatów. */
- wait(&pids[0]);
- wait(&pids[1]);
- /*Usuwamy kolejke*/
- remove_queue(qid);
- /* Czekamy aż ostatni proces, który kożysta z fifo przed zamknięciem go. */
- wait(&pids[2]);
- /*Usuwamy fifo*/
- remove(SCIEZKA_KOLEJKI_1);
- #ifdef DEBUGPIRNTF
- printf("Wszystko zakonczylo.\n");
- #endif
- }
- int proc1(key_t qid, int argc, char** argv)
- {
- /* Ustawia handlery(procedury obsługi) dla poszczególnych syganłów */
- signal(S1, sigS1Handler);
- signal(S2, sigS2Handler);
- signal(S3, sigS3Handler);
- /* Jeśli nie ma argumentów wywołania: tryb interaktywny. */
- if(argc == 1)
- {
- char buf[DLUGOSC_KOMUNIKATU];
- char* fgetsRet = NULL;
- while (1) {
- /* odczytuje kolejne linie z wejscia ( zachowanie gwarantowane dla linni nie dłużych niż długość komunikatu
- * i wysyła je przy użyciu kolejki komuniktaów do procesu 2*/
- again:
- errno = 0;
- fgetsRet = fgets(buf, DLUGOSC_KOMUNIKATU, stdin);
- if (fgetsRet == NULL && errno == EINTR)
- goto again;
- short czyOstatni = (buf[0] == '\n');
- wyslijKomunikat(qid, &msg, WIADOMOSC_OD_MASTERA, buf, czyOstatni);
- if (czyOstatni)
- break;
- }
- }
- /* Argument wywołnia -r: czytanie z pliku /dev/urandom */
- else if(argc == 2 && !strcmp(argv[1],"-r"))
- {
- short czyOstatni = 0;
- ssize_t ileOdczytano = 0;
- int fp = open("/dev/urandom", O_RDONLY);
- if(fp == -1)
- {
- /* Nie można uzyskać dostępu do pliku (nie istnieje lub brak uprawnień lub dowolny inny powód
- * Wysyłamy drugiemu procesowi informacje aby zakończył działanie */
- printf("Nie moge uzyskac dostepu do pliku.\n");
- wyslijKomunikat(qid, &msg, WIADOMOSC_OD_MASTERA, "", 1);
- exit(1);
- }
- /*Czyszczenie bufora*/
- char buf[DLUGOSC_KOMUNIKATU];
- for (int i = 0; i < DLUGOSC_KOMUNIKATU; ++i) {
- buf[i] = '\0';
- }
- /* Przesyłanie przy użuyciu kolejki komunikatów dane odczytane z /dev/urandom do drugiego procesu */
- while(1){
- againR:
- errno = 0;
- ileOdczytano = read(fp, buf, DLUGOSC_KOMUNIKATU);
- if(ileOdczytano == -1 && errno == EINTR)
- goto againR;
- if(ileOdczytano ==0)
- {
- czyOstatni = 1;
- } else
- {
- czyOstatni = 0;
- }
- wyslijKomunikat(qid, &msg, WIADOMOSC_OD_MASTERA, buf, czyOstatni);
- for (int i = 0; i < DLUGOSC_KOMUNIKATU; ++i) {
- buf[i] = '\0';
- }
- if(ileOdczytano == 0)
- break;
- }
- close(fp);
- }
- /* Argument wywołnia -f: czytanie z pliku podanego jako kolejny argument */
- /* Jak dla arguemtnu wywołania -r tylko ścieżka przyjęta przez użytkownika. */
- else if(argc == 3 && !strcmp(argv[1],"-f"))
- {
- short czyOstatni = 0;
- ssize_t ileOdczytano = 0;
- int fp = open(argv[2], O_RDONLY);
- if(fp == -1)
- {
- printf("Nie moge uzyskac dostepu do pliku.\n");
- wyslijKomunikat(qid, &msg, WIADOMOSC_OD_MASTERA, "", 1);
- exit(1);
- }
- char buf[DLUGOSC_KOMUNIKATU];
- for (int i = 0; i < DLUGOSC_KOMUNIKATU; ++i) {
- buf[i] = '\0';
- }
- while(1)
- {
- againF:
- ileOdczytano = read(fp, buf, DLUGOSC_KOMUNIKATU);
- if(ileOdczytano == -1 && errno == EINTR)
- goto againF;
- if(ileOdczytano ==0)
- {
- czyOstatni = 1;
- } else
- {
- czyOstatni = 0;
- }
- wyslijKomunikat(qid, &msg, WIADOMOSC_OD_MASTERA, buf, czyOstatni);
- for (int i = 0; i < DLUGOSC_KOMUNIKATU; ++i) {
- buf[i] = '\0';
- }
- if(ileOdczytano == 0)
- break;
- }
- //wyslijKomunikat(qid, &msg, "", buf, 1);
- close(fp);
- }
- return 0;
- }
- int proc2(key_t qid, char* sciezkaKolejki)
- {
- signal(S1, sigS1Handler);
- signal(S2, sigS2Handler);
- signal(S3, sigS3Handler);
- char buf[DLUGOSC_KOMUNIKATU];
- int fifo = open(sciezkaKolejki, O_WRONLY);
- do{
- /*Odbieram kolejne komunikaty z kolejki komunikatów i wartości kolejnych bajtów(charów) komunikatu
- * i wypisanie tych bajtów w wyniku konwersji przy użciu funkcji snprintf() do fifo */
- odczytajKomunikat(qid, WIADOMOSC_OD_MASTERA, &msg);
- strncpy(buf, msg.komunikat, DLUGOSC_KOMUNIKATU);
- size_t iloscZnakow = strlen(msg.komunikat);
- char bufKonwersji[3];
- for(int i = 0; i < iloscZnakow; i++)
- {
- snprintf(bufKonwersji, 3, "%02x", msg.komunikat[i]);
- // puts(bufKonwersji);
- again:
- errno = 0;
- if (write(fifo, bufKonwersji, 3) == -1 && errno == EINTR)
- goto again;
- }
- }while(!msg.czyOstatni);
- // remove_queue(qid);
- return 0;
- }
- int proc3(char* sciezkaKolejki)
- {
- signal(S1, sigS1Handler);
- signal(S2, sigS2Handler);
- signal(S3, sigS3Handler);
- int fifo = open(sciezkaKolejki, O_RDONLY);
- char buf[3];
- int ileWBuforze = 0;
- char odczytane[15][3];
- ssize_t readRet = 0;
- while(1)
- {
- /*Odczytywanie kolejnych skowertowanych bajtów przy użyciu fifo i ponawianie w przypadku
- * przerwania przez sygnał.*/
- again:
- errno = 0;
- readRet = read(fifo, buf, 3);
- if (readRet == 0)
- break;
- if (readRet == -1 && errno == EINTR)
- goto again;
- /* Zapisywanie kolejnego odczytanego z fifo skownwertownaego znaku w buforze */
- strcpy(odczytane[ileWBuforze++], buf);
- /* Jeśli bufor zapełniony wypisujemy dane */
- if(ileWBuforze >= 15)
- {
- int i = 0;
- for(; (ileWBuforze - 1) > i; i++)
- {
- printf("%s ", odczytane[i]);
- }
- printf("%s\n", odczytane[i]);
- ileWBuforze = 0;
- }
- }
- /* Wypisywanie pozostalych elemntów z bufora(jeśli zostaną po wypisaniu ostatniej 15sto znakowej linii */
- if(ileWBuforze > 0)
- {
- int i = 0;
- for(; i < (ileWBuforze - 1); i++)
- {
- printf("%s ", odczytane[i]);
- }
- printf("%s\n", odczytane[i]);
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement