Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* Długość linii, mechanizmy */
- #include "stdio.h"
- #include "string.h"
- #include "fcntl.h"
- #include "unistd.h"
- #include "errno.h"
- #include "sys/types.h"
- #include "sys/stat.h"
- #include "stdlib.h"
- #include "wait.h"
- #include "sys/ipc.h"
- #include "sys/sem.h"
- #include "sys/shm.h"
- #define PATH_FIFO "/tmp/pieniak_projekt"
- #define ROZMIAR_BUFORA_LINII 500
- #define ROZMIAR_BUFORA_KONWERSJI 2*ROZMIAR_BUFORA_LINII
- #define N_W_LINII 15
- #define S_SHM_READ 0
- #define S_SHM_WRITE 1
- #define S_PIDS_READ 2
- #define S_LAST_SIG_WRITE 3
- #define S_LAST_SIG_R1 4
- #define S_LAST_SIG_R2 5
- #define S_LAST_SIG_R3 6
- #define SIGNAL1 SIGINT
- #define SIGNAL2 SIGUSR1
- #define SIGNAL3 SIGCONT
- #define SIGNAL4 SIGUSR2
- void signalHandler(int signum);
- /* nazwy są dosc opisowe*/
- int semId;
- int shmId;
- /* To obszary pamieci dzielonej kolejno ilosci znakow w buforze(sposob przekazywania jej miedzy p2 i p3)*/
- int *nOfChars;
- /* To obszary pamieciprzechowuje znaki po konwersji(sposob przekazywania jej miedzy p2 i p3)*/
- char *convBuffer;
- /* Tablica pidow procesow sluzca im do komunikacji od przeslanych sygnalach */
- int *pids;
- /* Ostatni odebreany sygnał użyteczne gdy chcemy wiedziec czy musimy rozsylac sygnal od usera czy nie(
- jesli jest taki sam jak ostatni nie zmieni stanu procesow
- )*/
- int *lastSig;
- /* Kopia wartosci z powyzszej pamięci dzialonej aby nie blokować za długo dostępu do tej pamieci */
- int lastSigCopy;
- /* Deskryptor wejscia*/
- int inputDescriptor = -1;
- /* Maska na ktorej procesu oczekują przy użyciu funkcji sigsuspend po otrzymaniu sygnału 2 */
- sigset_t sigsuspendMask;
- /* Sighandler dla sygnałow 1-3 przesyla do innych procesow przez pamiec dzielona informacje o tym czego żąda operator(jeśli
- to żądniae jest różne od poprzedniego) i sam wykonuje odpowiednie czynnosci */
- void normalSigHandler(int signum);
- /* Dziala jak wyzje tylko nie rozsyla sygnalu a dzialania podejmuje nie na podstawie numeru sygnalu a zwartosci pamieci dzielonej*/
- void comunicationSigHandler(int signum);
- static struct sembuf semopBuffer;
- /* Analogiczna do zwyklej funkcji read tylko ponawia w przypadku otrzymania sygnału */
- int readFifo(int fd, char *str, size_t len) {
- int toReturn;
- repeat:
- toReturn = read(fd, str, len);
- if(toReturn == -1 && errno == EINTR)
- goto repeat;
- return toReturn;
- }
- /*Tablica pomocnicza i funkcja służące do konwersji wartosci bajtów na heksadecymalne */
- char hexConversionArray[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
- size_t hexConvesion(char* in, char* out, int n)
- {
- int i = 0;
- for(i = 0; i < n; i++)
- {
- out[2*i] = hexConversionArray[(in[i] >> 4) & 0x0F];
- out[2*i + 1] = hexConversionArray[(in[i] & 0x0F)];
- }
- return 2*n;
- }
- /* opisuje reakcję na sygnał. Wydzielone do osobnej funkcji ponieważ używam tego w 2 handlerach */
- void reactToSignal(int signum);
- /* Operacja na jednym z semaforow sysV z zestawu */
- void sysvSemop(int semid, int semnum, int anmount) {
- repeat:
- semopBuffer.sem_num = semnum;
- semopBuffer.sem_op = anmount;
- semopBuffer.sem_flg = 0;
- if (semop(semid, &semopBuffer, 1) == -1)
- {
- if(errno == EINTR)
- goto repeat;
- else {
- perror("semop");
- exit(1);
- }
- }
- }
- /* Analogiczna do zwyklej funkcji read tylko ponawia w przypadku otrzymania sygnału */
- int writeFifo(int fd, char *str, size_t len) {
- int toReturn;
- repeat:
- toReturn = write(fd, str, len);
- if(toReturn == -1 && errno == EINTR)
- goto repeat;
- return toReturn;
- }
- /* Z uwagi na ilosc semaforow ustawianie domyslnej wartosci semafora wydzieliwem do osobnej funkcji */
- int ustawDomyslnaSemafora(int semid, short semnum, int semval) {
- if (semctl(semid, semnum, SETVAL, semval) == -1){
- remove(PATH_FIFO);
- semctl(semid, 0, IPC_RMID, 0);
- perror("semop");
- return -1;
- }
- return 0;
- }
- /* Funkcje wywoływane w procesach 1-3*/
- void task1();
- void task2();
- void task3();
- int main(int argc, char** argv) {
- /* Otworz plik wskazany przez argumenty wywolania */
- if(argc == 2) {
- if(strcmp(argv[1], "-r") == 0) {
- inputDescriptor = open("/dev/urandom", O_RDONLY);
- } else {
- inputDescriptor = open(argv[1], O_RDONLY);
- }
- } else {
- inputDescriptor = 0;
- }
- if(inputDescriptor == -1) {
- perror("Otwieranie pliku wejsciowego");
- exit(1);
- }
- /* Przygotwuje maske dla sigsuspend */
- sigfillset (&sigsuspendMask);
- sigdelset(&sigsuspendMask, SIGNAL1);
- sigdelset(&sigsuspendMask, SIGNAL2);
- sigdelset(&sigsuspendMask, SIGNAL3);
- sigdelset(&sigsuspendMask, SIGNAL4);
- /* Tworze fifo do komunkacji procesów 1 i 2*/
- printf("Tworze fifo 1->2\n");
- umask(0);
- remove(PATH_FIFO);
- if(mkfifo(PATH_FIFO, 0600) == -1) {
- perror("Tworzenie fifo 1->2");
- exit(1);
- }
- /* Tworze zestaw semaforow */
- semId = semget(IPC_PRIVATE, 7, 0600|IPC_CREAT);
- if(semId == -1) {
- remove(PATH_FIFO);
- perror("Tworzenie semaforow");
- }
- /* Ustawiam wartosci domyslne semaforow */
- ustawDomyslnaSemafora(semId, S_SHM_READ, 0);
- ustawDomyslnaSemafora(semId, S_SHM_WRITE, 1);
- ustawDomyslnaSemafora(semId, S_PIDS_READ, 0);
- ustawDomyslnaSemafora(semId, S_LAST_SIG_WRITE, 3);
- ustawDomyslnaSemafora(semId, S_LAST_SIG_R1, 0);
- ustawDomyslnaSemafora(semId, S_LAST_SIG_R2, 0);
- ustawDomyslnaSemafora(semId, S_LAST_SIG_R3, 0);
- /*Tworze pamięc dzieloną */
- shmId = shmget(IPC_PRIVATE,sizeof(int) + ROZMIAR_BUFORA_KONWERSJI * sizeof(char) + 4 * sizeof(int), 0600|IPC_CREAT);
- if(shmId < 0) {
- perror("shmget");
- exit(1);
- }
- /* I przyłączma ją pod odpowiednie adresy */
- nOfChars = shmat(shmId, NULL, 0);
- convBuffer = (char*)(nOfChars + 1);
- pids = (int *)(convBuffer + ROZMIAR_BUFORA_KONWERSJI);
- lastSig = pids + 3;
- /* Tworze 3 procesy tworząc odpowiednie funkcje */
- int rc = fork();
- if(rc == 0) {
- task1();
- exit(0);
- }
- pids[0] = rc;
- rc = fork();
- if(rc == 0) {
- task2();
- exit(0);
- }
- pids[1] = rc;
- rc = fork();
- if(rc == 0) {
- task3();
- exit(0);
- }
- pids[2] = rc;
- /* Ustawiamy, ze startowym poprzednim sygnałem dla procesu jest sygnał do kontynuacji działania */
- *lastSig = SIGNAL3;
- lastSigCopy = SIGNAL3;
- /* Wypisuje pidy utworzonych procesów */
- printf("Pid1:%d pid2:%d pid3:%d\n", pids[0], pids[1], pids[2]);
- fflush(stdout);
- /* Informuję procesy, ze tablica pidów została poprawnie uzupełniona co jest ważne dla obsługi sygnałów wiec nie włączamy ich przed tym momentem */
- sysvSemop(semId, S_PIDS_READ, 3);
- /* Po zakończeniu procesów 1,2 i 3 usuwam dla ich komunikacji zasoby */
- wait(0);
- wait(0);
- wait(0);
- /* Program ussuwa utworzone zasoby */
- if(remove(PATH_FIFO) == -1) {
- perror("Usuwanie fifo 1");
- }
- if(shmctl(shmId, IPC_RMID, 0) == -1) {
- perror("Usuwanie pamieci dzielonej");
- }
- if(semctl(semId, 0, IPC_RMID, 0) == -1) {
- perror("Usuwanie zestawu semaforow");
- }
- printf("Zakończono działanie\n");
- }
- void task1() {
- /* Tworzę bufor otwieram fifo i po otrzymaniu informacji, że pidy zostały poprawnie uzupełnione włączam obsługę
- sygnałów */
- fprintf(stderr, "proces 1 uruchamia sie\n");
- size_t nOfReadChars = 0;
- char lineBuffer[ROZMIAR_BUFORA_LINII];
- int fifoFd = open(PATH_FIFO, O_WRONLY);
- sysvSemop(semId, S_PIDS_READ, -1);
- signal(SIGNAL1, normalSigHandler);
- signal(SIGNAL2, normalSigHandler);
- signal(SIGNAL3, normalSigHandler);
- signal(SIGNAL4, comunicationSigHandler);
- do {
- /* Pobieram dane ze wskazanego deskryptora i przekazuję je przez fifo poprzedzjaąc je ilościa odczytanych znaków do procesu 2 */
- nOfReadChars = readFifo(inputDescriptor, lineBuffer, ROZMIAR_BUFORA_LINII);
- writeFifo(fifoFd, (char*)(&nOfReadChars), sizeof(size_t));
- writeFifo(fifoFd, lineBuffer, nOfReadChars);
- } while (nOfReadChars > 0);
- }
- void task2() {
- /* Tworzę bufor otwieram fifo i po otrzymaniu informacji, że pidy zostały poprawnie uzupełnione włączam obsługę
- sygnałów */
- fprintf(stderr, "proces 2 uruchamia sie\n");
- long nOfCharsRead = 0;
- long nCharsConversion = 0;
- char lineBuffer[ROZMIAR_BUFORA_LINII];
- char conversionBuffer[ROZMIAR_BUFORA_KONWERSJI];
- int fifoFd = open(PATH_FIFO, O_RDONLY);
- sysvSemop(semId, S_PIDS_READ, -1);
- int i;
- signal(SIGNAL1, normalSigHandler);
- signal(SIGNAL2, normalSigHandler);
- signal(SIGNAL3, normalSigHandler);
- signal(SIGNAL4, comunicationSigHandler);
- do {
- /* Odczytuje linie z fifo ilosc bajtow a nastepnie same bajty do odpowiedniego bufora */
- readFifo(fifoFd, (char*)(&nOfCharsRead), sizeof(size_t));
- readFifo(fifoFd, lineBuffer, nOfCharsRead);
- /* Konwertuję te bajty na ich wartości heksadecymalne */
- nCharsConversion = hexConvesion(lineBuffer, conversionBuffer, nOfCharsRead);
- /* I przekazuję je przez pamięć dzieloną synchronizując do niej dostęp semaformai */
- sysvSemop(semId, S_SHM_WRITE, -1);
- *nOfChars = nCharsConversion;
- for(i = 0; i<nCharsConversion; i++) {
- convBuffer[i] = conversionBuffer[i];
- }
- sysvSemop(semId, S_SHM_READ, 1);
- /* Koncze w warunkach jak wyżej */
- } while (nOfCharsRead > 0);
- }
- void task3() {
- /* Tworże bufor i ustawiam obsługę sygnałów jak w poprzednich procesach */
- char recivedBuffer[ROZMIAR_BUFORA_KONWERSJI];
- char lineBuffer[100];
- fprintf(stderr, "proces 3 uruchamia sie\n");
- long lengthToPrint = 0;
- sysvSemop(semId, S_PIDS_READ, -1);
- int i;
- int nCharsInPrintingBuffer = 0;
- signal(SIGNAL1, normalSigHandler);
- signal(SIGNAL2, normalSigHandler);
- signal(SIGNAL3, normalSigHandler);
- signal(SIGNAL4, comunicationSigHandler);
- do {
- /* Odczytuję długość bufora przekazaną przez proces 2 oraz znaki powstale w wyniku konwersji. Odczyt synchronizuję przy użycoiu semaforów*/
- sysvSemop(semId, S_SHM_READ, -1);
- lengthToPrint = *nOfChars;
- for(i = 0; i<lengthToPrint; i++) {
- recivedBuffer[i] = convBuffer[i];
- }
- sysvSemop(semId, S_SHM_WRITE, 1);
- /* Wypisuję dane zgodnie ze specyfikacją */
- for(int i = 0; i < lengthToPrint/2; i++) {
- if(nCharsInPrintingBuffer == 0) {
- lineBuffer[0] = 0;
- }
- lineBuffer[3*nCharsInPrintingBuffer] = recivedBuffer[2*i];
- lineBuffer[3*nCharsInPrintingBuffer + 1] = recivedBuffer[2*i + 1];
- lineBuffer[3*nCharsInPrintingBuffer + 2] = ' ';
- nCharsInPrintingBuffer++;
- if(nCharsInPrintingBuffer >= N_W_LINII ) {
- lineBuffer[3*nCharsInPrintingBuffer] = '\n';
- lineBuffer[3*nCharsInPrintingBuffer + 1] = '\0';
- writeFifo(1, lineBuffer, 3*nCharsInPrintingBuffer +1);
- nCharsInPrintingBuffer = 0;
- lineBuffer[0] = 0;
- }
- }
- if(lengthToPrint == 0) {
- lineBuffer[3*nCharsInPrintingBuffer] = '\n';
- lineBuffer[3*nCharsInPrintingBuffer + 1] = '\0';
- writeFifo(1, lineBuffer, 3*nCharsInPrintingBuffer +1);
- }
- /* Warunek końca taki sam jak ostatnio */
- } while(lengthToPrint > 0);
- }
- /* Działanie opisane przy prototypie */
- void normalSigHandler(int signum) {
- fprintf(stderr, "Odebraalem normalny sygnal %d\n", signum);
- int myPid = getpid();
- if(signum != lastSigCopy) {
- sysvSemop(semId, S_LAST_SIG_WRITE, -2);
- *lastSig = signum;
- if(myPid != pids[0]) {
- fprintf(stderr, "Wysylam S4 do P1\n");
- sysvSemop(semId, S_LAST_SIG_R1, 1);
- kill(pids[0], SIGNAL4);
- }
- if(myPid != pids[1]) {
- fprintf(stderr, "Wysylam S4 do P2\n");
- sysvSemop(semId, S_LAST_SIG_R2, 1);
- kill(pids[1], SIGNAL4);
- }
- if(myPid != pids[2]) {
- fprintf(stderr, "Wysylam S4 do P3\n");
- sysvSemop(semId, S_LAST_SIG_R3, 1);
- kill(pids[2], SIGNAL4);
- }
- }
- lastSigCopy = signum;
- reactToSignal(signum);
- }
- /* Działanie opisane przy prototypie */
- void comunicationSigHandler(int signum) {
- int myPid = getpid();
- if(myPid == pids[0]) {
- sysvSemop(semId, S_LAST_SIG_R1, -1);
- } else if(myPid == pids[1]) {
- sysvSemop(semId, S_LAST_SIG_R2, -1);
- } else {
- sysvSemop(semId, S_LAST_SIG_R3, -1);
- }
- lastSigCopy = *lastSig;
- sysvSemop(semId, S_LAST_SIG_WRITE, 1);
- fprintf(stderr, "Odebralem sygnal %d przez pamiec dizelona\n", lastSigCopy);
- reactToSignal(lastSigCopy);
- }
- /* Działanie opisane przy prototypie */
- void reactToSignal(int signum) {
- switch (signum)
- {
- case SIGNAL1:
- exit(0);
- break;
- case SIGNAL2:
- sigsuspend(&sigsuspendMask);
- break;
- default:
- break;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement