Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/ipc.h>
- #include <sys/shm.h>
- #include <sys/sem.h>
- #include <fcntl.h>
- #include <string.h>
- #include <signal.h>
- #include <unistd.h>
- #include <errno.h>
- //#define _DEBUG
- #define BUFSIZE 200
- #define ODCZYT 0
- #define ZAPIS 1
- // numery semaforów w zbiorze
- const char *fnames[4] = { "", "fifo1", "fifo2", "fifo3" };
- typedef struct
- {
- int pid[4];
- char buf12[BUFSIZE];
- char buf23[BUFSIZE];
- } mem;
- mem *ptr;
- int shmid;
- int sem12, sem23;
- enum { PRACUJ, CZEKAJ, INIT } stan;
- static void get_sig(int signo)
- {
- // należy sprawdzić, czy nie jest to pierwsze budenie dzieci ze ¶pi±czki po urodzeniu
- // w takim wypadku nic nie musimy dalej robić
- if (stan == INIT)
- {
- stan = PRACUJ;
- return;
- }
- int pnr;
- int fs;
- int _pid = getpid();
- for (pnr = 1; _pid != ptr->pid[pnr] && pnr <= 3; ++pnr);
- // ponieważ procedura obsługi sygnałów jest taka sama dla wszystkich procesów
- // należy sprawdzić z którym z nich mamy do czynenia
- if (pnr == 4)
- {
- printf("porażka\n");
- exit(1);
- }
- #ifdef _DEBUG
- printf("%d: Otrzymałem sygnał %d\n", pnr, signo);
- #endif
- // je¶li przyszedł sygnał od operatora
- if (signo != SIGUSR2)
- {
- int i;
- for (i = 1; i <= 3; ++i)
- // każdemu z rodzeństwa (oprócz sobie) wysyłam komunikat
- if (i != pnr)
- {
- kill(ptr->pid[i], SIGUSR2);
- #ifdef _DEBUG
- printf("%d: Wysłałem sygnał %d do procesu %d\n", pnr, SIGUSR2, i);
- #endif
- int f = open(fnames[i], O_WRONLY);
- write(f, &signo, sizeof(signo));
- close(f);
- #ifdef _DEBUG
- printf("%d: Zapisałem sygnał %d do kolejki %s\n", pnr, signo, fnames[i]);
- #endif
- }
- }
- else
- {
- // sygnał od rodzeństwa
- #ifdef _DEBUG
- printf("%d: Prubuję odczytać sygnał ze swojej kolejki\n", pnr);
- #endif
- fs = open(fnames[pnr], O_RDONLY);
- read(fs, &signo, sizeof(signo));
- close(fs);
- #ifdef _DEBUG
- printf("%d: Odczytałem sygnał %d ze swojej kolejki\n", pnr, signo);
- #endif
- }
- #ifdef _DEBUG
- printf("%d: Podejmuję stosowne działania zwi±zane z sygnałem %d\n", pnr, signo);
- #endif
- // każdy proces podejmie teraz akcje zwi±zane z sygnałem wsyłanym przez operatora
- if (signo == SIGINT)
- {
- // poniższe zasoby może posprz±tać tylko jeden proces
- if (pnr == 1)
- {
- shmctl(shmid, IPC_RMID, 0);
- semctl(sem12, IPC_RMID, 0);
- semctl(sem23, IPC_RMID, 0);
- }
- // kolejkę fifo każdy proces usuwa sobie sam
- unlink(fnames[pnr]);
- exit(0);
- }
- else if (signo == SIGUSR1)
- {
- stan = CZEKAJ;
- }
- else if (signo == SIGCONT)
- {
- stan = PRACUJ;
- }
- }
- void wait4pids()
- {
- pause();
- // tu dzieci czekaj± na urodzenie ich wszystkich,
- // wpisanie imion i zabicie
- ptr = (mem *)shmat(shmid, NULL, 0);
- if (! ptr)
- {
- printf("bł±d shmat\n");
- exit(1);
- }
- #ifdef _DEBUG
- printf("?: pids: %d, %d, %d, %d\n",
- ptr->pid[0], ptr->pid[1], ptr->pid[2], ptr->pid[3]);
- #endif
- }
- void sem_down(int semid, int semnum)
- {
- struct sembuf op;
- op.sem_flg = 0;
- op.sem_num = semnum; // numer semafora: 0 do odczytu, 1 do zapisu
- op.sem_op = -1; // kierunek i warto¶ć: -1 o jedno w dół
- do
- {
- errno = 0;
- semop(semid, &op, 1);
- }
- while (errno == EINTR);
- // powodem przekroczenia opuszczonego semafora może być otrzymanie sygnału
- // w takim przypadku proces powinien wrócić przed semafor
- }
- void sem_up(int semid, int semnum)
- {
- struct sembuf op;
- op.sem_flg = 0;
- op.sem_num = semnum;
- op.sem_op = 1;
- semop(semid, &op, 1);
- }
- void proces1()
- {
- wait4pids();
- char buf[BUFSIZE];
- while (fgets(buf, sizeof(buf), stdin) > 0)
- {
- while (stan == CZEKAJ)
- pause();
- sem_down(sem12, ZAPIS);
- // opuszczamy semafor synchronizuj±cy zapis
- #ifdef _DEBUG
- printf("1: wychodzę zza semafora\n");
- #endif
- // kopiujemy
- strncpy(ptr->buf12, buf, sizeof(ptr->buf12));
- // strncpy(dok±d, sk±d, ile_najwięcej)
- sem_up(sem12, ODCZYT);
- // podnosimy semafor synchronizuj±cy odczyt
- usleep(300000);
- }
- get_sig(SIGINT);
- }
- void rot13(char *a)
- {
- for (; *a; *a = (*a - 1 / (~(~(*a) | 32) / 13 * 2 - 11) * 13), a++);
- // znalazłem na wiki i ciut przerobiłem :)
- }
- void proces2(void)
- {
- wait4pids();
- char buf[BUFSIZE];
- #ifdef _DEBUG
- int c = 1000;
- #endif
- do
- {
- sem_down(sem12, ODCZYT);
- // opuszczamy semafor synchronizuj±cy odczyt (komunikacja 1->2)
- #ifdef _DEBUG
- printf("2: wychodzę zza semafora\n");
- #endif
- strncpy(buf, ptr->buf12, sizeof(buf));
- sem_up(sem12, ZAPIS);
- // podnosimy semafor synchronizuj±cy zapis (komunikacja 1->2)
- rot13(buf);
- // wykonujemy proste kodowanie
- sem_down(sem23, ZAPIS);
- // opuszczamy semafor synchronizuj±cy zapis (komunikacja 2->3)
- strncpy(ptr->buf23, buf, sizeof(ptr->buf23));
- sem_up(sem23, ODCZYT);
- // podnosimy semafor synchronizuj±cy odczyt (komunikacja 2->3)
- #ifdef _DEBUG
- } while (--c);
- #else
- } while (1);
- #endif
- }
- void proces3(void)
- {
- wait4pids();
- char buf[BUFSIZE];
- #ifdef _DEBUG
- int c = 1000;
- #endif
- do
- {
- sem_down(sem23, ODCZYT);
- // opuszczamy semafor synchronizuj±cy odczyt (komunikacja 2->3)
- #ifdef _DEBUG
- printf("3: wychodzę zza semafora\n");
- #endif
- strncpy(buf, ptr->buf23, sizeof(buf));
- sem_up(sem23, ZAPIS);
- // podnosimy semafor synchronizuj±cy zapis (komunikacja 2->3)
- printf(buf);
- #ifdef _DEBUG
- } while (--c);
- #else
- } while (1);
- #endif
- }
- int main(int argc, char *argv[])
- {
- shmid = shmget(IPC_PRIVATE, sizeof(mem), 0644);
- ptr = (mem *)shmat(shmid, NULL, 0);
- // ptr to wskaĽnik na strukturę mem, gdzie będzie wszystko
- // pidy rodzeństwa oraz dwa bufory do transmisji (patrz pocz±tek pliku)
- if (! ptr)
- {
- printf("Bł±d shmat\n");
- return 1;
- }
- sem12 = semget(IPC_PRIVATE, 2, 0644);
- // po dwa semafory dla każdej transmisji 1->2 i 2->3
- sem23 = semget(IPC_PRIVATE, 2, 0644);
- // semafor o indeksie 0 będzie synchronizował odczyt
- // semafor o indeksie 1 będzie synchronizował zapis
- semctl(sem12, 0, SETVAL, 0);
- // semafor do odczytu przy transmisji 1->2 inicjujemy 0
- semctl(sem12, 1, SETVAL, 1);
- // semafor do zapisu przy transmisji 1->2 inicjujemy 1
- semctl(sem23, 0, SETVAL, 0);
- // analogicznie
- semctl(sem23, 1, SETVAL, 1);
- // analogicznie
- mkfifo(fnames[1], 0644);
- mkfifo(fnames[2], 0644);
- mkfifo(fnames[3], 0644);
- // po jednej kolejce na proces
- signal(SIGUSR1, get_sig);
- signal(SIGUSR2, get_sig);
- signal(SIGINT, get_sig);
- signal(SIGCONT, get_sig);
- // przejęcie obsługi sygnałów propaguje się na wszystkie dzieci
- ptr->pid[0] = getpid();
- stan = INIT;
- int i, pid[4];
- if ((pid[1] = fork()) == 0)
- proces1();
- else if ((pid[2] = fork()) == 0)
- proces2();
- else if ((pid[3] = fork()) == 0)
- proces3();
- else
- {
- for (i = 1; i <= 3; ptr->pid[i] = pid[i], i++)
- if (pid[1] < 0)
- return 1;
- #ifdef _DEBUG
- printf("0: pids: %d, %d, %d, %d\n",
- ptr->pid[0], ptr->pid[1], ptr->pid[2], ptr->pid[3]);
- #endif
- /* Rodzic w momencie robienia pierwszego dziecka nie wie jak będ± się
- * nazywały kolejne (pid), więc nie może mu tego powiedzieć, ale jako¶ musi
- * (żeby dzieci mogły ze sob± rozmawiać musz± wiedzieć jak się nazywaj±).
- * Dlatego wszystkie imiona l±duj± we wspólnej pamięci, a każde dziecko
- * po urodzeniu się zapada w ¶pi±czkę (pause) i czeka aż urodzone zostan±
- * wszystkie inne i nadane im zostan± imiona. Wtedy rodzic zabija wszystkie
- * swoje dzieci (kill), ale te nie gin± bo rodzic zarejestrował procedurę
- * obsługi sygnałów, która przeniosła się na dzieci. Dzieci się budz±,
- * odczytuj± swoje imiona, a rodzic może spokojnie dokończyć żywota.
- */
- kill(ptr->pid[1], SIGINT);
- kill(ptr->pid[2], SIGINT);
- kill(ptr->pid[3], SIGINT);
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement