├── .gitignore ├── 01. Memory management. Libraries. Time measurement ├── README.md ├── zad1i2 │ ├── Makefile │ ├── main.c │ ├── mylib.c │ └── mylib.h └── zad3 │ ├── a │ ├── Makefile │ ├── main.c │ ├── main_dynamic.c │ ├── mylib.c │ └── mylib.h │ └── b │ ├── Makefile │ ├── main.c │ ├── main_dynamic.c │ ├── mylib.c │ └── mylib.h ├── 02. File system. File operations ├── README.md ├── zad1 │ ├── Makefile │ ├── main.c │ ├── records.txt │ ├── records2.txt │ ├── records3.txt │ ├── wnioski.txt │ └── wyniki.txt └── zad2 │ ├── Makefile │ └── main.c ├── 03. Creating processes. Process environment, process control ├── README.md ├── zad1 │ ├── Makefile │ └── main.c ├── zad2 │ ├── Makefile │ ├── lista.txt │ ├── monitor.c │ └── tester.c └── zad3 │ ├── Makefile │ ├── lista.txt │ └── main.c ├── 04. Signals ├── README.md ├── zad1 │ ├── date.sh │ ├── main.c │ └── makefile ├── zad2 │ ├── Makefile │ ├── lista.txt │ ├── main.c │ └── tester.c └── zad3 │ ├── a │ ├── catcher.c │ ├── makefile │ └── sender.c │ └── b │ ├── catcher.c │ ├── makefile │ └── sender.c ├── 05. Inter-process communication(pipeline) ├── README.md ├── zad1 │ ├── commands.txt │ ├── main.c │ ├── makefile │ └── sample.txt ├── zad2 │ ├── makefile │ ├── master.c │ └── slave.c └── zajecia.c ├── 06. Inter-process communication(queue message) ├── README.md ├── zad1 │ ├── client.c │ ├── commands.h │ ├── commands.txt │ ├── makefile │ └── server.c └── zad2 │ ├── client.c │ ├── commands.h │ ├── commands.txt │ ├── makefile │ ├── server.c │ └── server.o ├── 07. Inter-process communication(semaphore) ├── README.md ├── zad1 │ ├── loader.c │ ├── makefile │ ├── shared_utils.h │ └── trucker.c └── zad2 │ ├── loader.c │ ├── makefile │ ├── shared_utils.h │ └── trucker.c ├── 08. Threads - image filtering ├── README.md ├── Times.txt ├── apple.jpeg ├── apple.pgm ├── apple_res.pgm ├── blurry_c3.txt ├── contours_c3.txt ├── contrast_c5.txt ├── distorted_c3.txt ├── filter_c40.txt ├── main.c ├── makefile └── sharpness_c3.txt ├── 09. Threads - synchronization methods ├── README.md ├── main.c └── makefile ├── 10. Network sockets ├── README.md └── zad1 │ ├── client.c │ ├── lib.c │ ├── lib.h │ ├── makefile │ ├── server.c │ ├── text1.txt │ ├── text2.txt │ └── text3.txt └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | */*.o 2 | */main 3 | */*.exe -------------------------------------------------------------------------------- /01. Memory management. Libraries. Time measurement/README.md: -------------------------------------------------------------------------------- 1 | # Zadanie 1. Alokacja tablicy z wskaźnikami na bloki pamięci zawierające znaki (25%) 2 | 3 | Zaprojektuj i przygotuj zestaw funkcji (bibliotekę) do zarządzania tablicą bloków, w których to blokach pamięci zapisywane są rezultaty operacji 4 | 5 | przeglądania (poleceniem find) katalogów przekazywanych jako odpowiedni parametr w poszukiwaniu plików o nazwie podanych jako kolejny parametr funkcji 6 | 7 | Biblioteka powinna umożliwiać: 8 | 9 | - utworzenie tablicy wskaźników w której będą przechowywane wskaźniki na bloki pamięci zawierające wyniki przeszukiwań, 10 | 11 | - ustawienie aktualnie przeszukiwanego katalogu oraz poszukiwanego pliku, 12 | 13 | - przeprowadzenie przeszukania tego katalogu i zapisanie wyniku poszukiwania w pliku tymczasowym 14 | 15 | - zarezerwowanie bloku pamięci o rozmiarze odpowiadającym rozmiarowi pliku tymczasowego i zapisanie w tej pamięci jego zawartości, ustawienie w tablicy wskaźników wskazania na ten blok, funkcja powinna zwrócić indeks stworzonego bloku w tablicy, 16 | 17 | - usunięcie z pamięci bloku o zadanym indeksie 18 | 19 | Tablice i bloki powinny być alokowane przy pomocy funkcji calloc (alokacja dynamiczna). 20 | 21 | Przygotuj plik Makefile, zawierający polecenia kompilujące pliki źródłowe biblioteki oraz tworzące biblioteki w dwóch wersjach: statyczną i współdzieloną. 22 | 23 | # 2. Program korzystający z biblioteki (25%) 24 | 25 | Napisz program testujący działanie funkcji z biblioteki z zadania 1. 26 | 27 | Jako argumenty przekaż liczbę elementów tablicy oraz listę zadań do wykonania. Zadania mogą stanowić zadania przeszukania katalogów, opisane przez listę (katalog, poszukiwany plik) lub zadania usunięcia bloku o podanym indeksie. 28 | 29 | Operacje mogą być specyfikowane w linii poleceń na przykład jak poniżej: 30 | 31 | * create_table rozmiar - stworzenie tablicy o rozmiarze "rozmiar" 32 | * search_directory dir file name_file_temp - wyszukanie pliku o nazwie file w katalogu dir i zapisanie wyjścia polecenia find w pliku name_file_temp 33 | * remove_block index - usuń z tablicy bloków o indeksie index 34 | 35 | Program powinien stworzyć tablice bloków o zadanej liczbie elementów 36 | 37 | W programie zmierz, wypisz na konsolę i zapisz do pliku z raportem czasy realizacji podstawowych operacji: 38 | 39 | - przeprowadzenie przeszukania katalogów o różnych poziomach zagłębień i różnych liczbach zawartych plików (omownie - dla zawierającego mało, średnią liczbę i dużo plików i podkatalogów) 40 | 41 | - zapisanie w pamięci bloków o różnych rozmiarach (odpowiadających rozmiarom różnych przeprowadzonych przeszukiwań) 42 | 43 | - usunięcie zaalokowanych bloków o różnych rozmiarach (odpowiadających rozmiarom różnych przeprowadzonych przeszukiwań) 44 | 45 | - na przemian kilkakrotne dodanie i usunięcie zadanej liczby bloków 46 | 47 | Mierząc czasy poszczególnych operacji zapisz trzy wartości: czas rzeczywisty, czas użytkownika i czas systemowy. Rezultaty umieść pliku raport2.txt i dołącz do archiwum zadania. 48 | 49 | # Zadanie 3. Testy i pomiary (50%) 50 | 51 | #### a) (25%) Przygotuj plik Makefile, zawierający polecenia kompilujące program z zad 2 na trzy sposoby: 52 | - z wykorzystaniem bibliotek statycznych, 53 | - z wykorzystaniem bibliotek dzielonych (dynamiczne, ładowane przy uruchomieniu programu), 54 | - z wykorzystaniem bibliotek ładowanych dynamicznie (dynamiczne, ładowane przez program), 55 | oraz uruchamiający testy. 56 | 57 | Wyniki pomiarów zbierz w pliku results3a.txt. Otrzymane wyniki krótko skomentuj. 58 | 59 | #### b) (25%) Rozszerz plik Makefile z punktu 3a) dodając możliwość skompilowania programu na trzech różnych poziomach optymalizacji -O0...-Os. Przeprowadź ponownie pomiary kompilując i uruchamiając program dla rożnych poziomów optymalizacji. 60 | 61 | Wyniki pomiarów dodaj do pliku results3b.txt. Otrzymane wyniki krotko skomentuj. 62 | 63 | Wygenerowane pliki z raportami załącz jako element rozwiązania. 64 | 65 | Uwaga: Do odczytania pliku można użyć funkcji read (man read), do wywołania zewnętrznego polecenia Unixa można użyć funkcji system (man system). 66 | -------------------------------------------------------------------------------- /01. Memory management. Libraries. Time measurement/zad1i2/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc -Wall 2 | 3 | static: 4 | make clean 5 | $(CC) -c mylib.c 6 | ar crs libmylib.a mylib.o 7 | $(CC) main.c -o main -L. -lmylib 8 | 9 | shared: 10 | make clean 11 | $(CC) -fPIC -c mylib.c 12 | $(CC) -shared -fPIC -o libmylib.so mylib.o 13 | $(CC) main.c -o main -L. -lmylib -Wl,-rpath=`pwd` 14 | 15 | clean: 16 | rm -f *.o 17 | rm -f *.a 18 | rm -f *.so 19 | rm -f main 20 | rm -f *.txt 21 | 22 | run: 23 | @echo -------Small------- 24 | ./main 4 create_table 2 search_directory ../ '*' my1_1.txt remove_block 1 remove_block 0 25 | ./main 5 create_table 5 search_directory ../ '*' my1_2.txt remove_block 0 remove_block 1 remove_block 2 26 | 27 | @echo -------Medium------- 28 | ./main 4 create_table 2 search_directory ../../../ '*' my2_1.txt remove_block 1 remove_block 0 29 | ./main 5 create_table 5 search_directory ../../../ '*' my2_2.txt remove_block 0 remove_block 1 remove_block 2 30 | 31 | @echo -------Large------- 32 | ./main 4 create_table 2 search_directory /lib '*' my3_1.txt remove_block 1 remove_block 0 33 | ./main 5 create_table 5 search_directory / '*' my3_2.txt 2> error.txt remove_block 0 remove_block 1 remove_block 2 34 | 35 | -------------------------------------------------------------------------------- /01. Memory management. Libraries. Time measurement/zad1i2/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "mylib.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | FILE * resultFile; 12 | 13 | void error(char * msg){ 14 | printf("%s", msg); 15 | exit(0); 16 | } 17 | 18 | double timeDifference(clock_t t1, clock_t t2){ 19 | return ((double)(t2 - t1) / sysconf(_SC_CLK_TCK)); 20 | } 21 | 22 | void writeResult(clock_t start, clock_t end, struct tms* t_start, struct tms* t_end){ 23 | printf("\tREAL_TIME: %fl\n", timeDifference(start,end)); 24 | printf("\tUSER_TIME: %fl\n", timeDifference(t_start->tms_utime, t_end->tms_utime)); 25 | printf("\tSYSTEM_TIME: %fl\n", timeDifference(t_start->tms_stime, t_end->tms_stime)); 26 | 27 | fprintf(resultFile, "\tREAL_TIME: %fl\n", timeDifference(start, end)); 28 | fprintf(resultFile, "\tUSER_TIME: %fl\n", timeDifference(t_start->tms_utime, t_end->tms_utime)); 29 | fprintf(resultFile, "\tSYSTEM_TIME: %fl\n", timeDifference(t_start->tms_stime, t_end->tms_stime)); 30 | } 31 | 32 | int main(int argc, char **argv) { 33 | int i; 34 | int size = argc; 35 | resultFile = fopen("./raport2.txt", "a"); 36 | struct tms * tms[size]; 37 | clock_t time[size]; 38 | for(i = 0; i < size; i++){ 39 | tms[i] = calloc(1, sizeof(struct tms *)); 40 | time[i] = 0; 41 | } 42 | 43 | if(argc < 2) 44 | error("Bad argument"); 45 | int current = 0; 46 | struct Block temp; 47 | struct ArrayOfBlocks myBlocks; 48 | int index; 49 | for(i=2; i 2 | #include "mylib.h" 3 | 4 | int size = 140; 5 | 6 | struct ArrayOfBlocks createArrayOfBlocks(int size){ 7 | struct ArrayOfBlocks array; 8 | 9 | array.arrayOfBlocks = (struct Block*) calloc(size, sizeof(struct Block)); 10 | array.index = -1; 11 | 12 | return array; 13 | }; 14 | 15 | struct Block setDirectoryAndFile(char *dir, char *file){ 16 | struct Block newBlock; 17 | newBlock.dir = (char*) calloc(strlen(dir), sizeof(char)); 18 | strcpy(newBlock.dir, dir); 19 | newBlock.file = (char*) calloc(strlen(file), sizeof(char)); 20 | strcpy(newBlock.file, file); 21 | 22 | return newBlock; 23 | }; 24 | 25 | struct Block find(struct Block newBlock, char* name){ 26 | char * command = calloc(size, sizeof(char)); 27 | int i; 28 | for(i = 0; i < size; ++i){ 29 | command[i] = 0; 30 | } 31 | strcpy(command, "find "); 32 | strcat(command, newBlock.dir); 33 | strcat(command, " -type f -name '"); 34 | strcat(command, newBlock.file); 35 | strcat(command, "' > "); 36 | strcat(command, name); 37 | 38 | system(command); 39 | 40 | FILE *f = fopen(name, "r"); 41 | if (f == NULL) 42 | { 43 | perror("Cannot open file"); 44 | exit(1); 45 | } 46 | 47 | fseek(f, 0, SEEK_END); 48 | long fileSize = ftell(f); 49 | fseek(f, 0, SEEK_SET); 50 | 51 | char ch; 52 | char * result = (char*) calloc((size_t) fileSize, sizeof(char)); 53 | 54 | i=0; 55 | while(!feof(f)) { 56 | if((ch = (char) fgetc(f)) != -1){ 57 | result[i++] = ch; 58 | } 59 | } 60 | result[i] = '\0'; 61 | 62 | newBlock.table = (char*) calloc(strlen(result), sizeof(char)); 63 | strcpy(newBlock.table, result); 64 | free(result); 65 | fclose(f); 66 | 67 | return newBlock; 68 | }; 69 | 70 | int addToArrayOfBlocks(struct ArrayOfBlocks arrayOfBlocks, struct Block newBlock){ 71 | arrayOfBlocks.arrayOfBlocks[arrayOfBlocks.index+1] = newBlock; 72 | return arrayOfBlocks.index+1; 73 | }; 74 | 75 | void removeBlock(struct ArrayOfBlocks arrayOfBlocks, int index){ 76 | free(arrayOfBlocks.arrayOfBlocks[index].table); 77 | free(arrayOfBlocks.arrayOfBlocks[index].file); 78 | free(arrayOfBlocks.arrayOfBlocks[index].dir); 79 | }; 80 | 81 | int isNumber(char* s) 82 | { 83 | int i; 84 | for (i = 0; i < strlen(s); i++) 85 | if (!isdigit(s[i])) 86 | return 0; 87 | return 1; 88 | } 89 | -------------------------------------------------------------------------------- /01. Memory management. Libraries. Time measurement/zad1i2/mylib.h: -------------------------------------------------------------------------------- 1 | #ifndef mylib_h 2 | #define mylib_h 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct ArrayOfBlocks{ 9 | int index; 10 | struct Block *arrayOfBlocks; 11 | }; 12 | 13 | struct Block{ 14 | char *dir; 15 | char *file; 16 | char *table; 17 | }; 18 | 19 | struct ArrayOfBlocks createArrayOfBlocks(int size); 20 | struct Block setDirectoryAndFile(char *dir, char *file); 21 | struct Block find(struct Block newBlock, char *name); 22 | int addToArrayOfBlocks(struct ArrayOfBlocks arrayOfBlocks, struct Block newBlock); 23 | void removeBlock(struct ArrayOfBlocks arrayOfBlocks, int index); 24 | int isNumber(char* s); 25 | 26 | #endif //mylib_h 27 | -------------------------------------------------------------------------------- /01. Memory management. Libraries. Time measurement/zad3/a/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc -Wall 2 | 3 | static: 4 | make clean 5 | $(CC) -c mylib.c 6 | ar crs libmylib.a mylib.o 7 | $(CC) main.c -o main -L. -lmylib 8 | 9 | shared: 10 | make clean 11 | $(CC) -fPIC -c mylib.c 12 | $(CC) -shared -fPIC -o libmylib.so mylib.o 13 | $(CC) main.c -o main -L. -lmylib -Wl,-rpath=`pwd` 14 | 15 | dynamic: 16 | make clean 17 | $(CC) -fPIC -c mylib.c -o mylib.o 18 | $(CC) -Wl,-rpath=. -fPIC -shared -o libmylib.so mylib.o 19 | $(CC) -fPIC -L. -o main main_dynamic.c -ldl -D DYNAMIC 20 | 21 | clean: 22 | rm -f *.so 23 | rm -f *.o 24 | rm -f *.a 25 | rm -f *.txt 26 | rm -f main 27 | rm -f main_dynamic 28 | 29 | run: 30 | ./main 4 create_table 2 search_directory ../ '*' my1_1.txt remove_block 1 remove_block 0 31 | ./main 5 create_table 5 search_directory ../ '*' my1_2.txt remove_block 0 remove_block 1 remove_block 2 32 | 33 | ./main 4 create_table 2 search_directory ../../../ '*' my2_1.txt remove_block 1 remove_block 0 34 | ./main 5 create_table 5 search_directory ../../../ '*' my2_2.txt remove_block 0 remove_block 1 remove_block 2 35 | 36 | ./main 4 create_table 2 search_directory /lib '*' my3_1.txt remove_block 1 remove_block 0 37 | ./main 5 create_table 5 search_directory / '*' my3_2.txt 2> error.txt remove_block 0 remove_block 1 remove_block 2 38 | -------------------------------------------------------------------------------- /01. Memory management. Libraries. Time measurement/zad3/a/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "mylib.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | FILE * resultFile; 12 | 13 | void error(char * msg){ 14 | printf("%s", msg); 15 | exit(0); 16 | } 17 | 18 | double timeDifference(clock_t t1, clock_t t2){ 19 | return ((double)(t2 - t1) / sysconf(_SC_CLK_TCK)); 20 | } 21 | 22 | void writeResultToTerminalAndFile(clock_t start, clock_t end, struct tms* t_start, struct tms* t_end){ 23 | printf("\tREAL_TIME: %fl\n", timeDifference(start,end)); 24 | printf("\tUSER_TIME: %fl\n", timeDifference(t_start->tms_utime, t_end->tms_utime)); 25 | printf("\tSYSTEM_TIME: %fl\n", timeDifference(t_start->tms_stime, t_end->tms_stime)); 26 | 27 | fprintf(resultFile, "\tREAL_TIME: %fl\n", timeDifference(start, end)); 28 | fprintf(resultFile, "\tUSER_TIME: %fl\n", timeDifference(t_start->tms_utime, t_end->tms_utime)); 29 | fprintf(resultFile, "\tSYSTEM_TIME: %fl\n", timeDifference(t_start->tms_stime, t_end->tms_stime)); 30 | } 31 | 32 | int main(int argc, char **argv) { 33 | int i; 34 | int size = argc; 35 | resultFile = fopen("./results3b.txt", "a"); 36 | struct tms * tms[size]; 37 | clock_t time[size]; 38 | for(i = 0; i < size; i++){ 39 | tms[i] = calloc(1, sizeof(struct tms *)); 40 | time[i] = 0; 41 | } 42 | 43 | if(argc < 2) 44 | error("Bad argument"); 45 | int current = 0; 46 | struct Block temp; 47 | struct ArrayOfBlocks myBlocks; 48 | int index; 49 | for(i=2; i 2 | #include 3 | #include 4 | #include 5 | #include "mylib.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | FILE * resultFile; 12 | 13 | void error(char * msg){ 14 | printf("%s", msg); 15 | fprintf(resultFile, "%s", msg); 16 | exit(0); 17 | } 18 | 19 | void libError(char * msg){ 20 | printf("%s\n", msg); 21 | fprintf(resultFile, "%s\n", dlerror()); 22 | exit(0); 23 | } 24 | 25 | double timeDifference(clock_t t1, clock_t t2){ 26 | return ((double)(t2 - t1) / sysconf(_SC_CLK_TCK)); 27 | } 28 | 29 | void writeResult(clock_t start, clock_t end, struct tms* t_start, struct tms* t_end){ 30 | printf("\tREAL_TIME: %fl\n", timeDifference(start,end)); 31 | printf("\tUSER_TIME: %fl\n", timeDifference(t_start->tms_utime, t_end->tms_utime)); 32 | printf("\tSYSTEM_TIME: %fl\n", timeDifference(t_start->tms_stime, t_end->tms_stime)); 33 | 34 | fprintf(resultFile, "\tREAL_TIME: %fl\n", timeDifference(start, end)); 35 | fprintf(resultFile, "\tUSER_TIME: %fl\n", timeDifference(t_start->tms_utime, t_end->tms_utime)); 36 | fprintf(resultFile, "\tSYSTEM_TIME: %fl\n", timeDifference(t_start->tms_stime, t_end->tms_stime)); 37 | } 38 | 39 | int main(int argc, char **argv) { 40 | void *handle = dlopen("./libmylib.so",RTLD_LAZY); 41 | if(!handle){ 42 | libError("Open error"); 43 | } 44 | int i; 45 | int size = argc; 46 | resultFile = fopen("./results3a.txt", "a"); 47 | struct tms * tms[size]; 48 | clock_t time[size]; 49 | for(i = 0; i < size; i++){ 50 | tms[i] = calloc(1, sizeof(struct tms *)); 51 | time[i] = 0; 52 | } 53 | 54 | if(argc < 2) 55 | error("Bad argument"); 56 | int current = 0; 57 | struct Block temp; 58 | struct ArrayOfBlocks myBlocks; 59 | int index; 60 | 61 | struct ArrayOfBlocks (*createArrayOfBlocks)() = (struct ArrayOfBlocks (*)())dlsym(handle, "createArrayOfBlocks"); 62 | struct Block (*setDirectoryAndFile)() = (struct Block (*)())dlsym(handle, "setDirectoryAndFile"); 63 | struct Block (*find)() = (struct Block (*)())dlsym(handle, "find"); 64 | int (*addToArrayOfBlocks)() = (int (*)())dlsym(handle, "addToArrayOfBlocks"); 65 | void (*removeBlock)() = (void (*)())dlsym(handle, "removeBlock"); 66 | int (*isNumber)() = (int (*)())dlsym(handle, "isNumber"); 67 | 68 | for(i=2; i 2 | #include "mylib.h" 3 | 4 | struct ArrayOfBlocks createArrayOfBlocks(int size){ 5 | struct ArrayOfBlocks array; 6 | 7 | array.arrayOfBlocks = (struct Block*) calloc(size, sizeof(struct Block)); 8 | array.index = -1; 9 | 10 | return array; 11 | }; 12 | 13 | struct Block setDirectoryAndFile(char *dir, char *file){ 14 | struct Block newBlock; 15 | newBlock.dir = (char*) calloc(strlen(dir), sizeof(char)); 16 | strcpy(newBlock.dir, dir); 17 | newBlock.file = (char*) calloc(strlen(file), sizeof(char)); 18 | strcpy(newBlock.file, file); 19 | 20 | return newBlock; 21 | }; 22 | 23 | struct Block find(struct Block newBlock, char* name){ 24 | char command[150]; 25 | strcpy(command, "find "); 26 | strcat(command, newBlock.dir); 27 | strcat(command, " -type f -name '"); 28 | strcat(command, newBlock.file); 29 | strcat(command, "' > "); 30 | strcat(command, name); 31 | 32 | system(command); 33 | 34 | FILE *f = fopen(name, "r"); 35 | if (f == NULL) 36 | { 37 | perror("Nie udalo sie otworzyc pliku"); 38 | exit(1); 39 | } 40 | 41 | fseek(f, 0, SEEK_END); 42 | long fileSize = ftell(f); 43 | fseek(f, 0, SEEK_SET); 44 | 45 | char ch; 46 | char *result = (char*) calloc((size_t) fileSize, sizeof(char)); 47 | int i=0; 48 | 49 | while(!feof(f)) { 50 | if((ch = (char) fgetc(f)) != -1){ 51 | result[i++] = ch; 52 | } 53 | } 54 | result[i] = '\0'; 55 | 56 | newBlock.table = (char*) calloc(strlen(result), sizeof(char)); 57 | strcpy(newBlock.table, result); 58 | free(result); 59 | fclose(f); 60 | 61 | return newBlock; 62 | }; 63 | 64 | int addToArrayOfBlocks(struct ArrayOfBlocks arrayOfBlocks, struct Block newBlock){ 65 | arrayOfBlocks.arrayOfBlocks[arrayOfBlocks.index+1] = newBlock; 66 | 67 | return arrayOfBlocks.index+1; 68 | }; 69 | 70 | void removeBlock(struct ArrayOfBlocks arrayOfBlocks, int index){ 71 | free(arrayOfBlocks.arrayOfBlocks[index].table); 72 | free(arrayOfBlocks.arrayOfBlocks[index].file); 73 | free(arrayOfBlocks.arrayOfBlocks[index].dir); 74 | }; 75 | 76 | int isNumber(char* s) 77 | { 78 | int i; 79 | for (i = 0; i < strlen(s); i++) 80 | if (!isdigit(s[i])) 81 | return 0; 82 | return 1; 83 | } 84 | -------------------------------------------------------------------------------- /01. Memory management. Libraries. Time measurement/zad3/a/mylib.h: -------------------------------------------------------------------------------- 1 | #ifndef mylib_h 2 | #define mylib_h 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct ArrayOfBlocks{ 9 | int index; 10 | struct Block *arrayOfBlocks; 11 | }; 12 | 13 | struct Block{ 14 | char *dir; 15 | char *file; 16 | char *table; 17 | }; 18 | 19 | struct ArrayOfBlocks createArrayOfBlocks(int size); 20 | struct Block setDirectoryAndFile(char *dir, char *file); 21 | struct Block find(struct Block newBlock, char *name); 22 | int addToArrayOfBlocks(struct ArrayOfBlocks arrayOfBlocks, struct Block newBlock); 23 | void removeBlock(struct ArrayOfBlocks arrayOfBlocks, int index); 24 | int isNumber(char* s); 25 | 26 | #endif //mylib_h 27 | -------------------------------------------------------------------------------- /01. Memory management. Libraries. Time measurement/zad3/b/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc -Wall 2 | 3 | static: 4 | make clean 5 | $(CC) -c mylib.c 6 | ar crs libmylib.a mylib.o 7 | $(CC) main.c -o main -L. -lmylib -O1 8 | 9 | shared: 10 | make clean 11 | $(CC) -fPIC -c mylib.c 12 | $(CC) -shared -fPIC -o libmylib.so mylib.o 13 | $(CC) main.c -o main -L. -lmylib -Wl,-rpath=`pwd` -O2 14 | 15 | dynamic: 16 | make clean 17 | $(CC) -fPIC -c mylib.c -o mylib.o 18 | $(CC) -Wl,-rpath=. -fPIC -shared -o libmylib.so mylib.o 19 | $(CC) -fPIC -L. -o main main_dynamic.c -ldl -D DYNAMIC 20 | 21 | clean: 22 | rm -f *.so 23 | rm -f *.o 24 | rm -f *.a 25 | rm -f *.txt 26 | rm -f main 27 | rm -f main_dynamic 28 | 29 | run: 30 | ./main 4 create_table 2 search_directory ../ '*' my1_1.txt remove_block 1 remove_block 0 31 | ./main 5 create_table 5 search_directory ../ '*' my1_2.txt remove_block 0 remove_block 1 remove_block 2 32 | 33 | ./main 4 create_table 2 search_directory ../../../ '*' my2_1.txt remove_block 1 remove_block 0 34 | ./main 5 create_table 5 search_directory ../../../ '*' my2_2.txt remove_block 0 remove_block 1 remove_block 2 35 | 36 | ./main 4 create_table 2 search_directory /lib '*' my3_1.txt remove_block 1 remove_block 0 37 | ./main 5 create_table 5 search_directory / '*' my3_2.txt 2> error.txt remove_block 0 remove_block 1 remove_block 2 38 | -------------------------------------------------------------------------------- /01. Memory management. Libraries. Time measurement/zad3/b/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "mylib.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | FILE * resultFile; 12 | 13 | void error(char * msg){ 14 | printf("%s", msg); 15 | exit(0); 16 | } 17 | 18 | double timeDifference(clock_t t1, clock_t t2){ 19 | return ((double)(t2 - t1) / sysconf(_SC_CLK_TCK)); 20 | } 21 | 22 | void writeResultToTerminalAndFile(clock_t start, clock_t end, struct tms* t_start, struct tms* t_end){ 23 | printf("\tREAL_TIME: %fl\n", timeDifference(start,end)); 24 | printf("\tUSER_TIME: %fl\n", timeDifference(t_start->tms_utime, t_end->tms_utime)); 25 | printf("\tSYSTEM_TIME: %fl\n", timeDifference(t_start->tms_stime, t_end->tms_stime)); 26 | 27 | fprintf(resultFile, "\tREAL_TIME: %fl\n", timeDifference(start, end)); 28 | fprintf(resultFile, "\tUSER_TIME: %fl\n", timeDifference(t_start->tms_utime, t_end->tms_utime)); 29 | fprintf(resultFile, "\tSYSTEM_TIME: %fl\n", timeDifference(t_start->tms_stime, t_end->tms_stime)); 30 | } 31 | 32 | int main(int argc, char **argv) { 33 | int i; 34 | int size = argc; 35 | resultFile = fopen("./results3b.txt", "a"); 36 | struct tms * tms[size]; 37 | clock_t time[size]; 38 | for(i = 0; i < size; i++){ 39 | tms[i] = calloc(1, sizeof(struct tms *)); 40 | time[i] = 0; 41 | } 42 | 43 | if(argc < 2) 44 | error("Bad argument"); 45 | int current = 0; 46 | struct Block temp; 47 | struct ArrayOfBlocks myBlocks; 48 | int index; 49 | for(i=2; i 2 | #include 3 | #include 4 | #include 5 | #include "mylib.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | FILE * resultFile; 12 | 13 | void error(char * msg){ 14 | printf("%s", msg); 15 | fprintf(resultFile, "%s", msg); 16 | exit(0); 17 | } 18 | 19 | void libError(char * msg){ 20 | printf("%s\n", msg); 21 | fprintf(resultFile, "%s\n", dlerror()); 22 | exit(0); 23 | } 24 | 25 | double timeDifference(clock_t t1, clock_t t2){ 26 | return ((double)(t2 - t1) / sysconf(_SC_CLK_TCK)); 27 | } 28 | 29 | void writeResult(clock_t start, clock_t end, struct tms* t_start, struct tms* t_end){ 30 | printf("\tREAL_TIME: %fl\n", timeDifference(start,end)); 31 | printf("\tUSER_TIME: %fl\n", timeDifference(t_start->tms_utime, t_end->tms_utime)); 32 | printf("\tSYSTEM_TIME: %fl\n", timeDifference(t_start->tms_stime, t_end->tms_stime)); 33 | 34 | fprintf(resultFile, "\tREAL_TIME: %fl\n", timeDifference(start, end)); 35 | fprintf(resultFile, "\tUSER_TIME: %fl\n", timeDifference(t_start->tms_utime, t_end->tms_utime)); 36 | fprintf(resultFile, "\tSYSTEM_TIME: %fl\n", timeDifference(t_start->tms_stime, t_end->tms_stime)); 37 | } 38 | 39 | int main(int argc, char **argv) { 40 | void *handle = dlopen("./libmylib.so",RTLD_LAZY); 41 | if(!handle){ 42 | libError("Open error"); 43 | } 44 | int i; 45 | int size = argc; 46 | resultFile = fopen("./results3a.txt", "a"); 47 | struct tms * tms[size]; 48 | clock_t time[size]; 49 | for(i = 0; i < size; i++){ 50 | tms[i] = calloc(1, sizeof(struct tms *)); 51 | time[i] = 0; 52 | } 53 | 54 | if(argc < 2) 55 | error("Bad argument"); 56 | int current = 0; 57 | struct Block temp; 58 | struct ArrayOfBlocks myBlocks; 59 | int index; 60 | 61 | struct ArrayOfBlocks (*createArrayOfBlocks)() = (struct ArrayOfBlocks (*)())dlsym(handle, "createArrayOfBlocks"); 62 | struct Block (*setDirectoryAndFile)() = (struct Block (*)())dlsym(handle, "setDirectoryAndFile"); 63 | struct Block (*find)() = (struct Block (*)())dlsym(handle, "find"); 64 | int (*addToArrayOfBlocks)() = (int (*)())dlsym(handle, "addToArrayOfBlocks"); 65 | void (*removeBlock)() = (void (*)())dlsym(handle, "removeBlock"); 66 | int (*isNumber)() = (int (*)())dlsym(handle, "isNumber"); 67 | 68 | for(i=2; i 2 | #include "mylib.h" 3 | 4 | int size = 140; 5 | 6 | struct ArrayOfBlocks createArrayOfBlocks(int size){ 7 | struct ArrayOfBlocks array; 8 | 9 | array.arrayOfBlocks = (struct Block*) calloc(size, sizeof(struct Block)); 10 | array.index = -1; 11 | 12 | return array; 13 | }; 14 | 15 | struct Block setDirectoryAndFile(char *dir, char *file){ 16 | struct Block newBlock; 17 | newBlock.dir = (char*) calloc(strlen(dir), sizeof(char)); 18 | strcpy(newBlock.dir, dir); 19 | newBlock.file = (char*) calloc(strlen(file), sizeof(char)); 20 | strcpy(newBlock.file, file); 21 | 22 | return newBlock; 23 | }; 24 | 25 | struct Block find(struct Block newBlock, char* name){ 26 | char * command = calloc(size, sizeof(char)); 27 | int i; 28 | for(i = 0; i < size; ++i){ 29 | command[i] = 0; 30 | } 31 | strcpy(command, "find "); 32 | strcat(command, newBlock.dir); 33 | strcat(command, " -type f -name '"); 34 | strcat(command, newBlock.file); 35 | strcat(command, "' > "); 36 | strcat(command, name); 37 | 38 | system(command); 39 | 40 | FILE *f = fopen(name, "r"); 41 | if (f == NULL) 42 | { 43 | perror("Cannot open file"); 44 | exit(1); 45 | } 46 | 47 | fseek(f, 0, SEEK_END); 48 | long fileSize = ftell(f); 49 | fseek(f, 0, SEEK_SET); 50 | 51 | char ch; 52 | char * result = (char*) calloc((size_t) fileSize, sizeof(char)); 53 | 54 | i=0; 55 | while(!feof(f)) { 56 | if((ch = (char) fgetc(f)) != -1){ 57 | result[i++] = ch; 58 | } 59 | } 60 | result[i] = '\0'; 61 | 62 | newBlock.table = (char*) calloc(strlen(result), sizeof(char)); 63 | strcpy(newBlock.table, result); 64 | free(result); 65 | fclose(f); 66 | 67 | return newBlock; 68 | }; 69 | 70 | int addToArrayOfBlocks(struct ArrayOfBlocks arrayOfBlocks, struct Block newBlock){ 71 | arrayOfBlocks.arrayOfBlocks[arrayOfBlocks.index+1] = newBlock; 72 | return arrayOfBlocks.index+1; 73 | }; 74 | 75 | void removeBlock(struct ArrayOfBlocks arrayOfBlocks, int index){ 76 | free(arrayOfBlocks.arrayOfBlocks[index].table); 77 | free(arrayOfBlocks.arrayOfBlocks[index].file); 78 | free(arrayOfBlocks.arrayOfBlocks[index].dir); 79 | }; 80 | 81 | int isNumber(char* s) 82 | { 83 | int i; 84 | for (i = 0; i < strlen(s); i++) 85 | if (!isdigit(s[i])) 86 | return 0; 87 | return 1; 88 | } 89 | -------------------------------------------------------------------------------- /01. Memory management. Libraries. Time measurement/zad3/b/mylib.h: -------------------------------------------------------------------------------- 1 | #ifndef mylib_h 2 | #define mylib_h 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct ArrayOfBlocks{ 9 | int index; 10 | struct Block *arrayOfBlocks; 11 | }; 12 | 13 | struct Block{ 14 | char *dir; 15 | char *file; 16 | char *table; 17 | }; 18 | 19 | struct ArrayOfBlocks createArrayOfBlocks(int size); 20 | struct Block setDirectoryAndFile(char *dir, char *file); 21 | struct Block find(struct Block newBlock, char *name); 22 | int addToArrayOfBlocks(struct ArrayOfBlocks arrayOfBlocks, struct Block newBlock); 23 | void removeBlock(struct ArrayOfBlocks arrayOfBlocks, int index); 24 | int isNumber(char* s); 25 | 26 | #endif //mylib_h 27 | -------------------------------------------------------------------------------- /02. File system. File operations/README.md: -------------------------------------------------------------------------------- 1 | # Zadanie 1. Porównanie wydajności systemowych i bibliotecznych funkcji we/wy (55%) 2 | 3 | (30%) Celem zadania jest napisanie programu porównującego wydajność systemowych i bibliotecznych funkcji wejścia/wyjścia. Program operował będzie na przechowywanej w pliku tablicy rekordów. Dla uproszczenia pojedynczy rekord będzie tablicą bajtów o stałej wielkości. Nazwa pliku, wielkość oraz liczba rekordów stanowić będą argumenty wywołania programu. 4 | 5 | Program udostępniać powinien operacje: 6 | 7 | generate - tworzenie pliku z rekordami wypełnionego wygenerowaną losową zawartością (można wykorzystać wirtualny generator /dev/random lub w wersji uproszczonej funkcję rand) 8 | sort - sortuje rekordy w pliku używając sortowania przez proste wybieranie. Kluczem do sortowania niech będzie wartość pierwszego bajtu rekordu (interpretowanego jako liczba bez znaku - unsigned char) Podczas sortowania w pamięci powinny być przechowywane jednocześnie najwyżej dwa rekordy (sprowadza się do zamieniania miejscami i porównywania dwóch rekordów). 9 | copy - kopiuje plik1 do pliku2. Kopiowanie powinno odbywać się za pomocą bufora o zadanej wielkości rekordu. 10 | 11 | Sortowanie i kopiowanie powinno być zaimplementowane w dwóch wariantach: 12 | 13 | sys - przy użyciu funkcji systemowych: read i write 14 | lib - przy użyciu funkcji biblioteki C: fread i fwrite 15 | 16 | Rodzaj operacji oraz sposób dostępu do plików ma być wybierany na podstawie argumentu wywołania - np.: 17 | ./program generate dane 100 512 powinno losowo generować 100 rekordów o długości 512 bajtów 18 | do pliku dane, 19 | ./program sort dane 100 512 sys powinien sortować rekordy w pliku dane przy użyciu funkcji systemowych, 20 | zakładając że zawiera on 100 rekordów wielkości 512 bajtów 21 | ./program copy plik1 plik2 100 512 lib powinno skopiować 100 rekordów pliku 1 do pliku 2 za pomocą funkcji 22 | bibliotecznych z wykorzystaniem bufora 512 bajtów 23 | 24 | (25%) Dla obu wariantów implementacji przeprowadź pomiary czasu użytkownika i czasu systemowego operacji sortowania i kopiowania. Testy wykonaj dla następujących rozmiarów rekordu: 1, 4, 512, 1024, 4096 i 8192 bajty. Dla każdego rozmiaru rekordu wykonaj dwa testy różniące się liczbą rekordów w sortowanym pliku. Liczby rekordów dobierz tak, by czas sortowania mieścił się w przedziale od kilku do kilkudziesięciu sekund. Porównując dwa warianty implementacji należy korzystać z identycznego pliku do sortowania (po wygenerowaniu, a przed sortowaniem, utwórz jego kopię). Zmierzone czasy zestaw w pliku wyniki.txt. Do pliku dodaj komentarz podsumowujący wnioski z testów. 25 | 26 | # Zadanie 2. Operacje na strukturze katalogów (45%) 27 | 28 | Napisz program wyszukujący w drzewie katalogu (ścieżka do katalogu jest pierwszym argumentem programu), w zależności od wartości drugiego argumentu ('<', '>','=') , pliki z datą modyfikacji wcześniejszą, późniejszą lub równą dacie podanej jako trzeci argument programu. Program ma wypisać na standardowe wyjście następujące informacje znalezionych plików: 29 | 30 | ścieżka bezwzględna pliku, 31 | rodzaj pliku (zwykły plik - file, katalog - dir, urządzenie znakowe - char dev, urządzenie blokowe - block dev, potok nazwany - fifo, link symboliczny - slink, soket - sock) 32 | rozmiar w bajtach, 33 | datę ostatniego dostępu, 34 | datę ostatniej modyfikacji. 35 | 36 | Ścieżka podana jako argument wywołania może być względna lub bezwzględna. Program nie powinien podążać za dowiązaniami symbolicznymi do katalogów. 37 | 38 | Program należy zaimplementować w dwóch wariantach: 39 | 40 | Korzystając z funkcji opendir, readdir oraz funkcji z rodziny stat (25%) 41 | Korzystając z funkcji nftw (20%) 42 | 43 | W ramach testowania funkcji utwórz w badanej strukturze katalogów jakieś dowiązania symboliczne, zwykłe pliki i katalogi. 44 | -------------------------------------------------------------------------------- /02. File system. File operations/zad1/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc -Wall 2 | 3 | compile: 4 | $(CC) -o main main.c 5 | 6 | clean: 7 | rm main 8 | truncate -s 0 records.txt records2.txt records3.txt wyniki.txt 9 | #rm *.txt 10 | 11 | run: 12 | make clean 13 | make compile 14 | #./main generate records.txt 5 7 copy records.txt records2.txt 5 7 sys sort records2.txt 5 7 sys 15 | #./main generate records.txt 5 7 copy records.txt records2.txt 5 7 sys sort records2.txt 5 7 lib 16 | #./main generate records.txt 5 7 copy records.txt records2.txt 5 7 lib sort records2.txt 5 7 sys 17 | #./main generate records.txt 5 7 copy records.txt records2.txt 5 7 lib sort records2.txt 5 7 lib 18 | 19 | 20 | #tutaj na zajecia 21 | # 1B - dac wiecej bajtow zeby bylo pare sekund 22 | ./main generate records.txt 1 200000 copy records.txt records2.txt 1 200000 lib copy records.txt records3.txt 1 200000 sys sort records2.txt 1 50000 lib sort records2.txt 1 50000 sys 23 | ./main generate records.txt 1 400000 copy records.txt records2.txt 1 400000 lib copy records.txt records3.txt 1 400000 sys sort records2.txt 1 100000 lib sort records2.txt 1 100000 sys 24 | 25 | # 4B - wiecej bajtow 26 | ./main generate records.txt 4 4000 copy records.txt records2.txt 4 4000 lib copy records.txt records3.txt 4 4000 sys sort records2.txt 4 100 lib sort records2.txt 4 100 sys 27 | ./main generate records.txt 4 8000 copy records.txt records2.txt 4 8000 lib copy records.txt records3.txt 4 8000 sys sort records2.txt 4 200 lib sort records2.txt 4 200 sys 28 | 29 | # 512B - wiecej bajtow 30 | ./main generate records.txt 512 4000 copy records.txt records2.txt 512 4000 lib copy records.txt records3.txt 512 4000 sys sort records2.txt 512 80 lib sort records2.txt 512 80 sys 31 | ./main generate records.txt 512 8000 copy records.txt records2.txt 512 8000 lib copy records.txt records3.txt 512 8000 sys sort records2.txt 512 160 lib sort records2.txt 512 160 sys 32 | 33 | # 1024B - wiecej bajtow 34 | ./main generate records.txt 1024 4000 copy records.txt records2.txt 1024 4000 lib copy records.txt records3.txt 1024 4000 sys sort records2.txt 1024 40 lib sort records2.txt 1024 40 sys 35 | ./main generate records.txt 1024 8000 copy records.txt records2.txt 1024 8000 lib copy records.txt records3.txt 1024 8000 sys sort records2.txt 1024 80 lib sort records2.txt 1024 80 sys 36 | 37 | # 4096B - wiecej bajtow 38 | ./main generate records.txt 4096 2000 copy records.txt records2.txt 4096 2000 lib copy records.txt records3.txt 4096 2000 sys sort records2.txt 4096 20 lib sort records2.txt 4096 20 sys 39 | ./main generate records.txt 4096 4000 copy records.txt records2.txt 4096 4000 lib copy records.txt records3.txt 4096 4000 sys sort records2.txt 4096 40 lib sort records2.txt 4096 40 sys 40 | 41 | # 8192B - wiecej bajtow 42 | ./main generate records.txt 8192 1000 copy records.txt records2.txt 8192 1000 lib copy records.txt records3.txt 8192 1000 sys sort records2.txt 8192 10 lib sort records2.txt 8192 10 sys 43 | ./main generate records.txt 8192 2000 copy records.txt records2.txt 8192 2000 lib copy records.txt records3.txt 8192 2000 sys sort records2.txt 8192 20 lib sort records2.txt 8192 20 sys 44 | rm main 45 | -------------------------------------------------------------------------------- /02. File system. File operations/zad1/wnioski.txt: -------------------------------------------------------------------------------- 1 | Standardowa biblioteka C oferuje funkcję odczytu niskiego poziomu read(...). 2 | Standardowa biblioteka C oferuje również wyższą funkcję fread(...). W przeciwieństwie do funkcji odczytu, można ustawić rozmiar bufora. Bufory mogą być dobre lub złe. Z jednej strony zmniejszają liczbę dostępów do dysku. Z drugiej strony wprowadzają krok pośredni między dyskiem a danymi użytkownika. Oznacza to, że mogą powodować niepotrzebne kopiowanie danych. Bufory zwykle powodują, że oprogramowanie jest szybsze, ponieważ kopiowanie danych w pamięci jest znacznie szybsze niż odczyt z dysku. 3 | To wyjania nasze wyniki, ponieważ sortowanie jak i kopiowanie z uzyciem funkcji z rodziny fread(...)(czyli funkcji bibliotecznych C) jest szybsze niz te same zadania z uzyciem funkcji z rodziny read(...)(czyli funkcji systemowych). 4 | 5 | Wiktor Reczek 6 | -------------------------------------------------------------------------------- /02. File system. File operations/zad1/wyniki.txt: -------------------------------------------------------------------------------- 1 | Generate 1 records each 200000 bytes long: 2 | USER_TIME: 0.000000l 3 | SYSTEM_TIME: 0.000000l 4 | 5 | Copy_lib records.txt to records2.txt with 1 records each 200000 bytes long: 6 | USER_TIME: 0.000000l 7 | SYSTEM_TIME: 0.000000l 8 | 9 | Copy_sys records.txt to records3.txt with 1 records each 200000 bytes long: 10 | USER_TIME: 0.000000l 11 | SYSTEM_TIME: 0.000000l 12 | 13 | Sort_lib records2.txt with 1 records each 50000 bytes long: 14 | USER_TIME: 0.000000l 15 | SYSTEM_TIME: 0.000000l 16 | 17 | Sort_sys records2.txt with 1 records each 50000 bytes long: 18 | USER_TIME: 0.000000l 19 | SYSTEM_TIME: 0.000000l 20 | 21 | Generate 1 records each 400000 bytes long: 22 | USER_TIME: 0.000000l 23 | SYSTEM_TIME: 0.000000l 24 | 25 | Copy_lib records.txt to records2.txt with 1 records each 400000 bytes long: 26 | USER_TIME: 0.000000l 27 | SYSTEM_TIME: 0.000000l 28 | 29 | Copy_sys records.txt to records3.txt with 1 records each 400000 bytes long: 30 | USER_TIME: 0.000000l 31 | SYSTEM_TIME: 0.000000l 32 | 33 | Sort_lib records2.txt with 1 records each 100000 bytes long: 34 | USER_TIME: 0.000000l 35 | SYSTEM_TIME: 0.000000l 36 | 37 | Sort_sys records2.txt with 1 records each 100000 bytes long: 38 | USER_TIME: 0.000000l 39 | SYSTEM_TIME: 0.000000l 40 | 41 | Generate 4 records each 4000 bytes long: 42 | USER_TIME: 0.000000l 43 | SYSTEM_TIME: 0.000000l 44 | 45 | Copy_lib records.txt to records2.txt with 4 records each 4000 bytes long: 46 | USER_TIME: 0.000000l 47 | SYSTEM_TIME: 0.000000l 48 | 49 | Copy_sys records.txt to records3.txt with 4 records each 4000 bytes long: 50 | USER_TIME: 0.000000l 51 | SYSTEM_TIME: 0.000000l 52 | 53 | Sort_lib records2.txt with 4 records each 100 bytes long: 54 | USER_TIME: 0.000000l 55 | SYSTEM_TIME: 0.000000l 56 | 57 | Sort_sys records2.txt with 4 records each 100 bytes long: 58 | USER_TIME: 0.000000l 59 | SYSTEM_TIME: 0.000000l 60 | 61 | Generate 4 records each 8000 bytes long: 62 | USER_TIME: 0.000000l 63 | SYSTEM_TIME: 0.000000l 64 | 65 | Copy_lib records.txt to records2.txt with 4 records each 8000 bytes long: 66 | USER_TIME: 0.000000l 67 | SYSTEM_TIME: 0.000000l 68 | 69 | Copy_sys records.txt to records3.txt with 4 records each 8000 bytes long: 70 | USER_TIME: 0.000000l 71 | SYSTEM_TIME: 0.000000l 72 | 73 | Sort_lib records2.txt with 4 records each 200 bytes long: 74 | USER_TIME: 0.000000l 75 | SYSTEM_TIME: 0.000000l 76 | 77 | Sort_sys records2.txt with 4 records each 200 bytes long: 78 | USER_TIME: 0.000000l 79 | SYSTEM_TIME: 0.000000l 80 | 81 | Generate 512 records each 4000 bytes long: 82 | USER_TIME: 0.000000l 83 | SYSTEM_TIME: 0.000000l 84 | 85 | Copy_lib records.txt to records2.txt with 512 records each 4000 bytes long: 86 | USER_TIME: 0.000000l 87 | SYSTEM_TIME: 0.000000l 88 | 89 | Copy_sys records.txt to records3.txt with 512 records each 4000 bytes long: 90 | USER_TIME: 0.000000l 91 | SYSTEM_TIME: 0.000000l 92 | 93 | Sort_lib records2.txt with 512 records each 80 bytes long: 94 | USER_TIME: 0.030000l 95 | SYSTEM_TIME: 0.020000l 96 | 97 | Sort_sys records2.txt with 512 records each 80 bytes long: 98 | USER_TIME: 0.040000l 99 | SYSTEM_TIME: 0.100000l 100 | 101 | Generate 512 records each 8000 bytes long: 102 | USER_TIME: 0.000000l 103 | SYSTEM_TIME: 0.000000l 104 | 105 | Copy_lib records.txt to records2.txt with 512 records each 8000 bytes long: 106 | USER_TIME: 0.000000l 107 | SYSTEM_TIME: 0.000000l 108 | 109 | Copy_sys records.txt to records3.txt with 512 records each 8000 bytes long: 110 | USER_TIME: 0.000000l 111 | SYSTEM_TIME: 0.000000l 112 | 113 | Sort_lib records2.txt with 512 records each 160 bytes long: 114 | USER_TIME: 0.020000l 115 | SYSTEM_TIME: 0.040000l 116 | 117 | Sort_sys records2.txt with 512 records each 160 bytes long: 118 | USER_TIME: 0.040000l 119 | SYSTEM_TIME: 0.100000l 120 | 121 | Generate 1024 records each 4000 bytes long: 122 | USER_TIME: 0.000000l 123 | SYSTEM_TIME: 0.000000l 124 | 125 | Copy_lib records.txt to records2.txt with 1024 records each 4000 bytes long: 126 | USER_TIME: 0.000000l 127 | SYSTEM_TIME: 0.000000l 128 | 129 | Copy_sys records.txt to records3.txt with 1024 records each 4000 bytes long: 130 | USER_TIME: 0.000000l 131 | SYSTEM_TIME: 0.000000l 132 | 133 | Sort_lib records2.txt with 1024 records each 40 bytes long: 134 | USER_TIME: 0.120000l 135 | SYSTEM_TIME: 0.100000l 136 | 137 | Sort_sys records2.txt with 1024 records each 40 bytes long: 138 | USER_TIME: 0.170000l 139 | SYSTEM_TIME: 0.300000l 140 | 141 | Generate 1024 records each 8000 bytes long: 142 | USER_TIME: 0.000000l 143 | SYSTEM_TIME: 0.000000l 144 | 145 | Copy_lib records.txt to records2.txt with 1024 records each 8000 bytes long: 146 | USER_TIME: 0.000000l 147 | SYSTEM_TIME: 0.000000l 148 | 149 | Copy_sys records.txt to records3.txt with 1024 records each 8000 bytes long: 150 | USER_TIME: 0.000000l 151 | SYSTEM_TIME: 0.010000l 152 | 153 | Sort_lib records2.txt with 1024 records each 80 bytes long: 154 | USER_TIME: 0.110000l 155 | SYSTEM_TIME: 0.120000l 156 | 157 | Sort_sys records2.txt with 1024 records each 80 bytes long: 158 | USER_TIME: 0.110000l 159 | SYSTEM_TIME: 0.360000l 160 | 161 | Generate 4096 records each 2000 bytes long: 162 | USER_TIME: 0.000000l 163 | SYSTEM_TIME: 0.000000l 164 | 165 | Copy_lib records.txt to records2.txt with 4096 records each 2000 bytes long: 166 | USER_TIME: 0.000000l 167 | SYSTEM_TIME: 0.000000l 168 | 169 | Copy_sys records.txt to records3.txt with 4096 records each 2000 bytes long: 170 | USER_TIME: 0.000000l 171 | SYSTEM_TIME: 0.010000l 172 | 173 | Sort_lib records2.txt with 4096 records each 20 bytes long: 174 | USER_TIME: 1.590000l 175 | SYSTEM_TIME: 1.540000l 176 | 177 | Sort_sys records2.txt with 4096 records each 20 bytes long: 178 | USER_TIME: 2.240000l 179 | SYSTEM_TIME: 4.800000l 180 | 181 | Generate 4096 records each 4000 bytes long: 182 | USER_TIME: 0.000000l 183 | SYSTEM_TIME: 0.000000l 184 | 185 | Copy_lib records.txt to records2.txt with 4096 records each 4000 bytes long: 186 | USER_TIME: 0.000000l 187 | SYSTEM_TIME: 0.010000l 188 | 189 | Copy_sys records.txt to records3.txt with 4096 records each 4000 bytes long: 190 | USER_TIME: 0.000000l 191 | SYSTEM_TIME: 0.010000l 192 | 193 | Sort_lib records2.txt with 4096 records each 40 bytes long: 194 | USER_TIME: 1.670000l 195 | SYSTEM_TIME: 1.560000l 196 | 197 | Sort_sys records2.txt with 4096 records each 40 bytes long: 198 | USER_TIME: 1.990000l 199 | SYSTEM_TIME: 5.070000l 200 | 201 | Generate 8192 records each 1000 bytes long: 202 | USER_TIME: 0.000000l 203 | SYSTEM_TIME: 0.000000l 204 | 205 | Copy_lib records.txt to records2.txt with 8192 records each 1000 bytes long: 206 | USER_TIME: 0.000000l 207 | SYSTEM_TIME: 0.000000l 208 | 209 | Copy_sys records.txt to records3.txt with 8192 records each 1000 bytes long: 210 | USER_TIME: 0.000000l 211 | SYSTEM_TIME: 0.010000l 212 | 213 | Sort_lib records2.txt with 8192 records each 10 bytes long: 214 | USER_TIME: 6.530000l 215 | SYSTEM_TIME: 6.700000l 216 | 217 | Sort_sys records2.txt with 8192 records each 10 bytes long: 218 | USER_TIME: 9.050000l 219 | SYSTEM_TIME: 21.830000l 220 | 221 | Generate 8192 records each 2000 bytes long: 222 | USER_TIME: 0.000000l 223 | SYSTEM_TIME: 0.000000l 224 | 225 | Copy_lib records.txt to records2.txt with 8192 records each 2000 bytes long: 226 | USER_TIME: 0.000000l 227 | SYSTEM_TIME: 0.010000l 228 | 229 | Copy_sys records.txt to records3.txt with 8192 records each 2000 bytes long: 230 | USER_TIME: 0.000000l 231 | SYSTEM_TIME: 0.020000l 232 | 233 | Sort_lib records2.txt with 8192 records each 20 bytes long: 234 | USER_TIME: 6.240000l 235 | SYSTEM_TIME: 6.220000l 236 | 237 | Sort_sys records2.txt with 8192 records each 20 bytes long: 238 | USER_TIME: 8.580000l 239 | SYSTEM_TIME: 19.670000l 240 | 241 | -------------------------------------------------------------------------------- /02. File system. File operations/zad2/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc -Wall 2 | 3 | compile: 4 | $(CC) -o main main.c 5 | 6 | clean: 7 | rm main 8 | 9 | run: 10 | ./main . ">" 01.01.2019 11 | ./main . "=" 20.03.2019 12 | ./main . "<" 22.03.2019 13 | ./main . ">" 10.10.2020 14 | ./main . "<" 01.01.2019 15 | ./main . "=" 22.03.2019 16 | -------------------------------------------------------------------------------- /02. File system. File operations/zad2/main.c: -------------------------------------------------------------------------------- 1 | #define _XOPEN_SOURCE 500 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | struct tm date_nftw; 12 | char sign_nftw; 13 | 14 | void error(char *msg){ 15 | printf("%s", msg); 16 | exit(EXIT_FAILURE); 17 | } 18 | 19 | int compDates(struct tm *date1, struct tm *date2, char *sign){ 20 | int datem1, datem2; 21 | datem1 = date1->tm_mday + 32*date1->tm_mon + 366*date1->tm_year; 22 | datem2 = date2->tm_mday + 32*date2->tm_mon + 366*date2->tm_year; 23 | 24 | if(strcmp(sign, "=") == 0) 25 | return datem1 == datem2; 26 | if(strcmp(sign, "<") == 0) 27 | return datem1 < datem2; 28 | if(strcmp(sign, ">") == 0) 29 | return datem1 > datem2; 30 | return 0; // nie uwzgledniaj 31 | } 32 | 33 | char *type_of_file(unsigned char type) { 34 | switch(type) { 35 | case 8: return "file"; //DT_REG 8 36 | case 4: return "dir"; //DT_DIR 4 37 | case 2: return "char dev"; //DT_CHR 2 38 | case 6: return "block dev"; //DT_BLK 6 39 | case 1: return "fifo"; //DT_FIFO 1 40 | case 10: return "slink"; //DT_LNK 10 41 | case 12: return "sock"; //DT_SOCK 12 42 | default: return ""; 43 | }; 44 | } 45 | 46 | char *type_of_file_nftw(int type){ 47 | switch(type) { 48 | case FTW_F: return "file"; 49 | case FTW_D: return "dir"; 50 | case FTW_SL: return "link"; 51 | default: return ""; 52 | }; 53 | } 54 | 55 | void _stat(char* dir, char *sign, struct tm *date){ 56 | DIR* directory = opendir(dir); 57 | 58 | if(directory == NULL) 59 | error("Can't open directory"); 60 | 61 | struct dirent *file; 62 | struct tm *modTime; 63 | struct tm *accTime; 64 | char buffer[50]; 65 | char *absPath = (char*) calloc(100, sizeof(char)); 66 | char *nextPath = (char*) calloc(100, sizeof(char)); 67 | struct stat stats; 68 | 69 | while((file = readdir(directory))){ 70 | strcpy(nextPath, dir); 71 | strcat(nextPath, "/"); 72 | strcat(nextPath, file->d_name); 73 | realpath(nextPath, absPath); 74 | 75 | stat(nextPath, &stats); 76 | 77 | if(strcmp(file->d_name, ".") != 0 && strcmp(file->d_name, "..") != 0){ 78 | modTime = localtime((const time_t *) &stats.st_mtime); 79 | accTime = localtime((const time_t *) &stats.st_atime); 80 | 81 | if(compDates(modTime, date, sign)){ 82 | printf("\nPath: %s\n" 83 | "Type: %s\n" 84 | "Size: %ld\n", 85 | absPath, 86 | type_of_file(file->d_type), 87 | stats.st_size); 88 | strftime (buffer, 50 ,"Last mod.: %d.%m.%Y\n", modTime); 89 | printf("%s", buffer); 90 | strftime (buffer, 50 ,"Last access: %d.%m.%Y\n", accTime); 91 | printf("%s", buffer); 92 | } 93 | 94 | if(file->d_type == 4) 95 | _stat(nextPath, sign, date); 96 | } 97 | } 98 | 99 | free(nextPath); 100 | free(absPath); 101 | free(file); 102 | closedir(directory); 103 | } 104 | 105 | int display_info(const char *path, const struct stat *sb, int type_of_flag, struct FTW *tw_buf){ 106 | struct tm *modTime; 107 | struct tm *accTime; 108 | char buffer[50]; 109 | char *absPath = (char*) calloc(100, sizeof(char)); 110 | 111 | modTime = localtime((const time_t *) &sb->st_mtime); 112 | accTime = localtime((const time_t *) &sb->st_atime); 113 | 114 | realpath(path, absPath); 115 | 116 | if(compDates(modTime, &date_nftw, &sign_nftw)){ 117 | printf("\nPath: %s\n" 118 | "Type: %s\n" 119 | "Size: %ld\n", 120 | absPath, 121 | type_of_file_nftw(type_of_flag), 122 | sb->st_size); 123 | strftime (buffer, 50 ,"Last mod.: %d.%m.%Y\n", modTime); 124 | printf("%s", buffer); 125 | strftime (buffer, 50 ,"Last access: %d.%m.%Y\n", accTime); 126 | printf("%s", buffer); 127 | } 128 | 129 | free(absPath); 130 | return 0; 131 | } 132 | 133 | void _nftw(char *dir, char *sign, struct tm *date){ 134 | sign_nftw = *sign; 135 | date_nftw = *date; 136 | nftw(dir, display_info, 10, FTW_PHYS); 137 | } 138 | 139 | int main(int argc, char **argv) { 140 | if(argc != 4) 141 | error("Invalid number of arguments"); 142 | 143 | char *path_to_dir, *sign; 144 | path_to_dir = argv[1]; 145 | 146 | if(strcmp(argv[2], "<") == 0 || strcmp(argv[2], ">") == 0 || strcmp(argv[2], "=") == 0) 147 | sign = argv[2]; 148 | else 149 | error("Bad argv[2]"); 150 | 151 | struct tm date; 152 | 153 | if(strptime(argv[3], "%d.%m.%Y", &date) == NULL) 154 | error("Bad argv[3]"); 155 | 156 | printf("\nSearching in %s files %s %s\n", argv[1],argv[2],argv[3]); 157 | printf("\n############--stat--#############\n"); 158 | _stat(path_to_dir, sign, &date); 159 | 160 | printf("\n\n############--nftw--#############\n\n"); 161 | _nftw(path_to_dir, sign, &date); 162 | 163 | return 0; 164 | } 165 | -------------------------------------------------------------------------------- /03. Creating processes. Process environment, process control/README.md: -------------------------------------------------------------------------------- 1 | # Zadanie 1. Drzewo procesów (15%) 2 | 3 | Modyfikując zadanie 2 z poprzedniego zestawu, napisz program, który dla każdego z podkatalogów utworzy proces potomny i wywoła polecenie ls -l. Wynik ls poprzedź wypisaniem ścieżki względnej od katalogu podanego jako argument oraz numeru PID procesu odpowiedzialnego za przeglądanie określonego poziomu. 4 | 5 | 6 | # Zadanie 2. Kopie zapasowe plików (50%) 7 | 8 | Napisz program monitor do robienia kopii zapasowych plików, zawartych w pliku lista podawanym jako argument programu. Plik lista zawiera w pojedynczej linii nazwę monitorowanego pliku wraz ze ścieżką względną bądź bezwzględną oraz liczbę, co ile sekund plik ma być monitorowany. Dla każdego pliku z lista program monitor tworzy odpowiednią liczbę procesów potomnych, aby każdy monitorował jeden plik. Drugim argumentem programu monitor jest czas monitorowania wyrażony w sekundach. Po upłynięciu tego czasu każdy z procesów potomnych kończy swoje działanie, zwracając do procesu macierzystego poprzez kod wyjścia procesu liczbę wykonanych kopii pliku. Program macierzysty pobiera statusy procesów potomnych, wypisuje raport: "Proces PID utworzył n kopii pliku" i kończy swoje działanie. UWAGA! Nie używamy sygnałów, które są tematem następnych zajęć. 9 | 10 | Kopiowanie pliku może odbywać się na dwa sposoby: (tryb - trzeci argument programu) 11 | 12 | Proces kopiuje do pamięci zawartość monitorowanego pliku oraz datę jego ostatniej modyfikacji, po czym jeśli data modyfikacji pliku (a tym samym zawartość pliku) zostanie zmieniona, to proces zapisuje skopiowaną do pamięci starą wersję pliku we wspólnym dla wszystkich podkatalogu archiwum a do pamięci zapisuje aktualną wersję pliku. 13 | Plik nie jest zapisywany w pamięci, natomiast na samym początku oraz po każdej zanotowanej modyfikacji pliku, proces utworzy nowy proces, który wywoła jedną z funkcji z rodziny exec, aby wykonać cp. 14 | 15 | Nazwa pliku utworzonej kopii to nazwa monitorowanego pliku, rozszerzona o datę modyfikacji pliku w formacie: _RRRR-MM-DD_GG-MM-SS. 16 | 17 | Napisz pomocniczy testowy program tester, przyjmujący argumenty: plik, pmin pmax i bytes, który do zadanego jako pierwszy argument pliku z losową częstością od pmin do pmax wyrażoną w sekundach dopisuje na jego koniec linię tekstu zawierającą pid procesu, wylosowaną liczbę sekund, aktualną datę i czas (nie liczą się do liczby bajtów) oraz dowolnego ciągu znaków o długości określonej w bytes. Program ten pozwoli w krótkim czasie wygenerować kilka wersji kopii zapasowych. 18 | 19 | 20 | # Zadanie 3. Zasoby procesów (35%) 21 | 22 | Zmodyfikuj program z Zadania 2 tak, aby każdy kopiujący proces miał nałożone pewne twarde ograniczenie na dostępny czas procesora oraz rozmiar pamięci wirtualnej. Wartości tych ograniczeń (odpowiednio w sekundach i megabajtach) powinny być przekazywane jako czwarty i piąty argument wywołania monitora. Ograniczenia powinny być nakładane przez proces potomny, w tym celu należy użyć funkcji setrlimit. Zakładamy, że wartości nakładanych ograniczeń są dużo niższe (t.j. bardziej restrykcyjne) niż ograniczenia, które system operacyjny narzuca na użytkownika uruchamiającego monitor. 23 | 24 | Zaimplementuj w monitorze raportowanie zużycia zasobów systemowych dla każdego procesu potomnego, w tym czas użytkownika i czas systemowy. Realizując tę część zadania zwróć uwagę na funkcję getrusage i flagę RUSAGE_CHILDREN. 25 | -------------------------------------------------------------------------------- /03. Creating processes. Process environment, process control/zad1/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc -Wall 2 | 3 | compile: 4 | $(CC) -o main main.c 5 | 6 | clean: 7 | rm -f main 8 | rm -f *.o 9 | 10 | run: 11 | make clean 12 | make compile 13 | ./main 14 | #./main ../ 15 | #./main /home/wiktor/Dokumenty na zajeciach dac inne 16 | -------------------------------------------------------------------------------- /03. Creating processes. Process environment, process control/zad1/main.c: -------------------------------------------------------------------------------- 1 | #define _XOPEN_SOURCE 500 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | void error(char *msg){ 11 | printf("%s", msg); 12 | exit(EXIT_FAILURE); 13 | } 14 | 15 | char *type_of_file_nftw(int type){ 16 | switch(type) { 17 | case FTW_F: return "file"; 18 | case FTW_D: return "dir"; 19 | case FTW_SL: return "link"; 20 | default: return ""; 21 | }; 22 | } 23 | 24 | int display_info(const char *path, const struct stat *sb, int flagType, struct FTW *tw_buf){ 25 | char *absPath = (char*) calloc(150, sizeof(char)); 26 | 27 | realpath(path, absPath); 28 | pid_t pid = fork(); 29 | if (pid < 0) error("pid fork()"); 30 | if (pid == 0){ 31 | if (flagType == FTW_D){ 32 | printf("\nPID: %d", pid); 33 | printf("\nPath: %s", path); 34 | printf("\nAbs. path: %s\n", absPath); 35 | char cmd[80] = "ls -l "; 36 | strcat(cmd, path); 37 | system(cmd); 38 | exit(0); 39 | } 40 | } 41 | else{ 42 | //kill(getpid(), SIGKILL); 43 | wait(&pid); 44 | } 45 | free(absPath); 46 | return 0; 47 | } 48 | 49 | int main(int argc, char **argv) { 50 | char * path; 51 | if (argc != 2) 52 | path = "."; 53 | else 54 | path = argv[1]; 55 | 56 | nftw(path, display_info, 10, FTW_PHYS); 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /03. Creating processes. Process environment, process control/zad2/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc -Wall 2 | 3 | clean: 4 | rm -f *.o 5 | rm -f monitor 6 | rm -f tester 7 | rm -f archiwum/* 8 | truncate -s 0 obiekt* 9 | 10 | compileMonitor: 11 | $(CC) -o monitor monitor.c 12 | 13 | compileTester: 14 | $(CC) -o tester tester.c 15 | 16 | runArch: 17 | make clean 18 | make compileMonitor 19 | ./monitor lista.txt 30 arch 20 | 21 | runExec: 22 | make clean 23 | make compileMonitor 24 | ./monitor lista.txt 30 exec 25 | 26 | runTester: 27 | make compileTester 28 | ./tester obiekt.txt 1 5 10 30 29 | #./tester obiekt1.txt 2 3 5 30 30 | #./tester obiekt2.txt 5 7 1 30 31 | #./tester obiekt3.txt 0 10 17 30 32 | -------------------------------------------------------------------------------- /03. Creating processes. Process environment, process control/zad2/lista.txt: -------------------------------------------------------------------------------- 1 | obiekt.txt . 2 2 | obiekt1.txt . 5 3 | obiekt2.txt . 3 4 | obiekt3.txt . 4 5 | -------------------------------------------------------------------------------- /03. Creating processes. Process environment, process control/zad2/monitor.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | struct fileInfo{ 11 | char * content; 12 | long size; 13 | char * time; 14 | }; 15 | 16 | void error(char *msg){ 17 | printf("%s", msg); 18 | exit(EXIT_FAILURE); 19 | } 20 | 21 | struct fileInfo * copyFileToMemory(char * filePath){ 22 | FILE *f = fopen(filePath, "rb"); 23 | if ( !f ) error("copyFileToMemory fopen"); 24 | fseek(f, 0, SEEK_END); 25 | long fsize = ftell(f); 26 | fseek(f, 0, SEEK_SET); /* same as rewind(f); */ 27 | 28 | char *string = malloc(fsize + 1); 29 | fread(string, fsize, 1, f); 30 | fclose(f); 31 | 32 | string[fsize] = 0; 33 | 34 | struct fileInfo * info = malloc(sizeof(struct fileInfo*)); 35 | info->content = string; 36 | info->size = fsize + 1; 37 | 38 | struct stat statbuf; 39 | if (stat(filePath, &statbuf) < 0) 40 | error("stat"); 41 | char * buffer = calloc(21, sizeof(char)); 42 | strftime (buffer, 21 ,"_%F_%T\n", localtime((const time_t *)&statbuf.st_mtime)); 43 | info->time = buffer; 44 | return info; 45 | } 46 | 47 | int monitorArch(char * fileName, int seconds, char * path, int programSeconds){ 48 | char filePath[100]; 49 | strcpy(filePath, path); 50 | strcat(filePath, "/"); 51 | strcat(filePath, fileName); 52 | 53 | FILE * file = fopen(filePath, "r"); 54 | if ( !file ) error("monitorArch fopen"); 55 | 56 | struct stat statbuf; 57 | 58 | int howMany = 0; 59 | struct fileInfo * info = copyFileToMemory(filePath); 60 | int i = 0; 61 | while(++i){ 62 | if (stat(filePath, &statbuf) < 0) 63 | error("monitorArch stat"); 64 | 65 | char cmp[21]; 66 | strftime (cmp, 21 ,"_%F_%T\n", localtime((const time_t *)&statbuf.st_mtime)); 67 | if (strcmp(info->time, cmp) != 0){ 68 | howMany++; 69 | char archPathWithName[120];// = calloc(120, sizeof(char)); 70 | strcpy(archPathWithName, path); 71 | strcat(archPathWithName, "/archiwum/"); 72 | strcat(archPathWithName, fileName); 73 | strcat(archPathWithName, info->time); 74 | 75 | FILE * newFile = fopen(archPathWithName, "w"); 76 | if ( !file ) error("archPathWithName fopen"); 77 | 78 | fprintf(newFile, "%s", info->content); 79 | fclose(newFile); 80 | 81 | info = copyFileToMemory(filePath); 82 | } 83 | sleep(seconds); 84 | if (i * seconds > programSeconds) break; 85 | } 86 | fclose(file); 87 | return howMany; 88 | } 89 | 90 | void monitorArchHelper(char * listFileName, int programSeconds){ 91 | FILE* file = fopen(listFileName, "r"); 92 | if ( !file ) error("monitorArchHelper fopen"); 93 | 94 | pid_t pids[30]; 95 | int howMany = 0; 96 | char line[80]; 97 | while (fgets(line, sizeof(line), file)) { 98 | char * name; 99 | char * path; 100 | int seconds; 101 | 102 | char * ptr = strtok(line, " "); 103 | name = ptr; 104 | ptr = strtok(NULL, " "); 105 | path = ptr; 106 | ptr = strtok(NULL, " "); 107 | seconds = atoi(ptr); 108 | pid_t pid = fork(); 109 | if (pid < 0) error("fork"); 110 | if (pid == 0){ 111 | int returned = monitorArch(name, seconds, path, programSeconds); 112 | exit(returned); // mozna _exit() jakby byly bledy 113 | } 114 | else{ 115 | pids[howMany] = pid; 116 | } 117 | howMany++; 118 | } 119 | fclose(file); 120 | 121 | int i; 122 | for (i = 0; i < howMany; ++i){ 123 | pid_t pid = pids[i]; 124 | wait(&pids[i]); 125 | if (WIFEXITED(pids[i])){ 126 | pid_t ret = WEXITSTATUS(pids[i]); 127 | printf("Proces %d utworzyl %d kopii pliku.\n", pid, ret); 128 | } 129 | } 130 | } 131 | 132 | int monitorExec(char * fileName, int seconds, char * path, int programSeconds){ 133 | char filePath[100]; 134 | strcpy(filePath, path); 135 | strcat(filePath, "/"); 136 | strcat(filePath, fileName); 137 | 138 | FILE * file = fopen(filePath, "r"); 139 | if ( !file ) error("monitorArch fopen"); 140 | 141 | struct stat statbuf; 142 | if (stat(filePath, &statbuf) < 0) 143 | error("exec stat"); 144 | char lastModTime[21];// = calloc(21, sizeof(char)); 145 | strftime (lastModTime, 21 ,"_%F_%T\n", localtime((const time_t *)&statbuf.st_mtime)); 146 | 147 | char archPathWithName[120];// = calloc(120, sizeof(char)); 148 | strcpy(archPathWithName, path); 149 | strcat(archPathWithName, "/archiwum/"); 150 | strcat(archPathWithName, fileName); 151 | strcat(archPathWithName, lastModTime); 152 | 153 | pid_t pid; 154 | int howMany = 0; 155 | pid = fork(); 156 | if (pid < 0) error("monitorExec fork"); 157 | if (pid == 0){ 158 | execlp("cp", "-T", filePath, archPathWithName, NULL); 159 | } 160 | else{ 161 | wait(&pid); 162 | howMany++; 163 | } 164 | //free(archPathWithName); 165 | 166 | int i = 0; 167 | while(++i){ 168 | if (stat(filePath, &statbuf) < 0) 169 | error("monitorArch stat"); 170 | 171 | char cmp[21]; 172 | strftime (cmp, 21 ,"_%F_%T\n", localtime((const time_t *)&statbuf.st_mtime)); 173 | 174 | if (strcmp(lastModTime, cmp) != 0){ 175 | strcpy(lastModTime, cmp); 176 | char archPathWithName[120];// = calloc(120, sizeof(char)); 177 | strcpy(archPathWithName, path); 178 | strcat(archPathWithName, "/archiwum/"); 179 | strcat(archPathWithName, fileName); 180 | strcat(archPathWithName, lastModTime); 181 | 182 | FILE * newFile = fopen(archPathWithName, "w"); 183 | if ( !file ) error("archPathWithName exec fopen"); 184 | 185 | pid = fork(); 186 | 187 | if (pid < 0) error("monitorExec fork"); 188 | if (pid == 0){ 189 | execlp("cp", "-T", filePath, archPathWithName, NULL); 190 | } 191 | else{ 192 | wait(&pid); 193 | howMany++; 194 | } 195 | 196 | // free(archPathWithName); 197 | fclose(newFile); 198 | } 199 | 200 | sleep(seconds); 201 | if (i * seconds > programSeconds) break; 202 | } 203 | 204 | // free(lastModTime); 205 | fclose(file); 206 | return howMany; 207 | } 208 | 209 | void monitorExecHelper(char * listFileName, int programSeconds){ 210 | FILE* file = fopen(listFileName, "r"); 211 | if ( !file ) error("monitorArchHelper fopen"); 212 | 213 | pid_t pids[30]; 214 | int howMany = 0; 215 | char line[80]; 216 | while (fgets(line, sizeof(line), file)) { 217 | char * name; 218 | char * path; 219 | int seconds; 220 | 221 | char * ptr = strtok(line, " "); 222 | name = ptr; 223 | ptr = strtok(NULL, " "); 224 | path = ptr; 225 | ptr = strtok(NULL, " "); 226 | seconds = atoi(ptr); 227 | 228 | pid_t pid = fork(); 229 | if (pid < 0) error("fork"); 230 | if (pid == 0){ 231 | int returned = monitorExec(name, seconds, path, programSeconds); 232 | exit(returned); 233 | } 234 | else{ 235 | pids[howMany] = pid; 236 | } 237 | howMany++; 238 | } 239 | fclose(file); 240 | 241 | int i; 242 | for (i = 0; i < howMany; ++i){ 243 | pid_t pid = pids[i]; 244 | wait(&pids[i]); 245 | if (WIFEXITED(pids[i])){ 246 | pid_t ret = WEXITSTATUS(pids[i]); 247 | printf("Proces %d utworzyl %d kopii pliku.\n", pid, ret); 248 | } 249 | } 250 | } 251 | 252 | int main(int argc, char * argv[]){ 253 | /// argv[1] = nazwa pliku z listą 254 | /// argv[2] = czas_monitorowania 255 | /// argv[3] = tryb kopiowania: 256 | if (argc != 4) 257 | error("Wrong arguments number"); 258 | 259 | if ( strcmp(argv[3], "arch") == 0 ) 260 | monitorArchHelper(argv[1], atoi(argv[2])); 261 | else if ( strcmp(argv[3], "exec") == 0 ) 262 | monitorExecHelper(argv[1], atoi(argv[2])); 263 | else 264 | error("Bad argv[3]"); 265 | 266 | return 0; 267 | } 268 | -------------------------------------------------------------------------------- /03. Creating processes. Process environment, process control/zad2/tester.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define ITERS 5 11 | 12 | void error(char *msg){ 13 | printf("%s", msg); 14 | exit(EXIT_FAILURE); 15 | } 16 | 17 | int main(int argc, char * argv[]){ 18 | /// argv[1] = plik 19 | /// argv[2] = pmin 20 | /// argv[3] = pmax 21 | /// argv[4] = bytes 22 | srand(time(NULL)); 23 | if (argc != 6) error("Bad arguments number"); 24 | 25 | 26 | int pmin = atoi(argv[2]); 27 | int pmax = atoi(argv[3]); 28 | char * bytes = argv[4];//atoi(argv[4]); 29 | int progSeconds = atoi(argv[5]); 30 | 31 | time_t rawtime; 32 | struct tm * timeinfo; 33 | 34 | int i; 35 | while(++i){ 36 | // for (i = 0; i < ITERS; ++i){ 37 | FILE * file = fopen(argv[1], "a"); 38 | if (!file) error("fopen"); 39 | 40 | pid_t pid = getpid(); 41 | int waitSeconds = rand() % (pmax - pmin) + pmin; 42 | time ( &rawtime ); 43 | timeinfo = localtime ( &rawtime ); 44 | char string[atoi(bytes)+1]; 45 | string[atoi(bytes)] = '\0'; 46 | int j; 47 | for (j = 0; j < atoi(bytes); j++){ 48 | string[j] = '0' + rand() % 72; 49 | } 50 | 51 | fprintf(file, "%d %d %s %s\n" 52 | ,pid 53 | ,waitSeconds 54 | ,strtok(asctime(timeinfo), "\n") 55 | ,string 56 | ); 57 | fclose(file); 58 | sleep(waitSeconds); 59 | if (i * waitSeconds > progSeconds) break; 60 | } 61 | 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /03. Creating processes. Process environment, process control/zad3/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc -Wall 2 | 3 | clean: 4 | rm -f *.o 5 | rm -f monitor 6 | rm -f tester 7 | rm -f archiwum/* 8 | truncate -s 0 obiekt* 9 | 10 | compileMonitor: 11 | $(CC) -o main main.c 12 | 13 | runArch: 14 | make clean 15 | make compileMonitor 16 | ./main lista.txt 30 arch 20 1 17 | #./main lista.txt 30 arch 200 200 18 | 19 | runExec: 20 | make clean 21 | make compileMonitor 22 | ./main lista.txt 30 exec 20 1 23 | #./main lista.txt 30 exec 200 200 24 | -------------------------------------------------------------------------------- /03. Creating processes. Process environment, process control/zad3/lista.txt: -------------------------------------------------------------------------------- 1 | obiekt.txt . 2 2 | obiekt1.txt . 5 3 | obiekt2.txt . 3 4 | obiekt3.txt . 4 5 | -------------------------------------------------------------------------------- /04. Signals/README.md: -------------------------------------------------------------------------------- 1 | # Zadanie 1 (25%) 2 | 3 | Napisz program wypisujący w pętli nieskończonej aktualną datę i godzinę. Po odebraniu sygnału SIGTSTP (CTRL+Z) program zatrzymuje się, wypisując komunikat "Oczekuję na CTRL+Z - kontynuacja albo CTR+C - zakończenie programu". Po ponownym wysłaniu SIGTSTP program powraca do pierwotnego wypisywania. 4 | Program powinien również obsługiwać sygnał SIGINT. Po jego odebraniu program wypisuje komunikat "Odebrano sygnał SIGINT" i kończy działanie. W kodzie programu, do przechwycenia sygnałów użyj zarówno funkcji signal, jak i sigaction (np. SIGINT odbierz za pomocą signal, a SIGTSTP za pomocą sigaction). 5 | Zrealizuj powyższe zadanie, tworząc program potomny, który będzie wywoływał jedną z funkcji z rodziny exec skrypt shellowy zawierający zapętlone systemowe polecenie date. Proces macierzysty będzie przychwytywał powyższe sygnały i przekazywał je do procesu potomnego, tj po otrzymaniu SIGTSTP kończy proces potomka, a jeśli ten został wcześniej zakończony, tworzy nowy, wznawiając działanie skryptu, a po otrzymaniu SIGINT kończy działanie potomka (jeśli ten jeszcze pracuje) oraz programu. 6 | 7 | 8 | # Zadanie 2 (35%) 9 | 10 | Zmodyfikuj program 2 (monitor - wersję z alokowaniem pamięci) z poprzedniego zestawu tak, aby to program macierzysty był odpowiedzialny za zakończenie procesów potomnych. Nie ma ograniczenia czasowego dla działania programu. Po uruchomieniu programu proces macierzysty wypisuje listę plików przydzielonych do określonych procesów potomnych. Po utworzeniu procesów potomnych, które działają w nieskończonych pętlach proces macierzysty nie przechodził w stan uśpienia, czekając na zakończenie procesów, tylko obiera komendy od użytkownika: 11 | 12 | LIST - program wypisuje listę procesów monitorujących pliki 13 | STOP PID - program zatrzymuje (nie kończy) monitorowanie procesu o numerze PID. Można to zrealizować poprzez wysłanie do procesu potomnego sygnału SIGUSR1. Proces macierzysty po odebraniu sygnału zatrzymuje pętlę poprzez zmianę flagi. 14 | STOP ALL - program zatrzymuje (nie kończy) monitorowanie wszystkich procesów potomnych 15 | START PID - program wznawia monitorowanie procesu o numerze PID (również poprzez wysłanie sygnału i zmianę flagi). 16 | START ALL - program wznawia działanie wszystkich procesów potomnych 17 | END - program kończy działanie wszystkich procesów i wyświetla końcowy raport. 18 | 19 | Zdefiniuj dodatkowo obsługę sygnału SIGINT, który będzie działał jak END, czyli wypisze raport końcowy. 20 | 21 | 22 | # Zadanie 3 (40%) 23 | 24 | Napisz dwa programy: sender program wysyłający sygnały SIGUSR1 i catcher - program zliczający ilość odebranych sygnałów. Ilość sygnałów SIGUSR1 wysyłanych przez pierwszy program powinna być określana w parametrze wywołania tego programu. Program catcher jest uruchamiany najpierw, wypisuje swój numer PID i czeka na sygnały SIGUSR1 i SIGUSR2. Wszystkie pozostałe sygnały są blokowane. Program sender przyjmuje trzy parametry: PID procesu catcher, ilość sygnałów do wysłania i tryb wysłania sygnałów. 25 | 26 | Po transmisji wszystkich sygnałów SIGUSR1 sender powinien wysłać sygnał SIGUSR2, po otrzymaniu którego catcher wysyła do sendera tyle sygnałów SIGUSR1, ile sam ich otrzymał a „transmisję” kończy wysłaniem sygnału SIGUSR2, wypisaniem liczby odebranych sygnałów i zakończeniem działania. PID sendera catcher pobiera ze struktury SIGACTION po przechwyceniu od niego sygnału. Program sender po otrzymaniu sygnału SIGUSR2 wyświetla komunikat o ilości otrzymanych sygnałów SIGUSR1 oraz o tym, ile powinien ich otrzymać i kończy działanie. 27 | 28 | UWAGA! W żaden sposób nie opóźniamy wysyłania sygnałów, wszelkie "gubienie" sygnałów jest zjawiskiem naturalnym. 29 | 30 | a) Wysyłanie sygnałów w obu programach należy wykonać w następujących trybach: (25%) 31 | 32 | KILL - za pomocą funkcji kill 33 | SIGQUEUE - za pomocą funkcji sigqueue - wraz z przesłanym sygnałem catcher wysyła numer kolejnego odsyłanego sygnału, dzięki czemu sender wie, ile dokładnie catcher odebrał, a tym samym wysłał do niego sygnałów. Wypisz tę dodatkową informację w senderze. 34 | SIGRT - zastępując SIGUSR1 i SIGUSR2 dwoma dowolnymi sygnałami czasu rzeczywistego wysyłanymi za pomocą kill. Jaka liczba sygnałów będzie teraz odebrana? 35 | 36 | b) Zmodyfikuj powyższe programy, dodając potwierdzenie odbioru sygnału po każdorazowym ich odebraniu przez program catcher. W tym celu, catcher wysyła do sendera sygnał SIGUSR1 informujący o odbiorze sygnału. Sender powinien wysłać kolejny sygnał dopiero po uzyskaniu tego potwierdzenia. Zapewnij rozwiązanie, w którym ilość sygnałów odebranych jest zgodna z ilością sygnałów wysłanych, i w którym nie dochodzi do zakleszczenia. (15%) 37 | -------------------------------------------------------------------------------- /04. Signals/zad1/date.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | while : 3 | do 4 | date 5 | sleep 1 6 | done -------------------------------------------------------------------------------- /04. Signals/zad1/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int arg; 10 | pid_t pid; 11 | int waiting = 0; 12 | 13 | void error(const char * msg){ 14 | perror(msg); 15 | exit(EXIT_FAILURE); 16 | } 17 | 18 | void sigintFunction(int signum){ 19 | printf("Odebrano sygnal SIGINT\n"); 20 | exit(EXIT_SUCCESS); 21 | } 22 | 23 | void sigtstpAction(int signum){ 24 | if (waiting == 1){ 25 | waiting = 0; 26 | } 27 | else if (waiting == 0){ 28 | if (arg == 2){ 29 | kill(pid, SIGKILL); 30 | } 31 | printf("Oczekuje na CTRL+Z - kontynuacja albo CTR+C - zakończenie programu\n"); 32 | waiting = 1; 33 | sigset_t mask; 34 | sigfillset(&mask); 35 | sigdelset(&mask, SIGINT); 36 | sigdelset(&mask, SIGTSTP); 37 | sigsuspend(&mask); 38 | } 39 | else error("bad waiting"); 40 | } 41 | 42 | void firstTask() { 43 | if (signal(SIGINT, sigintFunction) == SIG_ERR){ 44 | error("sigint signal"); 45 | } 46 | 47 | struct sigaction action; 48 | action.sa_handler = sigtstpAction; 49 | sigemptyset(&action.sa_mask); 50 | action.sa_flags = 0; 51 | if (sigaction(SIGTSTP, &action, NULL) != 0){ 52 | error("sigaction"); 53 | } 54 | 55 | while(1) { 56 | system("date"); 57 | sleep(1); 58 | } 59 | exit(EXIT_SUCCESS); 60 | } 61 | 62 | void secondTask(){ 63 | if (signal(SIGINT, sigintFunction) == SIG_ERR){ 64 | error("second sigint"); 65 | } 66 | 67 | struct sigaction action; 68 | action.sa_handler = sigtstpAction; 69 | sigemptyset(&action.sa_mask); 70 | action.sa_flags = 0; 71 | if (sigaction(SIGTSTP, &action, NULL) == -1){ 72 | error("second sigtstp"); 73 | } 74 | 75 | while(1){ 76 | pid = fork(); 77 | if (pid < 0){ 78 | error("fork()"); 79 | } 80 | 81 | if (pid == 0) { 82 | execlp("./date.sh", "date.sh", NULL); 83 | error("execlp"); 84 | } 85 | else { 86 | sigset_t mask; 87 | sigfillset(&mask); 88 | sigdelset(&mask, SIGINT); 89 | sigdelset(&mask, SIGTSTP); 90 | sigsuspend(&mask); 91 | } 92 | } 93 | exit(EXIT_SUCCESS); 94 | } 95 | 96 | int main(int argc, char * argv[]){ 97 | if (argc != 2) error("Bad arg number"); 98 | 99 | if (strcmp(argv[1], "first") == 0) { 100 | arg = 1; 101 | firstTask(); 102 | } 103 | else if (strcmp(argv[1], "second") == 0){ 104 | arg = 2; 105 | secondTask(); 106 | } 107 | else{ 108 | error("Bad arg"); 109 | } 110 | 111 | exit(EXIT_SUCCESS); 112 | } 113 | 114 | /// w 2gim modyfikujemy 3ci zestaw i git 115 | /// w 3cim zadaniu warto przechwycic CTRL + C 116 | /// za 2 tygodnie kolos tj. 12.04.2019 117 | /// 5 zestaw trzeba zrobic na czas 118 | -------------------------------------------------------------------------------- /04. Signals/zad1/makefile: -------------------------------------------------------------------------------- 1 | CC = gcc -Wall -o 2 | 3 | clean: 4 | rm -f *.o 5 | rm -f main 6 | 7 | compile: 8 | make clean 9 | $(CC) main main.c 10 | 11 | grant: 12 | chmod 755 date.sh 13 | 14 | run: 15 | make compile 16 | ./main first 17 | 18 | run2: 19 | make compile 20 | ./main second 21 | -------------------------------------------------------------------------------- /04. Signals/zad2/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc -Wall 2 | 3 | clean: 4 | rm -f *.o 5 | rm -f main 6 | rm -f tester 7 | rm -f archiwum/* 8 | truncate -s 0 obiekt* 9 | 10 | compileMain: 11 | $(CC) -o main main.c 12 | 13 | compileTester: 14 | $(CC) -o tester tester.c 15 | 16 | run: 17 | make clean 18 | make compileMain 19 | ./main lista.txt 20 | 21 | runTester: 22 | make compileTester 23 | ./tester obiekt.txt 1 5 10 30 24 | #./tester obiekt1.txt 2 3 5 30 25 | #./tester obiekt2.txt 5 7 1 30 26 | #./tester obiekt3.txt 0 10 17 30 27 | -------------------------------------------------------------------------------- /04. Signals/zad2/lista.txt: -------------------------------------------------------------------------------- 1 | obiekt.txt . 2 2 | obiekt1.txt . 5 3 | obiekt2.txt . 3 4 | obiekt3.txt . 4 5 | -------------------------------------------------------------------------------- /04. Signals/zad2/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int flag; 11 | int howMany; 12 | int parentFlag; 13 | pid_t pids[30]; 14 | int backups[30]; 15 | int isRunning[30]; 16 | 17 | struct fileInfo{ 18 | char * content; 19 | long size; 20 | char * time; 21 | }; 22 | 23 | void initPidList(){ 24 | int i; 25 | for (i = 0; i < 30; ++i){ 26 | pids[i] = 0; 27 | } 28 | } 29 | 30 | /// ----------- COMMANDS ------------- 31 | void LIST(); 32 | void STOPPID(pid_t); // SIGUSR1 33 | void STOPALL(); 34 | void STARTPID(pid_t); // SIGUSR2 35 | void STARTALL(); 36 | void END(); // SIGRTMAX for all pids 37 | 38 | void error(char *msg){ 39 | perror(msg); 40 | END(); 41 | exit(EXIT_FAILURE); 42 | } 43 | 44 | /// ----------- HANDLERS ------------ 45 | void sigintHandler(int signum){ // SIGINT 46 | END(); 47 | } 48 | 49 | void sigrtmaxHandler(int signum){ 50 | flag = 0; // to je zakonczy, bo koniec petli 51 | } 52 | 53 | void sigusr1Handler(int signum){ 54 | sigset_t mask; 55 | sigfillset(&mask); 56 | sigdelset(&mask, SIGINT); 57 | sigdelset(&mask, SIGUSR1); 58 | sigdelset(&mask, SIGUSR2); 59 | sigdelset(&mask, SIGRTMAX); 60 | sigsuspend(&mask); 61 | } 62 | 63 | void sigusr2Handler(int signum){ 64 | // unsuspends 65 | } 66 | 67 | /// ---------- PROPER FUNCTIONS ------------- 68 | 69 | struct fileInfo * copyFileToMemory(char * filePath){ 70 | FILE *f = fopen(filePath, "rb"); 71 | if ( !f ) error("copyFileToMemory fopen"); 72 | fseek(f, 0, SEEK_END); 73 | long fsize = ftell(f); 74 | fseek(f, 0, SEEK_SET); /* same as rewind(f); */ 75 | 76 | char *string = malloc(fsize + 1); 77 | fread(string, fsize, 1, f); 78 | fclose(f); 79 | 80 | string[fsize] = 0; 81 | 82 | struct fileInfo * info = malloc(sizeof(struct fileInfo*)); 83 | info->content = string; 84 | info->size = fsize + 1; 85 | 86 | struct stat statbuf; 87 | if (stat(filePath, &statbuf) < 0) 88 | error("stat"); 89 | char * buffer = calloc(21, sizeof(char)); 90 | strftime (buffer, 21 ,"_%F_%T\n", localtime((const time_t *)&statbuf.st_mtime)); 91 | info->time = buffer; 92 | return info; 93 | } 94 | 95 | int monitorArch(char * fileName, char * path, int seconds){ 96 | char filePath[100]; 97 | strcpy(filePath, path); 98 | strcat(filePath, "/"); 99 | strcat(filePath, fileName); 100 | 101 | FILE * file = fopen(filePath, "r"); 102 | if ( !file ) error("monitorArch fopen"); 103 | 104 | struct stat statbuf; 105 | 106 | int howManyChanges = 0; 107 | struct fileInfo * info = copyFileToMemory(filePath); 108 | 109 | signal(SIGRTMAX, sigrtmaxHandler); 110 | signal(SIGUSR1, sigusr1Handler); 111 | signal(SIGUSR2, sigusr2Handler); 112 | 113 | flag = 1; 114 | while(flag){ 115 | if (stat(filePath, &statbuf) < 0) 116 | error("monitorArch stat"); 117 | 118 | char cmp[21]; 119 | strftime (cmp, 21 ,"_%F_%T\n", localtime((const time_t *)&statbuf.st_mtime)); 120 | if (strcmp(info->time, cmp) != 0){ 121 | howManyChanges++; 122 | char archPathWithName[120]; 123 | strcpy(archPathWithName, path); 124 | strcat(archPathWithName, "/archiwum/"); 125 | strcat(archPathWithName, fileName); 126 | strcat(archPathWithName, info->time); 127 | 128 | FILE * newFile = fopen(archPathWithName, "w"); 129 | if ( !file ) error("archPathWithName fopen"); 130 | 131 | fprintf(newFile, "%s", info->content); 132 | fclose(newFile); 133 | 134 | info = copyFileToMemory(filePath); 135 | } 136 | sleep(seconds); 137 | } 138 | fclose(file); 139 | return howManyChanges; 140 | } 141 | 142 | void monitorArchHelper(char * listFileName){ 143 | FILE* file = fopen(listFileName, "r"); 144 | if ( !file ) error("monitorArchHelper fopen"); 145 | 146 | howMany = 0; 147 | char line[80]; 148 | while (fgets(line, sizeof(line), file)) { 149 | char * name; 150 | char * path; 151 | int seconds; 152 | 153 | char * ptr = strtok(line, " "); 154 | name = ptr; 155 | ptr = strtok(NULL, " "); 156 | path = ptr; 157 | ptr = strtok(NULL, " "); 158 | seconds = atoi(ptr); 159 | 160 | pid_t pid = fork(); 161 | if (pid < 0) error("fork"); 162 | if (pid == 0){ 163 | int returned = monitorArch(name, path, seconds); 164 | exit(returned); 165 | } 166 | else { 167 | printf("Process %d monitors %s.\n", pid, name); 168 | pids[howMany] = pid; 169 | isRunning[howMany] = 1; 170 | } 171 | howMany++; 172 | } 173 | fclose(file); 174 | 175 | parentFlag = 1; 176 | 177 | signal(SIGINT, sigintHandler); 178 | while(parentFlag){ 179 | char command[50]; 180 | if (fgets(command, 50, stdin) == NULL){ 181 | error("Bad fgets: probably too long string"); 182 | } 183 | 184 | char * cmd; // 6 185 | char * arg; // 4 186 | if ((cmd = strtok(command, " \n")) == NULL){ 187 | cmd = ""; 188 | } 189 | arg = strtok(NULL, "\n"); 190 | 191 | if (strcmp(cmd, "LIST") == 0){ 192 | LIST(); 193 | } else 194 | if (strcmp(cmd, "STOP") == 0){ 195 | if (strcmp(arg, "ALL") == 0){ 196 | STOPALL(); 197 | } 198 | else{ 199 | STOPPID(atoi(arg)); 200 | } 201 | } else 202 | if (strcmp(cmd, "START") == 0){ 203 | if (strcmp(arg, "ALL") == 0){ 204 | STARTALL(); 205 | } 206 | else{ 207 | STARTPID(atoi(arg)); 208 | } 209 | } else 210 | if (strcmp(cmd, "END") == 0){ 211 | END(); 212 | } 213 | else printf("BAD COMMAND\n"); 214 | cmd = ""; 215 | arg = ""; 216 | } 217 | } 218 | 219 | int main(int argc, char * argv[]){ 220 | /// argv[1] = nazwa pliku z listą 221 | if (argc != 2) 222 | error("Wrong arguments number"); 223 | 224 | initPidList(); 225 | monitorArchHelper(argv[1]); 226 | 227 | return 0; 228 | } 229 | 230 | /** ----------- COMMANDS -------------- */ 231 | 232 | void LIST(){ 233 | int i; 234 | for (i = 0; i < howMany; ++i){ 235 | if (isRunning[i]) 236 | printf("Process %d is running.\n", pids[i]); 237 | else 238 | printf("Process %d is blocked.\n", pids[i]); 239 | } 240 | } 241 | 242 | void STOPPID(pid_t pid){ // SIGUSR1 243 | int i; 244 | for (i = 0; i < howMany; ++i){ 245 | if (pids[i] == pid){ 246 | isRunning[i] = 0; 247 | break; 248 | } 249 | } 250 | kill(pid, SIGUSR1); 251 | } 252 | 253 | void STOPALL(){ 254 | int i; 255 | for (i = 0; i < howMany; ++i){ 256 | isRunning[i] = 0; 257 | STOPPID(pids[i]); 258 | } 259 | } 260 | 261 | void STARTPID(pid_t pid){ // SIGUSR2 262 | int i; 263 | for (i = 0; i < howMany; ++i){ 264 | if (pids[i] == pid){ 265 | isRunning[i] = 1; 266 | break; 267 | } 268 | } 269 | kill(pid, SIGUSR2); 270 | } 271 | 272 | void STARTALL(){ 273 | int i; 274 | for (i = 0; i < howMany; ++i){ 275 | isRunning[i] = 1; 276 | STARTPID(pids[i]); 277 | } 278 | } 279 | 280 | void END(){ // SIGRTMAX 281 | int i; 282 | for (i = 0; i < howMany; ++i){ 283 | pid_t pid = pids[i]; 284 | kill(pid, SIGRTMAX); 285 | } 286 | parentFlag = 0; 287 | 288 | for (i = 0; i < howMany; ++i){ 289 | pid_t pid = pids[i]; 290 | wait(&pids[i]); 291 | if (WIFEXITED(pids[i])){ 292 | pid_t ret = WEXITSTATUS(pids[i]); 293 | printf("Process %d created %d file copies.\n", pid, ret); 294 | } 295 | } 296 | exit(0); 297 | } 298 | -------------------------------------------------------------------------------- /04. Signals/zad2/tester.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define ITERS 5 11 | 12 | void error(char *msg){ 13 | printf("%s", msg); 14 | exit(EXIT_FAILURE); 15 | } 16 | 17 | int main(int argc, char * argv[]){ 18 | /// argv[1] = plik 19 | /// argv[2] = pmin 20 | /// argv[3] = pmax 21 | /// argv[4] = bytes 22 | srand(time(NULL)); 23 | if (argc != 6) error("Bad arguments number"); 24 | 25 | 26 | int pmin = atoi(argv[2]); 27 | int pmax = atoi(argv[3]); 28 | char * bytes = argv[4];//atoi(argv[4]); 29 | int progSeconds = atoi(argv[5]); 30 | 31 | time_t rawtime; 32 | struct tm * timeinfo; 33 | 34 | int i; 35 | while(++i){ 36 | // for (i = 0; i < ITERS; ++i){ 37 | FILE * file = fopen(argv[1], "a"); 38 | if (!file) error("fopen"); 39 | 40 | pid_t pid = getpid(); 41 | int waitSeconds = rand() % (pmax - pmin) + pmin; 42 | time ( &rawtime ); 43 | timeinfo = localtime ( &rawtime ); 44 | char string[atoi(bytes)+1]; 45 | string[atoi(bytes)] = '\0'; 46 | int j; 47 | for (j = 0; j < atoi(bytes); j++){ 48 | string[j] = '0' + rand() % 72; 49 | } 50 | 51 | fprintf(file, "%d %d %s %s\n" 52 | ,pid 53 | ,waitSeconds 54 | ,strtok(asctime(timeinfo), "\n") 55 | ,string 56 | ); 57 | fclose(file); 58 | sleep(waitSeconds); 59 | if (i * waitSeconds > progSeconds) break; 60 | } 61 | 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /04. Signals/zad3/a/catcher.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | volatile pid_t sendersPid; 9 | volatile int signalsReceived = 0; 10 | 11 | void error(char *msg){ 12 | perror(msg); 13 | exit(EXIT_FAILURE); 14 | } 15 | 16 | void sigusrHandler(int signum){ 17 | if (signum == SIGUSR1){ 18 | signalsReceived++; 19 | 20 | struct sigaction action; 21 | 22 | sigfillset(&action.sa_mask); 23 | sigdelset(&action.sa_mask, SIGUSR1); 24 | sigdelset(&action.sa_mask, SIGUSR2); 25 | 26 | action.sa_flags = 0; 27 | action.sa_handler = sigusrHandler; 28 | 29 | sigsuspend(&action.sa_mask); 30 | } 31 | else if (signum == SIGUSR2){ 32 | sigset_t mask; 33 | sigfillset(&mask); 34 | sigprocmask(SIG_SETMASK, &mask, NULL); 35 | } 36 | else error("Bad signal"); 37 | } 38 | 39 | void sigusrHandlerSA(int signum, siginfo_t * info, void * context){ 40 | if (signum == SIGUSR1){ 41 | sendersPid = info->si_pid; 42 | signalsReceived++; 43 | 44 | struct sigaction action; 45 | 46 | sigfillset(&action.sa_mask); 47 | sigdelset(&action.sa_mask, SIGUSR1); 48 | sigdelset(&action.sa_mask, SIGUSR2); 49 | 50 | action.sa_flags = 0; 51 | action.sa_handler= sigusrHandler; 52 | 53 | if (sigaction(SIGUSR1, &action, NULL) != 0) error("sigaction1 in self handler"); 54 | if (sigaction(SIGUSR2, &action, NULL) != 0) error("sigaction1 in self handler"); 55 | 56 | sigsuspend(&action.sa_mask); 57 | } 58 | else if (signum == SIGUSR2){ 59 | sendersPid = info->si_pid; 60 | sigset_t mask; 61 | sigfillset(&mask); 62 | sigprocmask(SIG_SETMASK, &mask, NULL); 63 | } 64 | else error("Bad signal"); 65 | } 66 | 67 | /// ---------- REAL TIME ------------ 68 | void sigRTHandler(int signum){ 69 | if (signum == SIGRTMIN){ 70 | signalsReceived++; 71 | 72 | struct sigaction action; 73 | 74 | sigfillset(&action.sa_mask); 75 | sigdelset(&action.sa_mask, SIGRTMIN); 76 | sigdelset(&action.sa_mask, SIGRTMAX); 77 | 78 | action.sa_flags = 0; 79 | action.sa_handler= sigRTHandler; 80 | 81 | //if (sigaction(SIGRTMIN, &action, NULL) != 0) error("sigaction1 in self handler"); 82 | //if (sigaction(SIGRTMAX, &action, NULL) != 0) error("sigaction1 in self handler"); 83 | 84 | sigsuspend(&action.sa_mask); 85 | } 86 | else if (signum == SIGRTMAX){ 87 | sigset_t mask; 88 | sigfillset(&mask); 89 | sigprocmask(SIG_SETMASK, &mask, NULL); 90 | } 91 | else error("Bad signal"); 92 | } 93 | 94 | void sigRTHandlerSA(int signum, siginfo_t * info, void * context){ 95 | if (signum == SIGRTMIN){ 96 | sendersPid = info->si_pid; 97 | signalsReceived++; 98 | 99 | struct sigaction action; 100 | 101 | sigfillset(&action.sa_mask); 102 | sigdelset(&action.sa_mask, SIGRTMIN); 103 | sigdelset(&action.sa_mask, SIGRTMAX); 104 | 105 | action.sa_flags = 0; 106 | action.sa_handler= sigRTHandler; 107 | 108 | if (sigaction(SIGRTMIN, &action, NULL) != 0) error("sigaction1 in self handler"); 109 | if (sigaction(SIGRTMAX, &action, NULL) != 0) error("sigaction1 in self handler"); 110 | 111 | sigsuspend(&action.sa_mask); 112 | } 113 | else if (signum == SIGRTMAX){ 114 | sendersPid = info->si_pid; 115 | sigset_t mask; 116 | sigfillset(&mask); 117 | sigprocmask(SIG_SETMASK, &mask, NULL); 118 | } 119 | else error("Bad signal"); 120 | } 121 | 122 | /// ----------- MODES ------------- 123 | 124 | void killMode(){ 125 | int i; 126 | for (i = 0; i < signalsReceived; ++i){ 127 | kill(sendersPid, SIGUSR1); 128 | } 129 | sleep(0.2); 130 | kill(sendersPid, SIGUSR2); 131 | kill(sendersPid, SIGUSR2); 132 | kill(sendersPid, SIGUSR2); 133 | } 134 | 135 | void queueMode(){ 136 | int i; 137 | union sigval value; 138 | for (i = 0; i < signalsReceived; ++i){ 139 | value.sival_int = i; 140 | sigqueue(sendersPid, SIGUSR1, value); 141 | } 142 | sleep(0.2); 143 | kill(sendersPid, SIGUSR2); 144 | kill(sendersPid, SIGUSR2); 145 | kill(sendersPid, SIGUSR2); 146 | } 147 | 148 | void rtMode(){ 149 | int i; 150 | sleep(1); 151 | for (i = 0; i < signalsReceived; ++i){ 152 | kill(sendersPid, SIGRTMIN); 153 | } 154 | sleep(1); 155 | 156 | kill(sendersPid, SIGRTMAX); 157 | kill(sendersPid, SIGRTMAX); 158 | } 159 | 160 | /// ---------- RECEIVE ----------- 161 | void receiveSignals(){ 162 | printf("My pid is %d.\n", getpid()); 163 | 164 | struct sigaction action; 165 | 166 | sigfillset(&action.sa_mask); 167 | sigdelset(&action.sa_mask, SIGUSR1); 168 | sigdelset(&action.sa_mask, SIGUSR2); 169 | 170 | action.sa_flags |= SA_SIGINFO; 171 | action.sa_sigaction = sigusrHandlerSA; 172 | 173 | if (sigaction(SIGUSR1, &action, NULL) != 0) error("sigaction1 in receiver"); 174 | if (sigaction(SIGUSR2, &action, NULL) != 0) error("sigaction2 in receiver"); 175 | 176 | pause(); 177 | } 178 | 179 | void receiveRTSignals(){ 180 | printf("My pid is %d.\n", getpid()); 181 | 182 | struct sigaction action; 183 | 184 | sigfillset(&action.sa_mask); 185 | sigdelset(&action.sa_mask, SIGRTMIN); 186 | sigdelset(&action.sa_mask, SIGRTMAX); 187 | 188 | action.sa_flags |= SA_SIGINFO; 189 | action.sa_sigaction = sigRTHandlerSA; 190 | 191 | if (sigaction(SIGRTMIN, &action, NULL) != 0) error("sigaction1 in receiver"); 192 | if (sigaction(SIGRTMAX, &action, NULL) != 0) error("sigaction2 in receiver"); 193 | 194 | pause(); 195 | } 196 | 197 | int main(int argc, char ** argv){ 198 | if (argc != 2) error("Bad args number"); 199 | char * mode = argv[1]; 200 | 201 | if (strcmp(mode, "KILL") == 0){ 202 | receiveSignals(); 203 | killMode(); 204 | printf("Got %d SIGUSR1 signals from %d.\n", signalsReceived, sendersPid); 205 | } 206 | else if (strcmp(mode, "SIGQUEUE") == 0){ 207 | receiveSignals(); 208 | queueMode(); 209 | printf("Got %d SIGUSR1 signals from %d.\n", signalsReceived, sendersPid); 210 | } 211 | else if (strcmp(mode, "SIGRT") == 0){ 212 | receiveRTSignals(); 213 | rtMode(); 214 | printf("Got %d SIGRTMIN signals from %d.\n", signalsReceived, sendersPid); 215 | } 216 | else error("Bad first arg"); 217 | 218 | return 0; 219 | } 220 | -------------------------------------------------------------------------------- /04. Signals/zad3/a/makefile: -------------------------------------------------------------------------------- 1 | CC = gcc -Wall -o 2 | 3 | make clean: 4 | rm -f *.o 5 | rm -f *.a 6 | rm -f main 7 | rm -f catcher 8 | rm -f sender 9 | 10 | make compile: 11 | $(CC) sender sender.c && $(CC) catcher catcher.c 12 | 13 | make kill: 14 | ./catcher KILL 15 | 16 | make queue: 17 | ./catcher SIGQUEUE 18 | 19 | make rt: 20 | ./catcher SIGRT 21 | -------------------------------------------------------------------------------- /04. Signals/zad3/a/sender.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | volatile pid_t catchersPid; 9 | volatile int signalsSent; 10 | volatile int signalsReceived = 0; 11 | volatile int msgs[100]; 12 | volatile int counter = 0; 13 | 14 | 15 | void error(char *msg){ 16 | perror(msg); 17 | exit(EXIT_FAILURE); 18 | } 19 | 20 | /// ---------- HANDLERS ------------- 21 | void sigusrHandler(int signum){ 22 | sigset_t mask; 23 | sigfillset(&mask); 24 | if (signum == SIGUSR1){ 25 | signalsReceived++; 26 | sigdelset(&mask, SIGUSR1); 27 | sigdelset(&mask, SIGUSR2); 28 | sigsuspend(&mask); 29 | } 30 | else if (signum == SIGUSR2){ 31 | sigprocmask(SIG_SETMASK, &mask, NULL); 32 | } 33 | else error("Bad signalin sigusr handler"); 34 | } 35 | 36 | void sigusrHandler2(int signum, siginfo_t * info, void * context){ 37 | if (signum == SIGUSR1){ 38 | signalsReceived++; 39 | 40 | struct sigaction action; 41 | 42 | sigfillset(&action.sa_mask); 43 | sigdelset(&action.sa_mask, SIGUSR1); 44 | sigdelset(&action.sa_mask, SIGUSR2); 45 | 46 | action.sa_flags |= SA_SIGINFO; 47 | action.sa_sigaction = sigusrHandler2; 48 | 49 | if (sigaction(SIGUSR1, &action, NULL) != 0) error("sigaction1 in sigusrHandler2"); 50 | 51 | msgs[counter++] = info->si_value.sival_int; 52 | 53 | sigsuspend(&action.sa_mask); 54 | } 55 | else if (signum == SIGUSR2){ 56 | sigset_t mask; 57 | sigfillset(&mask); 58 | sigprocmask(SIG_SETMASK, &mask, NULL); 59 | } 60 | else error("Bad signal in sigusr2 handler"); 61 | } 62 | 63 | void sigRTHandler(int signum){ 64 | sigset_t mask; 65 | sigfillset(&mask); 66 | if (signum == SIGRTMIN){ 67 | signalsReceived++; 68 | sigdelset(&mask, SIGRTMIN); 69 | sigdelset(&mask, SIGRTMAX); 70 | sigsuspend(&mask); 71 | } 72 | else if (signum == SIGRTMAX){ 73 | sigprocmask(SIG_SETMASK, &mask, NULL); 74 | } 75 | else error("Bad signal in sigrt handler"); 76 | } 77 | 78 | 79 | /// ----------- RECEIVE ------------- 80 | void receiveSignals(){ 81 | struct sigaction action; 82 | 83 | sigfillset(&action.sa_mask); 84 | sigdelset(&action.sa_mask, SIGUSR1); 85 | sigdelset(&action.sa_mask, SIGUSR2); 86 | 87 | action.sa_flags = 0; 88 | action.sa_handler= sigusrHandler; 89 | 90 | if (sigaction(SIGUSR1, &action, NULL) != 0) error("sigaction1 in receiver"); 91 | if (sigaction(SIGUSR2, &action, NULL) != 0) error("sigaction2 in receiver"); 92 | 93 | pause(); 94 | } 95 | 96 | void receiveSignalsQueue(){ 97 | struct sigaction action; 98 | 99 | sigfillset(&action.sa_mask); 100 | sigdelset(&action.sa_mask, SIGUSR1); 101 | sigdelset(&action.sa_mask, SIGUSR2); 102 | 103 | action.sa_flags |= SA_SIGINFO; 104 | action.sa_sigaction = sigusrHandler2; 105 | 106 | if (sigaction(SIGUSR1, &action, NULL) != 0) error("sigaction1 in receiver"); 107 | if (sigaction(SIGUSR2, &action, NULL) != 0) error("sigaction2 in receiver"); 108 | 109 | pause(); 110 | } 111 | 112 | void receiveSignalsRT(){ 113 | struct sigaction action; 114 | 115 | sigfillset(&action.sa_mask); 116 | sigdelset(&action.sa_mask, SIGRTMIN); 117 | sigdelset(&action.sa_mask, SIGRTMAX); 118 | 119 | action.sa_flags = 0; 120 | action.sa_handler= sigRTHandler; 121 | 122 | if (sigaction(SIGRTMIN, &action, NULL) != 0) error("sigaction1 in receiver"); 123 | if (sigaction(SIGRTMAX, &action, NULL) != 0) error("sigaction2 in receiver"); 124 | 125 | pause(); 126 | } 127 | 128 | /// ------------- SEND -------------- 129 | void killMode(){ 130 | int i; 131 | for (i = 0; i < signalsSent; ++i){ 132 | kill(catchersPid, SIGUSR1); 133 | } 134 | sleep(0.2); 135 | kill(catchersPid, SIGUSR2); 136 | kill(catchersPid, SIGUSR2); 137 | 138 | receiveSignals(); 139 | } 140 | 141 | void queueMode(){ 142 | int i; 143 | for (i = 0; i < signalsSent; ++i){ 144 | kill(catchersPid, SIGUSR1); 145 | } 146 | sleep(0.2); 147 | kill(catchersPid, SIGUSR2); 148 | kill(catchersPid, SIGUSR2); 149 | 150 | receiveSignalsQueue(); 151 | } 152 | 153 | void rtMode(){ 154 | int i; 155 | for (i = 0; i < signalsSent; ++i){ 156 | kill(catchersPid, SIGRTMIN); 157 | } 158 | sleep(1); 159 | kill(catchersPid, SIGRTMAX); 160 | kill(catchersPid, SIGRTMAX); 161 | 162 | receiveSignalsRT(); 163 | } 164 | 165 | /// ------------- MAIN ---------------- 166 | int main(int argc, char ** argv){ 167 | /// argv[1] = PID catchera 168 | /// argv[2] = how many signals to send 169 | /// argv[3] = mode of signal sending 170 | 171 | if (argc != 4) error("Bad args number"); 172 | catchersPid = atoi(argv[1]); 173 | signalsSent = atoi(argv[2]); 174 | char * mode = argv[3]; 175 | 176 | if (strcmp(mode, "KILL") == 0){ 177 | killMode(); 178 | } 179 | else if (strcmp(mode, "SIGQUEUE") == 0){ 180 | queueMode(); 181 | int i; 182 | for (i = 0; i < counter; ++i){ 183 | printf("Received %dth signal number %d.\n", i, msgs[i]); 184 | } 185 | } 186 | else if (strcmp(mode, "SIGRT") == 0){ 187 | rtMode(); 188 | } 189 | else error("Bad third arg"); 190 | 191 | printf("Sent %d signals to %d and received %d.\n", signalsSent, catchersPid, signalsReceived); 192 | 193 | return 0; 194 | } 195 | -------------------------------------------------------------------------------- /04. Signals/zad3/b/catcher.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | volatile pid_t sendersPid; 9 | volatile int signalsReceived = 0; 10 | volatile int whichSent = 0; 11 | 12 | void error(char *msg){ 13 | perror(msg); 14 | exit(EXIT_FAILURE); 15 | } 16 | 17 | /// --------- KILL ---------- 18 | void killHandler(int signum){ 19 | if (signum == SIGUSR1){ 20 | signalsReceived++; 21 | 22 | sigset_t mask; 23 | sigfillset(&mask); 24 | sigdelset(&mask, SIGUSR1); 25 | sigdelset(&mask, SIGUSR2); 26 | kill(sendersPid, SIGUSR1); 27 | sigsuspend(&mask); 28 | 29 | } 30 | else if (signum == SIGUSR2){ 31 | kill(sendersPid, SIGUSR1); 32 | } 33 | else error("Bad signal in handler"); 34 | } 35 | 36 | void killHandlerSA(int signum, siginfo_t * info, void * context){ 37 | if (signum == SIGUSR1){ 38 | sendersPid = info->si_pid; 39 | signalsReceived++; 40 | 41 | struct sigaction action; 42 | action.sa_handler = killHandler; 43 | action.sa_flags = 0; 44 | sigfillset(&action.sa_mask); 45 | sigdelset(&action.sa_mask, SIGUSR1); 46 | sigdelset(&action.sa_mask, SIGUSR2); 47 | 48 | sigaction(SIGUSR1, &action, NULL); 49 | sigaction(SIGUSR2, &action, NULL); 50 | 51 | kill(sendersPid, SIGUSR1); 52 | 53 | sigsuspend(&action.sa_mask); 54 | } 55 | else if (signum == SIGUSR2){ 56 | kill(sendersPid, SIGUSR1); 57 | } 58 | else error("Bad signal in handler"); 59 | } 60 | 61 | void killMode(){ 62 | printf("My pid is %d.\n", getpid()); 63 | 64 | struct sigaction action; 65 | action.sa_sigaction = killHandlerSA; 66 | action.sa_flags |= SA_SIGINFO; 67 | sigfillset(&action.sa_mask); 68 | sigdelset(&action.sa_mask, SIGUSR1); 69 | sigdelset(&action.sa_mask, SIGUSR2); 70 | 71 | sigaction(SIGUSR1, &action, NULL); 72 | sigaction(SIGUSR2, &action, NULL); 73 | 74 | sigsuspend(&action.sa_mask); 75 | } 76 | 77 | /// -------- QUEUE ---------- 78 | /** 79 | void queueHandler(int signum){ 80 | if (signum == SIGUSR1){ 81 | signalsReceived++; 82 | 83 | union sigval value; 84 | value.sival_int = whichSent++; 85 | 86 | sigset_t mask; 87 | sigfillset(&mask); 88 | sigdelset(&mask, SIGUSR1); 89 | sigdelset(&mask, SIGUSR2); 90 | kill(sendersPid, SIGUSR1); 91 | 92 | sigqueue(sendersPid, SIGUSR1, value); 93 | 94 | sigsuspend(&mask); 95 | } 96 | else if (signum == SIGUSR2){ 97 | union sigval value; 98 | value.sival_int = whichSent; 99 | sigqueue(sendersPid, SIGUSR1, value); 100 | } 101 | else error("Bad signal in handler"); 102 | } 103 | */ 104 | void queueHandlerSA(int signum, siginfo_t * info, void * context){ // mozna dodac pozniej zwykly handler 105 | if (signum == SIGUSR1){ 106 | sendersPid = info->si_pid; 107 | signalsReceived++; 108 | 109 | union sigval value; 110 | value.sival_int = whichSent++; 111 | 112 | struct sigaction action; 113 | action.sa_sigaction = queueHandlerSA; 114 | action.sa_flags = SA_SIGINFO; 115 | sigfillset(&action.sa_mask); 116 | sigdelset(&action.sa_mask, SIGUSR1); 117 | sigdelset(&action.sa_mask, SIGUSR2); 118 | 119 | sigaction(SIGUSR1, &action, NULL); 120 | sigaction(SIGUSR2, &action, NULL); 121 | 122 | sigqueue(sendersPid, SIGUSR1, value); 123 | 124 | sigsuspend(&action.sa_mask); 125 | } 126 | else if (signum == SIGUSR2){ 127 | union sigval value; 128 | value.sival_int = whichSent; 129 | sigqueue(sendersPid, SIGUSR1, value); 130 | } 131 | else error("Bad signal in handler"); 132 | } 133 | 134 | void queueMode(){ 135 | printf("My pid is %d.\n", getpid()); 136 | 137 | struct sigaction action; 138 | action.sa_sigaction = queueHandlerSA; 139 | action.sa_flags |= SA_SIGINFO; 140 | sigfillset(&action.sa_mask); 141 | sigdelset(&action.sa_mask, SIGUSR1); 142 | sigdelset(&action.sa_mask, SIGUSR2); 143 | 144 | sigaction(SIGUSR1, &action, NULL); 145 | sigaction(SIGUSR2, &action, NULL); 146 | 147 | sigsuspend(&action.sa_mask); 148 | } 149 | 150 | /// --------- REAL TIME ----------- 151 | void rtHandler(int signum){ 152 | 153 | } 154 | 155 | void rtHandlerSA(int signum, siginfo_t * info, void * context){ 156 | if (signum == SIGRTMIN){ 157 | sendersPid = info->si_pid; 158 | signalsReceived++; 159 | 160 | struct sigaction action; 161 | 162 | sigfillset(&action.sa_mask); 163 | sigdelset(&action.sa_mask, SIGRTMIN); 164 | sigdelset(&action.sa_mask, SIGRTMAX); 165 | 166 | action.sa_flags = SA_SIGINFO; 167 | action.sa_sigaction = rtHandlerSA; 168 | 169 | if (sigaction(SIGRTMIN, &action, NULL) != 0) error("sigaction1 in self handler"); 170 | if (sigaction(SIGRTMAX, &action, NULL) != 0) error("sigaction1 in self handler"); 171 | 172 | kill(sendersPid, SIGRTMIN); 173 | 174 | sigsuspend(&action.sa_mask); 175 | } 176 | else if (signum == SIGRTMAX){ 177 | sendersPid = info->si_pid; 178 | kill(sendersPid, SIGRTMIN); 179 | } 180 | else error("Bad signal"); 181 | } 182 | 183 | void rtMode(){ 184 | printf("My pid is %d.\n", getpid()); 185 | 186 | struct sigaction action; 187 | action.sa_sigaction = rtHandlerSA; 188 | action.sa_flags |= SA_SIGINFO; 189 | sigfillset(&action.sa_mask); 190 | sigdelset(&action.sa_mask, SIGRTMIN); 191 | sigdelset(&action.sa_mask, SIGRTMAX); 192 | 193 | sigaction(SIGRTMIN, &action, NULL); 194 | sigaction(SIGRTMAX, &action, NULL); 195 | 196 | sigsuspend(&action.sa_mask); 197 | } 198 | 199 | int main(int argc, char ** argv){ 200 | if (argc != 2) error("Bad args number"); 201 | char * mode = argv[1]; 202 | 203 | if (strcmp(mode, "KILL") == 0){ 204 | killMode(); 205 | printf("Got %d SIGUSR1 signals.\n", signalsReceived); 206 | } 207 | else if (strcmp(mode, "SIGQUEUE") == 0){ 208 | queueMode(); 209 | printf("Got %d SIGUSR1 signals from %d.\n", signalsReceived, sendersPid); 210 | } 211 | else if (strcmp(mode, "SIGRT") == 0){ 212 | rtMode(); 213 | printf("Got %d SIGRTMIN signals from %d.\n", signalsReceived, sendersPid); 214 | } 215 | else error("Bad first arg"); 216 | 217 | return 0; 218 | } 219 | -------------------------------------------------------------------------------- /04. Signals/zad3/b/makefile: -------------------------------------------------------------------------------- 1 | CC = gcc -Wall -o 2 | 3 | make clean: 4 | rm -f *.o 5 | rm -f *.a 6 | rm -f main 7 | rm -f catcher 8 | rm -f sender 9 | 10 | make compile: 11 | $(CC) sender sender.c && $(CC) catcher catcher.c 12 | 13 | make kill: 14 | ./catcher KILL 15 | 16 | make queue: 17 | ./catcher SIGQUEUE 18 | 19 | make rt: 20 | ./catcher SIGRT 21 | -------------------------------------------------------------------------------- /04. Signals/zad3/b/sender.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | volatile pid_t catchersPid; 9 | volatile int signalsSent; 10 | volatile int signalsReceived = 0; 11 | volatile int msgs[2000]; 12 | volatile int counter = 0; 13 | 14 | 15 | void error(char *msg){ 16 | perror(msg); 17 | exit(EXIT_FAILURE); 18 | } 19 | 20 | /// ------------- KILL -------------- 21 | void killHandler(int signum){ 22 | signalsReceived++; 23 | } 24 | 25 | void killMode(){ 26 | int i; 27 | 28 | struct sigaction action; 29 | action.sa_handler = killHandler; 30 | sigfillset(&action.sa_mask); 31 | sigdelset(&action.sa_mask, SIGUSR1); 32 | action.sa_flags = 0; 33 | sigaction(SIGUSR1, &action, NULL); 34 | 35 | for (i = 0; i < signalsSent; ++i){ 36 | kill(catchersPid, SIGUSR1); 37 | sigsuspend(&action.sa_mask); 38 | } 39 | 40 | kill(catchersPid, SIGUSR2); 41 | sigsuspend(&action.sa_mask); 42 | } 43 | 44 | /// --------- QUEUE ---------- 45 | void queueHandlerSA(int signum, siginfo_t * info, void * context){ 46 | signalsReceived++; 47 | msgs[counter++] = info->si_value.sival_int; 48 | } 49 | 50 | void queueMode(){ 51 | int i; 52 | 53 | struct sigaction action; 54 | action.sa_sigaction = queueHandlerSA; 55 | sigfillset(&action.sa_mask); 56 | sigdelset(&action.sa_mask, SIGUSR1); 57 | action.sa_flags = SA_SIGINFO; 58 | sigaction(SIGUSR1, &action, NULL); 59 | 60 | union sigval value; 61 | 62 | for (i = 0; i < signalsSent; ++i){ 63 | sigqueue(catchersPid, SIGUSR1, value); 64 | sigsuspend(&action.sa_mask); 65 | } 66 | 67 | sigqueue(catchersPid, SIGUSR2, value); 68 | sigsuspend(&action.sa_mask); 69 | } 70 | 71 | /// -------- REAL TIME --------- 72 | void rtHandler(int signum){ 73 | signalsReceived++; 74 | } 75 | 76 | void rtMode(){ 77 | int i; 78 | 79 | struct sigaction action; 80 | action.sa_handler = killHandler; 81 | sigfillset(&action.sa_mask); 82 | sigdelset(&action.sa_mask, SIGRTMIN); 83 | action.sa_flags = 0; 84 | sigaction(SIGRTMIN, &action, NULL); 85 | 86 | for (i = 0; i < signalsSent; ++i){ 87 | kill(catchersPid, SIGRTMIN); 88 | sigsuspend(&action.sa_mask); 89 | } 90 | 91 | kill(catchersPid, SIGRTMAX); 92 | sigsuspend(&action.sa_mask); 93 | } 94 | 95 | /// ------------- MAIN ---------------- 96 | int main(int argc, char ** argv){ 97 | /// argv[1] = PID catchera 98 | /// argv[2] = how many signals to send 99 | /// argv[3] = mode of signal sending 100 | 101 | if (argc != 4) error("Bad args number"); 102 | catchersPid = atoi(argv[1]); 103 | signalsSent = atoi(argv[2]); 104 | char * mode = argv[3]; 105 | 106 | if (strcmp(mode, "KILL") == 0){ 107 | killMode(); 108 | } 109 | else if (strcmp(mode, "SIGQUEUE") == 0){ 110 | queueMode(); 111 | int i; 112 | for (i = 0; i < counter; ++i){ 113 | printf("Received %dth signal number %d.\n", i, msgs[i]); 114 | } 115 | } 116 | else if (strcmp(mode, "SIGRT") == 0){ 117 | rtMode(); 118 | } 119 | else error("Bad third arg"); 120 | 121 | printf("Sent %d signals to %d and received %d.\n", signalsSent, catchersPid, signalsReceived); 122 | 123 | return 0; 124 | } 125 | -------------------------------------------------------------------------------- /05. Inter-process communication(pipeline)/README.md: -------------------------------------------------------------------------------- 1 | # Zadanie 1 (55%) 2 | 3 | Napisz interpreter poleceń przechowywanych w pliku (sciezka do pliku to pierwszy argument wywolania programu). 4 | 5 | Polecenia w pliku przechowywane są w kolejnych liniach w postaci: 6 | 7 | prog1 arg1 ... argn1 | prog2 arg1 ... argn2 | ... | progN arg1 ... argnN 8 | 9 | Dla każdej takiej linii interpreter powinien uruchomić wszystkie N poleceń w osobnych procesach, zapewniając przy użyciu potoków nienazwanych oraz funkcji dup2, by wyjście standardowe procesu k było przekierowane do wejścia standardowego procesu (k+1). Można założyć ograniczenie górne na ilość obsługiwanych argumentów oraz ilość połączonych komend w pojedynczym poleceniu (co najmniej 5). Po uruchomieniu ciągu programów składających się na pojedczyne polecenie (linijkę) interpreter powinien oczekiwać na zakończenie wszystkich tych programów. 10 | 11 | Uwaga: należy użyć pipe/fork/exec, nie popen 12 | 13 | # Zadanie 2 (45%) 14 | 15 | Należy napisać dwa programy - master oraz slave - które będą komunikować się poprzez potok nazwany (kolejkę FIFO), do której ścieżkę będą dostawać jako argument wywołania. Do potoku pisać będzie wiele procesów wykonujących program slave, a czytał będzie z niej jeden proces master. 16 | 17 | Master przyjmuje jeden argument - ścieżkę do potoku nazwanego. Tworzy on ten potok nazwany, a następnie czyta kolejne linijki z potoku nazwanego i wypisuje je na ekran. 18 | 19 | Slave przyjmuje dwa argumenty - ścieżkę do potoku nazwanego i liczbę całkowitą N. Wykonuje następujące akcje: 20 | 21 | otwiera potok nazwany 22 | wypisuje swój PID na wyjście standardowe 23 | N razy zapisuje do potoku nazwanego linijkę składającą się ze swojego PIDu oraz obecnej daty 24 | datę należy wygenerować programem date uruchomionym przy użyciu funkcji popen 25 | po każdym zapisie należy odczekać losową ilość czasu (np. 2-5 sekund) 26 | -------------------------------------------------------------------------------- /05. Inter-process communication(pipeline)/zad1/commands.txt: -------------------------------------------------------------------------------- 1 | ps aux | wc -l 2 | ps aux | grep "grep" 3 | ls -l | grep Apr | head -n 1 4 | cat sample.txt | grep -v a | sort 5 | -------------------------------------------------------------------------------- /05. Inter-process communication(pipeline)/zad1/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define MAX_CMDS 5 9 | 10 | void error(char * msg){ 11 | perror(msg); 12 | exit(EXIT_FAILURE); 13 | } 14 | 15 | char ** splitCommands(char * line){ 16 | int count = 0; 17 | char ** args = NULL; 18 | char delims[2] = {' ', '\n'}; 19 | line = strtok(line, delims); 20 | while (line){ 21 | count++; 22 | args = realloc(args, count * sizeof(char*)); 23 | args[count - 1] = line; 24 | line = strtok(NULL, delims); 25 | } 26 | args = realloc(args, (count + 1) * sizeof(char*)); 27 | args[count] = NULL; 28 | 29 | return args; 30 | } 31 | 32 | int executeLine(char * line, ssize_t len){ 33 | int i; 34 | int pipes[2][2]; 35 | int cmdsCount = 0; 36 | 37 | char * cmds[MAX_CMDS]; 38 | 39 | line = strtok(line, "|"); 40 | while (line){ 41 | cmds[cmdsCount++] = line; 42 | line = strtok(NULL, "|"); 43 | } 44 | 45 | for (i = 0; i < cmdsCount; ++i){ 46 | 47 | if (i != 0){ 48 | close(pipes[i % 2][0]); 49 | close(pipes[i % 2][1]); 50 | } 51 | 52 | if (pipe(pipes[i % 2]) < 0){ 53 | error("pipe"); 54 | } 55 | 56 | pid_t pid = vfork(); 57 | if (pid == 0){ /// DZIECKO 58 | char ** args = splitCommands(cmds[i]); 59 | 60 | if (i != cmdsCount - 1){ 61 | close(pipes[i % 2][0]); 62 | if (dup2(pipes[i % 2][1], STDOUT_FILENO) < 0){ 63 | error("dup2"); 64 | } 65 | } 66 | 67 | if (i != 0) { 68 | close(pipes[(i+1) % 2][1]); 69 | if (dup2(pipes[(i+1) % 2][0], STDIN_FILENO) < 0){ 70 | error("dup2"); 71 | } 72 | } 73 | 74 | if (execvp(args[0], args) < 0){ 75 | error("execvp"); 76 | } 77 | error("not allowed location"); 78 | } 79 | else if (pid > 0){ 80 | //wait(&pid); 81 | } 82 | else { 83 | error("Bad fork"); 84 | } 85 | } 86 | close(pipes[i % 2][0]); 87 | close(pipes[i % 2][1]); 88 | wait(NULL); 89 | exit(0); 90 | } 91 | 92 | int main(int argc, char ** argv){ 93 | /// argv[1] = file name 94 | if (argc != 2){ 95 | error("Bad args number"); 96 | } 97 | 98 | FILE * fp; 99 | char * line = NULL; 100 | size_t len = 0; 101 | ssize_t read; 102 | fp = fopen(argv[1], "r"); 103 | if (fp == NULL) 104 | error("fopen"); 105 | 106 | while ((read = getline(&line, &len, fp)) != -1) { 107 | pid_t pid = vfork(); 108 | if (pid == 0){ 109 | executeLine(line, read); 110 | error("Bad location"); 111 | } 112 | else if (pid > 0){ 113 | int status; 114 | wait(&status); 115 | if (status){ 116 | error("On status"); 117 | } 118 | } 119 | else{ 120 | error("main fork()"); 121 | } 122 | } 123 | 124 | fclose(fp); 125 | if (line) 126 | free(line); 127 | 128 | return 0; 129 | } 130 | -------------------------------------------------------------------------------- /05. Inter-process communication(pipeline)/zad1/makefile: -------------------------------------------------------------------------------- 1 | CC = gcc -Wall -o 2 | 3 | clean: 4 | rm -f main 5 | 6 | compile: 7 | make clean 8 | $(CC) main main.c 9 | 10 | run: 11 | make compile 12 | ./main commands.txt 13 | -------------------------------------------------------------------------------- /05. Inter-process communication(pipeline)/zad1/sample.txt: -------------------------------------------------------------------------------- 1 | ajgdskgs 2 | lvcxksdf 3 | vncxakdfj 4 | qewopfia 5 | zxcjvkds 6 | akfjds 7 | qwofihds 8 | gjslkjd 9 | xxcxzsdvc 10 | pfoiwefkckj 11 | bcklxxv 12 | zayaaaz 13 | pqoingxzsd 14 | poeirwehkbv 15 | zxbvnghkwt 16 | jkgdioewb 17 | -------------------------------------------------------------------------------- /05. Inter-process communication(pipeline)/zad2/makefile: -------------------------------------------------------------------------------- 1 | CC = gcc -Wall -o 2 | 3 | clean: 4 | rm -f master 5 | rm -f slave 6 | rm -f *.o 7 | rm -f *.a 8 | rm -f nazwa 9 | 10 | compile: 11 | make clean 12 | $(CC) slave slave.c 13 | $(CC) master master.c 14 | 15 | runmaster: 16 | make compile 17 | ./master ./nazwa 18 | 19 | runslave: 20 | ./slave ./nazwa 10 21 | -------------------------------------------------------------------------------- /05. Inter-process communication(pipeline)/zad2/master.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define MAX_CONT_SIZE 256 11 | 12 | void error(char * msg){ 13 | perror(msg); 14 | exit(EXIT_FAILURE); 15 | } 16 | 17 | int main(int argc, char ** argv){ 18 | /// argv[1] = sciezka do potoku nazwanego 19 | if (argc != 2){ 20 | error("Bad args count"); 21 | } 22 | 23 | int fd; 24 | 25 | char buffer[MAX_CONT_SIZE]; 26 | 27 | if (mkfifo(argv[1], 0666) < 0) error("mkfifo"); 28 | 29 | if ((fd = open(argv[1], O_RDONLY)) < 0) error("open"); 30 | while(read(fd, buffer, sizeof(buffer)) > 0){ 31 | printf("%s\n", buffer); 32 | } 33 | if (close(fd) < 0) error("close"); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /05. Inter-process communication(pipeline)/zad2/slave.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define MAX_CONT_SIZE 256 11 | 12 | void error(char * msg){ 13 | perror(msg); 14 | exit(EXIT_FAILURE); 15 | } 16 | 17 | int main(int argc, char ** argv){ 18 | /// argv[1] = sciezka do potoku nazwanego 19 | /// argv[2] = liczba N 20 | if (argc != 3){ 21 | error("Bad args count"); 22 | } 23 | 24 | int fd; 25 | int pid = getpid(); 26 | srand(time(NULL)); 27 | 28 | printf("Moj PID to %d.\n", pid); 29 | 30 | int i; 31 | char buffer[MAX_CONT_SIZE]; 32 | char output[MAX_CONT_SIZE]; 33 | 34 | if ((fd = open(argv[1], O_WRONLY)) < 0) error("open"); 35 | for (i = 0; i < atoi(argv[2]); ++i){ 36 | FILE * pipe = popen("date", "r"); 37 | if (!pipe) error("popen"); 38 | if (!fgets(buffer, MAX_CONT_SIZE, pipe)) error("fgets"); 39 | char * buffer2 = strtok(buffer, "\n"); 40 | if (pclose(pipe) < 0) error("pclose"); 41 | if (sprintf(output, "%d %s", pid, buffer2) < 0) error("sprintf"); 42 | if (write(fd, output, strlen(output)) < 0) error("write"); 43 | sleep((rand() % 3 + 1)); 44 | } 45 | 46 | if (close(fd) < 0) error("close"); 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /05. Inter-process communication(pipeline)/zajecia.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char ** argv){ 6 | char nazwa[100]; 7 | strcpy(nazwa, "cat "); 8 | strcat(nazwa, argv[1]); 9 | strcat(nazwa, " | sort "); 10 | 11 | if (argc == 2){ 12 | FILE * result = popen(nazwa, "w"); 13 | fseek(result, 0L, SEEK_END); 14 | int size = ftell(result); 15 | fseek(result, 0L, SEEK_SET); 16 | 17 | char * buffer = (char*)calloc(size, sizeof(char)); 18 | fread(buffer, sizeof(char), size, result); 19 | printf("%s", buffer); 20 | 21 | pclose(result); 22 | } 23 | else if (argc == 3){ 24 | strcat(nazwa, "> "); 25 | strcat(nazwa, argv[2]); 26 | 27 | FILE * result = popen(nazwa, "w"); 28 | 29 | pclose(result); 30 | } 31 | else 32 | printf("BLAD"); 33 | } 34 | 35 | /// WERSJA 1 36 | /// cat plik | sort A wykonac i wyswietlic wynik 37 | -------------------------------------------------------------------------------- /06. Inter-process communication(queue message)/README.md: -------------------------------------------------------------------------------- 1 | # Zadanie 1. Prosty chat - System V (50%) 2 | 3 | Napisz prosty chat typu klient-serwer, w którym komunikacja zrealizowana jest za pomocą kolejek komunikatów - jedna, na zlecenia klientów dla serwera, druga, prywatna, na odpowiedzi. 4 | 5 | Serwer po uruchomieniu tworzy nową kolejkę komunikatów systemu V. Za pomocą tej kolejki klienci będą wysyłać komunikaty do serwera. Wysyłane zlecenia mają zawierać rodzaj zlecenia jako rodzaj komunikatu oraz informację od którego klienta zostały wysłane (ID klienta), w odpowiedzi rodzajem komunikatu ma być informacja identyfikująca czekającego na nią klienta. 6 | 7 | Klient bezpośrednio po uruchomieniu tworzy kolejkę z unikalnym kluczem IPC i wysyła jej klucz komunikatem do serwera (komunikat INIT). Po otrzymaniu takiego komunikatu, serwer otwiera kolejkę klienta, przydziela klientowi identyfikator (np. numer w kolejności zgłoszeń) i odsyła ten identyfikator do klienta (komunikacja w kierunku serwer->klient odbywa się za pomocą kolejki klienta). Po otrzymaniu identyfikatora, klient rozpoczyna wysyłanie zleceń do serwera (w pętli), zlecenia są czytane ze standardowego wyjścia w postaci typ_komunikatu albo z pliku tekstowego w którym w każdej linii znajduje się jeden komunikat (napisanie po stronie klienta READ plik zamiast typu komunikatu). Przygotuj pliki z dużą liczbą zleceń, aby można było przetestować działanie zleceń i priorytetów. 8 | 9 | Rodzaje zleceń 10 | 11 | ECHO string: 12 | Klient wysyła ciąg znaków. Serwer odsyła ten sam ciąg z powrotem, dodatkowo podając datę jego otrzymania. Klient po odebraniu wysyła go na standardowe wyjście. 13 | LIST: 14 | Zlecenie wypisania listy wszystkich aktywnych klientów 15 | FRIENDS lista_id_klientów 16 | Klient wysyła do serwera listę klientów, z którymi chce się grupowo komunikować. Serwer przechowuje tylko ostatnią listę. Kolejne wysłanie komunikatu FRIENDS nadpisuje poprzednią listę. Wysłanie samego FRIENDS czyści listę. 17 | Grupę można modyfikować, wysyłając do serwera komunikaty: ADD lista_id_klientów oraz DEL lista_id_klientów. Wysłanie ADD lista_id_klientów po uprzednim wyczyszczeniu listy jest analogiczne z wysłaniem FRIENDS lista_id_klientów. Próba wysłania ADD i DEL bez argumentów powinna zostać obsłużona po stronie klienta. 18 | 2ALL string: 19 | Zlecenie wysłania komunikatu do wszystkich pozostałych klientów. Klient wysyła ciąg znaków. Serwer wysyła ten ciąg wraz z identyfikatorem klienta-nadawcy oraz aktualną datą do wszystkich pozostałych klientów. 20 | 2FRIENDS string: 21 | Zlecenie wysłania komunikatu do zdefiniowanej wcześniej grupy klientów. Klient wysyła ciąg znaków. Serwer wysyła ten ciąg wraz z identyfikatorem klienta-nadawcy oraz aktualną datą do zdefiniowanej wcześniej grupy klientów. 22 | 2ONE id_klienta string: 23 | Zlecenie wysłania komunikatu do konkretnego klienta. Klient wysyła ciąg znaków podając jako adresata konkretnego klienta o identyfikatorze z listy aktywnych klientów. Serwer wysyła ten ciąg wraz z identyfikatorem klienta-nadawcy oraz aktualną datą do wskazanego klienta. 24 | STOP: 25 | Zgłoszenie zakończenia pracy klienta. Klient wysyła ten komunikat, kiedy kończy pracę, aby serwer mógł usunąć z listy jego kolejkę. Następnie kończy pracę, usuwając swoją kolejkę. Komunikat ten wysyłany jest również, gdy po stronie klienta zostanie wysłany sygnał SIGINT. 26 | 27 | Zlecenia powinny być obsługiwane zgodnie z priorytetami, najwyższy priorytet ma STOP, potem LIST oraz FRIENDS i reszta. Można tego dokonać poprzez sterowanie parametrem MTYPE w funkcji msgsnd. 28 | Poszczególne rodzaje komunikatów należy identyfikować za pomocą typów komunikatów systemu V. Klucze dla kolejek mają być generowane na podstawie ścieżki $HOME. Małe liczby do wygenerowania kluczy oraz rodzaje komunikatów mają być zdefiniowane we wspólnym pliku nagłówkowym. Dla uproszczenia można założyć, że długość komunikatu (lub maksymalna długość łańcucha znaków przy usłudze echa) jest ograniczona pewną stałą (jej definicja powinna znaleźć się w pliku nagłówkowym). 29 | Klient i serwer należy napisać w postaci osobnych programów (nie korzystamy z funkcji fork). Serwer musi być w stanie pracować z wieloma klientami naraz. Przed zakończeniem pracy każdy proces powinien usunąć kolejkę którą utworzył (patrz IPC_RMID oraz funkcja atexit). Dla uproszczenia można przyjąć, że serwer przechowuje informacje o klientach w statycznej tablicy (rozmiar tablicy ogranicza liczbę klientów, którzy mogą się zgłosić do serwera). 30 | Serwer może wysłać do klientów komunikaty: 31 | 32 | inicjujący pracę klienta (kolejka główna serwera) 33 | wysyłający odpowiedzi do klientów (kolejki klientów) 34 | informujący klientów o zakończeniu pracy serwera - po wysłaniu takiego sygnału i odebraniu wiadomości STOP od wszystkich klientów serwer usuwa swoją kolejkę i kończy pracę. (kolejki klientów) 35 | 36 | Należy obsłużyć przerwanie działania serwera lub klienta za pomocą CTRL+C. Po stronie klienta obsługa tego sygnału jest równoważna z wysłaniem komunikatu STOP. 37 | 38 | # Zadanie 2. Prosty chat - POSIX (50%) 39 | 40 | Zrealizuj zadanie analogiczne do Zadania 1, wykorzystując kolejki komunikatów POSIX. Kolejka klienta powinna mieć losową nazwę zgodną z wymaganiami stawianymi przez POSIX. Na typ komunikatu można zarezerwować pierwszy bajt jego treści. Obsługa zamykania kolejek analogiczna jak w zadaniu 1, z tym, że aby można było usunąć kolejkę, wszystkie procesy powinny najpierw ją zamknąć. Przed zakończeniem pracy klient wysyła do serwera komunikat informujący, że serwer powinien zamknąć po swojej stronie kolejkę klienta. Następnie klient zamyka i usuwa swoją kolejkę. Serwer przed zakończeniem pracy zamyka wszystkie otwarte kolejki, informuje klientów, aby usunęli swoje kolejki oraz zamknęli kolejkę serwera i usuwa kolejkę, którą utworzył. 41 | -------------------------------------------------------------------------------- /06. Inter-process communication(queue message)/zad1/client.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "commands.h" 14 | 15 | #define MAX_MSG_LEN 256 16 | #define MAX_USR_CNT 10 17 | 18 | int sqid = -1; 19 | key_t sqkey = -1; 20 | 21 | int cqid = -1; 22 | key_t cqkey = -1; 23 | 24 | int q_desc = -1; 25 | int sessionID = -1; 26 | 27 | void recognize_and_proceed(char * , char * ); 28 | void echo(char * string){ 29 | MyMsg msg; 30 | msg.cqid = cqid; 31 | msg.cqkey = cqkey; 32 | msg.mtype = ECHO; 33 | sprintf(msg.mtext, "%s", string); 34 | if (msgsnd(q_desc, &msg, MSG_SIZE, 0) < 0) error("client echo msgsnd failed"); 35 | if (msgrcv(cqid, &msg, MSG_SIZE, 0, 0) == -1) error("server response"); 36 | printf("Client received: %s\n", msg.mtext); 37 | } 38 | 39 | void list(){ 40 | MyMsg msg; 41 | msg.cqid = cqid; 42 | msg.cqkey = cqkey; 43 | msg.mtype = LIST; 44 | sprintf(msg.mtext, "%s", "List"); 45 | if (msgsnd(q_desc, &msg, MSG_SIZE, 0) < 0) error("client list msgsnd failed"); 46 | } 47 | 48 | void to_all(char * string){ 49 | MyMsg msg; 50 | msg.cqid = cqid; 51 | msg.cqkey = cqkey; 52 | msg.mtype = TOALL; 53 | sprintf(msg.mtext, "%s", string); 54 | if (msgsnd(q_desc, &msg, MSG_SIZE, 0) < 0) error("client to_all msgsnd failed"); 55 | } 56 | 57 | void to_one(int ID, char * string){ 58 | MyMsg msg; 59 | msg.cqid = cqid; 60 | msg.cqkey = ID; 61 | msg.mtype = TOONE; 62 | sprintf(msg.mtext, "%s", string); 63 | if (msgsnd(q_desc, &msg, MSG_SIZE, 0) < 0) error("client to_one msgsnd failed"); 64 | } 65 | 66 | void stop(){ 67 | MyMsg msg; 68 | msg.cqid = cqid; 69 | msg.cqkey = cqkey; 70 | msg.mtype = STOP; 71 | sprintf(msg.mtext, "%s", "Stop"); 72 | if (msgsnd(q_desc, &msg, MSG_SIZE, 0) < 0) error("client echo msgsnd failed"); 73 | exit(0); 74 | } 75 | 76 | void delete_queue(){ 77 | if ( msgctl(cqid, IPC_RMID, NULL) < 0){ 78 | printf("main queue remove"); 79 | } 80 | else{ 81 | printf("Deleted successfully.\n"); 82 | } 83 | } 84 | 85 | void handle_sigint(int signum){ 86 | printf("Odebrano sygnal SIGINT\n"); 87 | stop(); 88 | } 89 | 90 | void read_f(char * filename){ 91 | char * buff; 92 | size_t len = 0; 93 | ssize_t bufsize = 1; 94 | 95 | printf("filename: %s\n", filename); 96 | 97 | FILE * file = fopen(filename, "r"); 98 | if (!file) error("READ fopen"); 99 | while ((bufsize = getline(&buff, &len, file)) > 0){ 100 | char * rest; 101 | char * cmd = strtok_r(buff, delims, &rest); 102 | 103 | recognize_and_proceed(cmd, rest); 104 | } 105 | 106 | if (fclose(file) < 0){ 107 | error("READ fclose"); 108 | } 109 | } 110 | 111 | void recognize_and_proceed(char * cmd, char * rest){ 112 | rest = strtok_r(rest, "\n", &rest); // ucinam enter na koncu 113 | if (strcmp(cmd, "ECHO") == 0){ 114 | echo(rest); 115 | } 116 | else if (strcmp(cmd, "LIST") == 0){ 117 | list(); 118 | } 119 | else if (strcmp(cmd, "2ALL") == 0){ 120 | to_all(rest); 121 | } 122 | else if (strcmp(cmd, "2ONE") == 0){ 123 | char * num = strtok_r(rest, delims, &rest); 124 | to_one(atoi(num), rest); 125 | } 126 | else if (strcmp(cmd, "STOP") == 0){ 127 | stop(); 128 | } 129 | else if (strcmp(cmd, "READ") == 0){ 130 | read_f(rest); 131 | } 132 | else { 133 | printf("Bad command\n"); 134 | } 135 | } 136 | 137 | int create_queue(char * path, int ID){ 138 | int key = ftok(path, ID); 139 | if (key == -1) error("ftok in create_queue"); 140 | 141 | int QID = msgget(key, 0); 142 | if (QID < 0) error("msgget in create_queue"); 143 | 144 | return QID; 145 | } 146 | 147 | void register_client(){ 148 | MyMsg msg; 149 | msg.mtype = LOGIN; 150 | msg.cqid = cqid; 151 | msg.cqkey = cqkey; 152 | sprintf(msg.mtext, "%s", "Login"); 153 | 154 | if ( msgsnd(q_desc, &msg, MSG_SIZE, 0) < 0) error("client login failed"); 155 | if ( msgrcv(cqid, &msg, MSG_SIZE, 0, 0) < 0) error("server login response failed"); 156 | if (sscanf(msg.mtext, "%d", &sessionID) < 1) error("sscanf login failed"); 157 | if (sessionID < 0) error("servers queue full"); 158 | 159 | printf("Client registered with session ID %d.\n", sessionID); 160 | } 161 | 162 | int main(int argc, char ** argv){ 163 | if ( atexit(delete_queue) < 0) error("atexit"); 164 | if ( signal(SIGINT, handle_sigint) == SIG_ERR) error("signal"); 165 | 166 | char * path = getenv("HOME"); 167 | if (!path) error("getenv"); 168 | 169 | q_desc = create_queue(path, PROJECT_ID); 170 | 171 | cqkey = ftok(path, getpid()); 172 | if (cqkey == -1) error("cannot generate clients queue key"); 173 | 174 | cqid = msgget(cqkey, IPC_CREAT | IPC_EXCL | 0666); 175 | if (cqid < 0) error("clients msgget"); 176 | 177 | 178 | register_client(); 179 | 180 | char * buff; 181 | size_t len = 0; 182 | while(1){ 183 | printf("\nType command:\n> "); 184 | getline(&buff, &len, stdin); // ssize_t bufsize = 185 | char * rest; 186 | char * cmd = strtok_r(buff, delims, &rest); 187 | if (!cmd){ 188 | printf("empty string\n"); 189 | continue; 190 | } 191 | recognize_and_proceed(cmd, rest); 192 | } 193 | 194 | return 0; 195 | } 196 | -------------------------------------------------------------------------------- /06. Inter-process communication(queue message)/zad1/commands.h: -------------------------------------------------------------------------------- 1 | #ifndef commands_h 2 | #define commands_h 3 | 4 | #define MAX_CLIENTS 10 5 | #define PROJECT_ID 0x099 6 | #define MAX_MSG_SIZE 4096 7 | 8 | const char delims[3] = {' ', '\n', '\t'}; 9 | 10 | int error(char * msg){ 11 | perror(msg); 12 | exit(EXIT_FAILURE); 13 | } 14 | 15 | typedef enum mtype { 16 | LOGIN = 1, STOP = 2, LIST = 3, ECHO = 4, 17 | TOALL = 5, TOONE = 6 18 | } mtype; 19 | 20 | typedef struct MyMsg{ 21 | long mtype; 22 | int cqid; 23 | key_t cqkey; 24 | char mtext[MAX_MSG_SIZE]; 25 | } MyMsg; 26 | 27 | const size_t MSG_SIZE = sizeof(MyMsg) - sizeof(long); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /06. Inter-process communication(queue message)/zad1/commands.txt: -------------------------------------------------------------------------------- 1 | ECHO "upa" 2 | ECHO "nic" 3 | LIST 4 | -------------------------------------------------------------------------------- /06. Inter-process communication(queue message)/zad1/makefile: -------------------------------------------------------------------------------- 1 | CC = gcc -Wall -o 2 | 3 | clean: 4 | rm -f *.o 5 | rm -f *.a 6 | rm -f server 7 | rm -f client 8 | 9 | compile: 10 | make clean 11 | $(CC) server server.c 12 | $(CC) client client.c 13 | 14 | runserver: 15 | ./server 16 | 17 | runclient: 18 | ./client 19 | -------------------------------------------------------------------------------- /06. Inter-process communication(queue message)/zad1/server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "commands.h" 14 | 15 | int cqids[10] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; 16 | key_t cqkeys[10]; 17 | int active = 1; 18 | int counter = 0; 19 | int q_desc = -1; 20 | key_t sqkey = -1; 21 | 22 | void end(){ 23 | active = 0; 24 | } 25 | 26 | void handle_sigint(int signum){ 27 | printf("Odebrano sygnal SIGINT\n"); 28 | end(); 29 | exit(EXIT_SUCCESS); 30 | } 31 | 32 | void delete_queue(){ 33 | if (q_desc > -1){ 34 | int tmp = msgctl(q_desc, IPC_RMID, NULL); 35 | if (tmp == -1){ 36 | printf("error on deleting queue"); 37 | } 38 | printf("deleted servers queue successfully"); 39 | } 40 | } 41 | 42 | void log_in(MyMsg * msg){ 43 | cqids[counter] = msg->cqid; 44 | cqkeys[counter] = msg->cqkey; 45 | if (msgget(cqkeys[counter], 0) == -1) error("msgget"); 46 | if (counter >= MAX_CLIENTS){ 47 | printf("Maximum number of clients exceeded"); 48 | sprintf(msg->mtext, "%d", -1); 49 | } 50 | else{ 51 | sprintf(msg->mtext, "%d", counter); 52 | while (cqids[counter] > 0 && counter < MAX_CLIENTS) counter++; 53 | } 54 | if (msgsnd(cqids[counter-1], msg, MSG_SIZE, 0) == -1) error("login response failed"); 55 | } 56 | 57 | void echo(MyMsg * msg){ 58 | time_t sekund; 59 | char napis[100]; 60 | 61 | time (&sekund); 62 | strftime (napis, 100, "%c", localtime(&sekund)); 63 | 64 | sprintf(msg->mtext, "%s %s", msg->mtext, napis); 65 | if (msgsnd(msg->cqid, msg, MSG_SIZE, 0) == -1) error("echo msgsnd"); 66 | } 67 | 68 | void stop(MyMsg * msg){ 69 | int i; 70 | for (i = 0; i < MAX_CLIENTS; ++i){ 71 | if (cqids[i] == msg->cqid){ 72 | cqids[i] = -1; 73 | counter = i; 74 | } 75 | } 76 | printf("Client %d exited.\n", msg->cqid); 77 | } 78 | 79 | void list(){ 80 | int i; 81 | printf("Active clients:\n"); 82 | for (i = 0; i < MAX_CLIENTS; ++i){ 83 | if (cqids[i] > 0) 84 | printf(" -\t %d\n", cqids[i]); 85 | } 86 | } 87 | 88 | void to_all(MyMsg * msg){ 89 | int i; 90 | for (i = 0; i < MAX_CLIENTS; ++i){ 91 | if (cqids[i] > 0){ 92 | if (msgsnd(cqids[i], msg, MSG_SIZE, 0) == -1) 93 | error("to_all msgsnd"); 94 | } 95 | } 96 | } 97 | 98 | void to_one(MyMsg * msg){ 99 | if (msgsnd(msg->cqkey, msg, MSG_SIZE, 0) == -1) error("to one msgsnd"); 100 | } 101 | 102 | void recognize_and_proceed(MyMsg * msg){ 103 | if (!msg) return; 104 | switch(msg->mtype){ 105 | case LOGIN: 106 | log_in(msg); 107 | printf("Logged user with cqid %d.\n", msg->cqid); 108 | break; 109 | case STOP: 110 | stop(msg); 111 | printf("Client %d is gone.\n", msg->cqid); 112 | break; 113 | case LIST: 114 | list(); 115 | break; 116 | case ECHO: 117 | printf("Server got >>%s<< from >>%d<<.\n", msg->mtext, msg->cqid); 118 | echo(msg); 119 | break; 120 | case TOALL: 121 | to_all(msg); 122 | printf("Server sent >>%s<< to all clients.\n", msg->mtext); 123 | break; 124 | case TOONE: 125 | to_one(msg); 126 | printf("Server sent >>%s<< to %d.\n", msg->mtext, msg->cqkey); 127 | break; 128 | } 129 | } 130 | 131 | int main(int argc, char ** argv){ 132 | if ( atexit(delete_queue) < 0) error("atexit()"); 133 | if ( signal(SIGINT, handle_sigint) == SIG_ERR) error("signal()"); 134 | 135 | struct msqid_ds current_state; 136 | 137 | char * path = getenv("HOME"); 138 | if (!path) error("getenv"); 139 | 140 | sqkey = ftok(path, PROJECT_ID); 141 | if (sqkey == -1) error("server ftok"); 142 | 143 | q_desc = msgget(sqkey, IPC_CREAT | IPC_EXCL | 0666); 144 | if (q_desc < 0) error("server msgget"); 145 | 146 | MyMsg msg; 147 | while(1){ 148 | if (active == 0){ 149 | if (msgctl(q_desc, IPC_STAT, ¤t_state) < 0) error("msgctl"); 150 | if (counter == 0) break; // current_state.msg_qnum 151 | } 152 | if (msgrcv(q_desc, &msg, MSG_SIZE, 0, 0) < 0) error("msgrcv"); 153 | recognize_and_proceed(&msg); 154 | } 155 | 156 | return 0; 157 | } 158 | -------------------------------------------------------------------------------- /06. Inter-process communication(queue message)/zad2/client.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "commands.h" 16 | 17 | int cqid = -1; 18 | 19 | mqd_t q_desc = -1; 20 | mqd_t sqid = -1; 21 | int sessionID = -1; 22 | char myPath[10]; 23 | 24 | void recognize_and_proceed(char * , char * ); 25 | void echo(char * string){ 26 | MyMsg msg; 27 | msg.cqid = cqid; 28 | msg.pid = getpid(); 29 | msg.mtype = ECHO; 30 | sprintf(msg.mtext, "%s", string); 31 | if (mq_send(q_desc, (char*)&msg, MSG_SIZE, 1) < 0) error("client echo msgsnd failed"); 32 | if (mq_receive(cqid, (char*)&msg, MSG_SIZE, NULL) == -1) error("server response"); 33 | printf("Client received: %s\n", msg.mtext); 34 | } 35 | 36 | void list(){ 37 | MyMsg msg; 38 | msg.cqid = cqid; 39 | msg.pid = getpid(); 40 | msg.mtype = LIST; 41 | sprintf(msg.mtext, "%s", "List"); 42 | if (mq_send(q_desc, (char*)&msg, MSG_SIZE, 1) < 0) error("client list msgsnd failed"); 43 | } 44 | 45 | void to_all(char * string){ 46 | MyMsg msg; 47 | msg.cqid = cqid; 48 | msg.pid = getpid(); 49 | msg.mtype = TOALL; 50 | sprintf(msg.mtext, "%s", string); 51 | if (mq_send(q_desc, (char*)&msg, MSG_SIZE, 1) < 0) error("client to_all msgsnd failed"); 52 | } 53 | 54 | void to_one(int ID, char * string){ 55 | MyMsg msg; 56 | msg.cqid = cqid; 57 | msg.pid = ID; 58 | msg.mtype = TOONE; 59 | sprintf(msg.mtext, "%s", string); 60 | if (mq_send(q_desc, (char*)&msg, MSG_SIZE, 1) < 0) error("client to_one msgsnd failed"); 61 | } 62 | 63 | void stop(){ 64 | MyMsg msg; 65 | msg.cqid = cqid; 66 | msg.pid = getpid(); 67 | msg.mtype = STOP; 68 | sprintf(msg.mtext, "%s", "Stop"); 69 | if (mq_send(q_desc, (char*)&msg, MSG_SIZE, 1) < 0) error("client echo msgsnd failed"); 70 | exit(0); 71 | } 72 | 73 | void delete_queue(){ 74 | if (cqid > -1){ 75 | if (sessionID >= 0){ 76 | printf("Need to close all\n"); 77 | } 78 | 79 | if (mq_close(q_desc) == -1){ 80 | printf("error on closing server's queue\n"); 81 | } 82 | else { 83 | printf("closed server's queue successfully\n"); 84 | } 85 | 86 | if (mq_close(cqid) == -1) { 87 | printf("error on closing clients's queue\n"); 88 | } 89 | else { 90 | printf("closed client's queue successfully\n"); 91 | } 92 | 93 | if (mq_unlink(myPath) == -1) { 94 | printf("cannot delete client's queue\n"); 95 | } 96 | else { 97 | printf("deleted client's queue successfully\n"); 98 | } 99 | } 100 | else { 101 | printf("queue doesn't exist\n"); 102 | } 103 | } 104 | 105 | void handle_sigint(int signum){ 106 | printf("Odebrano sygnal SIGINT\n"); 107 | stop(); 108 | } 109 | 110 | void read_f(char * filename){ 111 | char * buff; 112 | size_t len = 0; 113 | ssize_t bufsize = 1; 114 | 115 | printf("filename: %s\n", filename); 116 | 117 | FILE * file = fopen(filename, "r"); 118 | if (!file) error("READ fopen"); 119 | while ((bufsize = getline(&buff, &len, file)) > 0){ 120 | char * rest; 121 | char * cmd = strtok_r(buff, delims, &rest); 122 | 123 | recognize_and_proceed(cmd, rest); 124 | } 125 | 126 | if (fclose(file) < 0){ 127 | error("READ fclose"); 128 | } 129 | } 130 | 131 | void recognize_and_proceed(char * cmd, char * rest){ 132 | rest = strtok_r(rest, "\n", &rest); // ucinam enter na koncu 133 | if (strcmp(cmd, "ECHO") == 0){ 134 | echo(rest); 135 | } 136 | else if (strcmp(cmd, "LIST") == 0){ 137 | list(); 138 | } 139 | else if (strcmp(cmd, "2ALL") == 0){ 140 | to_all(rest); 141 | } 142 | else if (strcmp(cmd, "2ONE") == 0){ 143 | char * num = strtok_r(rest, delims, &rest); 144 | to_one(atoi(num), rest); 145 | } 146 | else if (strcmp(cmd, "STOP") == 0){ 147 | stop(); 148 | } 149 | else if (strcmp(cmd, "READ") == 0){ 150 | read_f(rest); 151 | } 152 | else { 153 | printf("Bad command\n"); 154 | } 155 | } 156 | 157 | void register_client(){ 158 | MyMsg msg; 159 | msg.mtype = LOGIN; 160 | msg.cqid = cqid; 161 | msg.pid = getpid(); 162 | sprintf(msg.mtext, "%s", "Login"); 163 | 164 | if (mq_send(q_desc, (char*)&msg, MSG_SIZE, 1) < 0) error("client login failed"); 165 | if (mq_receive(cqid, (char*)&msg, MSG_SIZE, NULL) < 0) error("server login response failed"); 166 | if (sscanf(msg.mtext, "%d", &sessionID) < 1) error("sscanf login failed"); 167 | if (sessionID < 0) error("servers queue full"); 168 | 169 | printf("Client registered with session ID %d.\n", sessionID); 170 | } 171 | 172 | int main(int argc, char ** argv){ 173 | printf("My PID = %d\n", getpid()); 174 | if ( atexit(delete_queue) == -1) error("atexit"); 175 | if ( signal(SIGINT, handle_sigint) == SIG_ERR) error("signal"); 176 | 177 | sprintf(myPath, "/%d", getpid()); 178 | 179 | q_desc = mq_open(server_path, O_WRONLY); 180 | if (q_desc == -1) error("cannot open server's queue"); 181 | 182 | struct mq_attr posixAttr; 183 | posixAttr.mq_maxmsg = MAX_MSG_Q_SZ; 184 | posixAttr.mq_msgsize = MSG_SIZE; 185 | 186 | cqid = mq_open(myPath, O_RDONLY | O_CREAT | O_EXCL, 187 | 0666, &posixAttr); 188 | if (cqid == -1) error("cannot create client's queue"); 189 | 190 | printf("client cqid = %d\n", cqid); 191 | register_client(); 192 | 193 | char * buff; 194 | size_t len = 0; 195 | while(1){ 196 | printf("\nType command:\n> "); 197 | getline(&buff, &len, stdin); // ssize_t bufsize = 198 | char * rest; 199 | char * cmd = strtok_r(buff, delims, &rest); 200 | if (!cmd){ 201 | printf("empty string\n"); 202 | continue; 203 | } 204 | recognize_and_proceed(cmd, rest); 205 | } 206 | 207 | return 0; 208 | } 209 | -------------------------------------------------------------------------------- /06. Inter-process communication(queue message)/zad2/commands.h: -------------------------------------------------------------------------------- 1 | #ifndef commands_h 2 | #define commands_h 3 | 4 | #define MAX_CLIENTS 10 5 | #define PROJECT_ID 0x099 6 | #define MAX_MSG_SIZE 4096 7 | #define MSG_SIZE sizeof(MyMsg) 8 | #define MAX_MSG_Q_SZ 9 9 | 10 | const char delims[3] = {' ', '\n', '\t'}; 11 | 12 | int error(char * msg){ 13 | perror(msg); 14 | exit(EXIT_FAILURE); 15 | } 16 | 17 | typedef enum mtype { 18 | LOGIN = 1, STOP = 2, LIST = 3, ECHO = 4, 19 | TOALL = 5, TOONE = 6 20 | } mtype; 21 | 22 | typedef struct MyMsg{ 23 | long mtype; 24 | int cqid; 25 | pid_t pid; 26 | char mtext[MAX_MSG_SIZE]; 27 | } MyMsg; 28 | 29 | const char server_path[] = "/server"; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /06. Inter-process communication(queue message)/zad2/commands.txt: -------------------------------------------------------------------------------- 1 | ECHO "upa" 2 | ECHO "nic" 3 | LIST 4 | -------------------------------------------------------------------------------- /06. Inter-process communication(queue message)/zad2/makefile: -------------------------------------------------------------------------------- 1 | CC = gcc -Wall -o 2 | 3 | clean: 4 | rm -f *.o 5 | rm -f *.a 6 | rm -f server 7 | rm -f client 8 | 9 | compile: 10 | make clean 11 | $(CC) server server.c 12 | $(CC) client client.c 13 | 14 | runserver: 15 | ./server 16 | 17 | runclient: 18 | ./client 19 | -------------------------------------------------------------------------------- /06. Inter-process communication(queue message)/zad2/server.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "commands.h" 16 | 17 | int cqids[10] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; 18 | pid_t pids[10] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; 19 | int active = 1; 20 | int counter = 0; 21 | mqd_t q_desc = -1; 22 | 23 | void end(){ 24 | active = 0; 25 | } 26 | 27 | void handle_sigint(int signum){ 28 | printf("Odebrano sygnal SIGINT\n"); 29 | end(); 30 | exit(EXIT_SUCCESS); 31 | } 32 | 33 | void delete_queue(){ 34 | if (q_desc > -1){ 35 | if ( mq_close(q_desc) == -1) error("mq_close"); 36 | if (mq_unlink(server_path) == -1) error("mq_unlink"); 37 | printf("deleted server's queue successfully\n"); 38 | } 39 | } 40 | 41 | void log_in(MyMsg * msg){ 42 | cqids[counter] = msg->cqid; 43 | pids[counter] = msg->pid; 44 | char clientPath[10]; 45 | sprintf(clientPath, "/%d", pids[counter]); 46 | printf("Clients path: %s, pid: %d, cqid: %d\n", clientPath, pids[counter], cqids[counter]); 47 | printf("Got pid = %d\n", pids[counter]); 48 | 49 | int cqid = mq_open(clientPath, O_WRONLY); 50 | if (cqid == -1) error("cannot read client's queue"); 51 | 52 | if (counter >= MAX_CLIENTS){ 53 | printf("Maximum number of clients exceeded\n"); 54 | sprintf(msg->mtext, "%d", -1); 55 | if (mq_send(cqid, (char*)msg, MSG_SIZE, 1) == -1) error("login response failed"); 56 | if (mq_close(cqid) == -1) error("cannot close client's queue"); 57 | } 58 | else{ 59 | sprintf(msg->mtext, "%d", counter); 60 | while (pids[counter] > 0 && counter < MAX_CLIENTS) counter++; 61 | } 62 | if (mq_send(cqids[counter-1], (char*)msg, MSG_SIZE, 1) == -1) error("login response failed"); 63 | } 64 | 65 | void echo(MyMsg * msg){ 66 | time_t sekund; 67 | char napis[100]; 68 | 69 | time (&sekund); 70 | strftime (napis, 100, "%c", localtime(&sekund)); 71 | 72 | sprintf(msg->mtext, "%s %s", msg->mtext, napis); 73 | if (mq_send(msg->cqid, (char*)msg, MSG_SIZE, 1) == -1) error("echo msgsnd"); 74 | } 75 | 76 | void stop(MyMsg * msg){ 77 | int i; 78 | for (i = 0; i < MAX_CLIENTS; ++i){ 79 | if (cqids[i] == msg->cqid){ 80 | cqids[i] = -1; 81 | counter = i; 82 | } 83 | } 84 | printf("Client %d exited.\n", msg->cqid); 85 | } 86 | 87 | void list(){ 88 | int i; 89 | printf("Active clients:\n"); 90 | for (i = 0; i < MAX_CLIENTS; ++i){ 91 | if (cqids[i] > 0) 92 | printf(" -\t %d\n", cqids[i]); 93 | } 94 | } 95 | 96 | void to_all(MyMsg * msg){ 97 | int i; 98 | for (i = 0; i < MAX_CLIENTS; ++i){ 99 | if (cqids[i] > 0){ 100 | if (mq_send(cqids[i], (char*)msg, MSG_SIZE, 1) == -1) 101 | error("to_all msgsnd"); 102 | } 103 | } 104 | } 105 | 106 | void to_one(MyMsg * msg){ 107 | if (mq_send(msg->cqid, (char*)msg, MSG_SIZE, 1) == -1) error("to one msgsnd"); 108 | } 109 | 110 | void recognize_and_proceed(MyMsg * msg){ 111 | if (!msg) return; 112 | switch(msg->mtype){ 113 | case LOGIN: 114 | log_in(msg); 115 | printf("Logged user with cqid %d.\n", msg->cqid); 116 | break; 117 | case STOP: 118 | stop(msg); 119 | printf("Client %d is gone.\n", msg->cqid); 120 | break; 121 | case LIST: 122 | list(); 123 | break; 124 | case ECHO: 125 | printf("Server got >>%s<< from >>%d<<.\n", msg->mtext, msg->cqid); 126 | echo(msg); 127 | break; 128 | case TOALL: 129 | to_all(msg); 130 | printf("Server sent >>%s<< to all clients.\n", msg->mtext); 131 | break; 132 | case TOONE: 133 | to_one(msg); 134 | printf("Server sent >>%s<< to %d.\n", msg->mtext, msg->pid); 135 | break; 136 | } 137 | } 138 | 139 | int main(int argc, char ** argv){ 140 | if ( atexit(delete_queue) < 0) error("atexit()"); 141 | if ( signal(SIGINT, handle_sigint) == SIG_ERR) error("signal()"); 142 | 143 | struct mq_attr current_state; 144 | struct mq_attr posix_attr; 145 | posix_attr.mq_maxmsg = MAX_MSG_Q_SZ; 146 | posix_attr.mq_msgsize = MSG_SIZE; 147 | 148 | q_desc = mq_open(server_path, O_RDONLY | 149 | O_CREAT | O_EXCL, 0666, &posix_attr); 150 | 151 | if (q_desc == -1) error("cannot create server's queue"); 152 | 153 | MyMsg msg; 154 | while(1){ 155 | if (active == 0){ 156 | if (mq_getattr(q_desc, ¤t_state) == -1) error("cannot read queue params"); 157 | if (current_state.mq_curmsgs == 0) exit(0); 158 | } 159 | if (mq_receive(q_desc, (char*)&msg, MSG_SIZE, NULL) == -1) error("msgrcv"); 160 | recognize_and_proceed(&msg); 161 | } 162 | 163 | return 0; 164 | } 165 | -------------------------------------------------------------------------------- /06. Inter-process communication(queue message)/zad2/server.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wreczek/Operating-Systems/903f132c4b8089d0e875df0548d333be870cc13f/06. Inter-process communication(queue message)/zad2/server.o -------------------------------------------------------------------------------- /07. Inter-process communication(semaphore)/README.md: -------------------------------------------------------------------------------- 1 | # Zadanie 7. 2 | 3 | Przy taśmie transportowej pracują pracownicy, którzy mogą wrzucać na taśmę ładunki o masach odpowiednio od 1 do N jednostek (N jest wartością całkowitą). Na końcu taśmy stoi ciężarówka o ładowności X jednostek, którą należy zawsze załadować do pełna tak, że nie można dołożyć następnej paczki z taśmy. Wszyscy pracownicy starają się układać paczki na taśmie najszybciej jak to możliwe. Taśma może przetransportować w danej chwili maksymalnie K sztuk paczek. Jednocześnie jednak taśma ma ograniczony udźwig: maksymalnie M jednostek masy, tak, że niedopuszczalne jest położenie np. samych najcięższych paczek (N*K>M). Po zapełnieniu ciężarówki następuje wyładowanie i pojawia się pusta o takich samych parametrach. Paczki „zjeżdżające” z taśmy muszą od razu trafić na samochód dokładnie w takiej kolejności, w jakiej zostały położone na taśmie. 4 | 5 | Zakładamy, że pracownicy i ciężarówki to osobne procesy loader i trucker. Kolejni pracownicy są uruchamiani w pętli przez jeden proces macierzysty (za pomocą funkcji fork oraz exec). Ich liczba jest podana w argumencie programu. Identyfikatorem pracownika jest jego PID. Taśma transportowa o ładowności K sztuk i M jednostek jest umieszczona w pamięci wspólnej. Pamięć wspólną i semafory tworzy i usuwa program ciężarówki trucker. Należy obsłużyć SIGINT, aby pousuwać pamięć wspólną i utworzone semafory. W przypadku uruchomienia programu loader przed uruchomieniem truckera, powinien zostać wypisany odpowiedni komunikat (obsłużony błąd spowodowany brakiem dostępu do nieutworzonej pamięci), W przypadku, gdy trucker kończy pracę, powinien zablokować semafor taśmy transportowej dla pracowników, załadować to, co pozostało na taśmie, w przypadku wersji Posix dodatkowo poinformować pracowników, aby ze swojej strony pozamykali mechanizmy synchronizacyjne i pousuwać je. 6 | 7 | Program ciężarówki przyjmuje jako argument X (ładowność ciężarówki) oraz K i M (ładowność taśmy) i wypisuje cyklicznie na ekranie komunikaty o następujących zdarzeniach: 8 | 9 | * podjechanie pustej ciężarówki, 10 | * czekanie na załadowanie paczki, 11 | * ładowanie paczki do ciężarówki - identyfikator pracownika, różnica czasu od próby załadowania na taśmę do załadowania na ciężarówkę, liczba jednostek - stan ciężarówki - ilość zajętych i wolnych miejsc, 12 | * brak miejsca - odjazd i wyładowanie pełnej ciężarówki. 13 | 14 | Program pracownika przyjmuje jako argument wartość od 1 do N (liczba jednostek paczki) i wypisuje cyklicznie (zakładamy, że ładunki nie są toksyczne i proces nie umiera po załadowaniu jednej paczki, opcjonalny parametr C może zdefiniować liczbę cykli, w przypadku nie podania go, działa w pętli nieskończonej) na ekranie komunikaty o następujących zdarzeniach: 15 | 16 | * Załadowanie paczki o N jednostkach z podaniem identyfikatora pracownika i czasu załadowania. 17 | * Czekanie na zwolnienie taśmy. 18 | 19 | Każdy komunikat ciężarówki lub pracownika powinien zawierać znacznik czasowy z dokładnością do mikrosekund. Każdy komunikat pracownika powinien ponadto zawierać informacje o swoim identyfikatorze -PID. Każde zdarzenie związane z ładowaniem na taśmę i zwalnianie jej powinno dodatkowo poinformować o liczbie wolnych/zajętych miejsc oraz jednostek. 20 | 21 | Do implementacji programów należy wykorzystać semafory zliczające, operujące na semaforach wielowartościowych (atomowe zmniejszanie i zwiększanie semafora o dowolną wartość) oraz pamięć wspólną. 22 | 23 | Synchronizacja procesów musi wykluczać zakleszczenia i gwarantować sekwencję zdarzeń zgodną ze schematem działania taśmy. Niedopuszczalne jest na przykład: 24 | 25 | * załadowanie paczki na taśmę, kiedy przekroczona została maksymalna liczba jednostek albo maksymalna liczba paczek, 26 | * pobranie paczki z taśmy, gdy osiągnięta została maksymalna ładowność ciężarówki, 27 | * załadowanie paczki na taśmę w momencie gdy ciężarówka jest pełna i odjeżdża do wyładowania, 28 | * dopuszczenie do sytuacji, gdy któryś z pracowników nie jest w stanie przez dłuższy czas położyć paczki na taśmie, 29 | * pobranie paczki w innej kolejności niż tej, w której zostały położone na taśmie. 30 | 31 | Zrealizuj powyższy problem synchronizacyjny, wykorzystując mechanizmy synchronizacji procesów oraz pamięć współdzieloną ze standardu: 32 | 33 | 1. IPC - System V (50%) 34 | 2. IPC - Posix (50%) 35 | -------------------------------------------------------------------------------- /07. Inter-process communication(semaphore)/zad1/loader.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wreczek/Operating-Systems/903f132c4b8089d0e875df0548d333be870cc13f/07. Inter-process communication(semaphore)/zad1/loader.c -------------------------------------------------------------------------------- /07. Inter-process communication(semaphore)/zad1/makefile: -------------------------------------------------------------------------------- 1 | CC = gcc -Wall -o 2 | 3 | trucker_args: 4 | #Pass arguments: X, K, M 5 | 6 | loader_args: 7 | #Pass arguments: N, loaders_num, C 8 | 9 | clean: 10 | rm -f *.o 11 | rm -f trucker 12 | rm -f loader 13 | rm -f test 14 | 15 | compile: 16 | make clean 17 | $(CC) trucker trucker.c 18 | $(CC) loader loader.c 19 | 20 | run_trucker: 21 | make compile 22 | ./trucker 100 16 50 23 | 24 | run_loader: 25 | make compile 26 | ./loader 5 4 3 27 | -------------------------------------------------------------------------------- /07. Inter-process communication(semaphore)/zad1/shared_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef SHARED_UTILS_H 2 | #define SHARED_UTILS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #define MAX_PCKGS_NUM 256 19 | #define PROJECT_ID 0xAAAA 20 | #define PROJECT_PATH getenv("HOME") 21 | 22 | typedef struct timeval timeval; 23 | 24 | /** Arguments: 25 | - trucker.c: 26 | X to pojemnosc tira 27 | K to max liczba paczek na tasmie 28 | M to max masa paczek na tasmie 29 | - loader.c: 30 | N to maksymalna masa paczki 31 | loaders_num to liczba loaderow 32 | C to liczba cykli 33 | */ 34 | 35 | union semun { /* Used in calls to semctl() */ 36 | int val; 37 | struct semid_ds * buf; 38 | unsigned short * array; 39 | #if defined(__linux__) 40 | struct seminfo * __buf; 41 | #endif 42 | }; 43 | typedef union semun semun; 44 | 45 | enum trucker_status{ 46 | ARRIVAL, 47 | WAITING, 48 | LOADING, 49 | DEPARTURE 50 | }; 51 | typedef enum trucker_status trucker_status; 52 | 53 | enum loader_status{ 54 | SHIPING, 55 | AWAITING 56 | }; 57 | typedef enum loader_status loader_status; 58 | 59 | struct Conveyor{ 60 | trucker_status t_status; 61 | int K; // max liczba sztuk 62 | int curr_k; // aktualna liczba sztuk 63 | int M; // max waga 64 | int curr_m; // aktualna waga 65 | int current_insert; // miejsce pod ktorym mozemy (po weryfikacji) wsadzic loadera ??? 66 | int current_remove; // stad pierwsza paczka do wziecia 67 | pid_t pids[MAX_PCKGS_NUM]; // kolejka pidow loaderow 68 | struct timeval times[MAX_PCKGS_NUM]; // czasy polozenia na tasmie 69 | int weights[MAX_PCKGS_NUM]; // waga poszczegolnych paczek 70 | int truck_left_space; 71 | struct timeval s_time; 72 | 73 | } *conveyor; 74 | typedef struct Conveyor Conveyor; 75 | 76 | void error(char * msg){ 77 | perror(msg); 78 | exit(EXIT_FAILURE); 79 | } 80 | 81 | struct timeval gettime(){ 82 | struct timeval time; 83 | gettimeofday(&time,NULL); 84 | return time; 85 | } 86 | 87 | struct timeval current_time(){ 88 | struct timeval time, ret_time; 89 | gettimeofday(&time, NULL); 90 | if (time.tv_usec - conveyor->s_time.tv_usec < 0){ 91 | ret_time.tv_sec = time.tv_sec - conveyor->s_time.tv_sec-1; 92 | ret_time.tv_usec = conveyor->s_time.tv_usec - time.tv_usec; 93 | } 94 | else { 95 | ret_time.tv_sec = time.tv_sec - conveyor->s_time.tv_sec-1; 96 | ret_time.tv_usec = time.tv_usec - conveyor->s_time.tv_usec; 97 | } 98 | return ret_time; 99 | } 100 | 101 | /// ^^^^^ SEMAPHORES ^^^^^ 102 | void acquire_conveyor(int semid){ 103 | struct sembuf sops; 104 | sops.sem_num = 0; 105 | sops.sem_op = -1; 106 | sops.sem_flg = 0; 107 | 108 | if (semop(semid, &sops, 1) < 0) error("semop1"); 109 | } 110 | 111 | void release_conveyor(int semid){ 112 | struct sembuf sops; 113 | sops.sem_num = 0; 114 | sops.sem_op = 1; 115 | sops.sem_flg = 0; 116 | 117 | if (semop(semid, &sops, 1) < 0) error("semop2"); 118 | } 119 | 120 | void trucker_acquire(int semid){ 121 | struct sembuf sops; 122 | sops.sem_num = 1; 123 | sops.sem_op = -1; 124 | sops.sem_flg = 0; 125 | 126 | if (semop(semid, &sops, 1) < 0) error("semop3"); 127 | } 128 | 129 | void trucker_release(int semid){ 130 | struct sembuf sops; 131 | sops.sem_num = 1; 132 | sops.sem_op = 1; 133 | sops.sem_flg = 0; 134 | 135 | if (semop(semid, &sops, 1) < 0) error("semop"); 136 | } 137 | 138 | void acquire_K(int semid){ 139 | struct sembuf sops; 140 | sops.sem_num = 3; 141 | sops.sem_op = -1; 142 | sops.sem_flg = 0; 143 | 144 | if (semop(semid, &sops, 1) < 0) error("semop3"); 145 | } 146 | 147 | void release_K(int semid){ 148 | struct sembuf sops; 149 | sops.sem_num = 2; 150 | sops.sem_op = 1; 151 | sops.sem_flg = 0; 152 | 153 | if (semop(semid, &sops, 1) < 0) error("semop"); 154 | } 155 | 156 | void acquire_M(int semid, int value){ 157 | struct sembuf sops; 158 | sops.sem_num = 3; 159 | sops.sem_op = -value; 160 | sops.sem_flg = 0; 161 | 162 | if (semop(semid, &sops, 1) < 0) error("semop3"); 163 | } 164 | 165 | void release_M(int semid, int value){ 166 | struct sembuf sops; 167 | sops.sem_num = 3; 168 | sops.sem_op = value; 169 | sops.sem_flg = 0; 170 | 171 | if (semop(semid, &sops, 1) < 0) error("semop"); 172 | } 173 | 174 | /// $$$$$ SEMAPHORES $$$$$ 175 | 176 | int is_conveyor_available(){ 177 | return conveyor->t_status == WAITING || conveyor->t_status == LOADING; 178 | } 179 | 180 | int is_conveyor_empty(){ 181 | return conveyor->pids[conveyor->current_remove] < 0; 182 | } 183 | 184 | #endif // SHARED_UTILS_H 185 | -------------------------------------------------------------------------------- /07. Inter-process communication(semaphore)/zad1/trucker.c: -------------------------------------------------------------------------------- 1 | #include "shared_utils.h" 2 | 3 | key_t key; 4 | int shmid; 5 | int semid; 6 | int X, K, M; 7 | int current; 8 | timeval tm; 9 | 10 | void SIGINT_handler(int signum){ 11 | printf("Finished unloading.\n"); 12 | exit(EXIT_SUCCESS); 13 | } 14 | 15 | void arrival(){ // ARRIVAL 16 | sleep(1); 17 | tm = current_time(); 18 | printf("Truck just arrived: %ld.%ld\n", tm.tv_sec, tm.tv_usec); 19 | conveyor->t_status = WAITING; 20 | } 21 | 22 | void waiting(){ // WAITING 23 | sleep(1); 24 | tm = current_time(); 25 | printf("Current remove = %d, pids[..] = %d\n", conveyor->current_remove, conveyor->pids[conveyor->current_remove]); 26 | printf("Truck is ready for loading: %ld.%ld\n\n", tm.tv_sec, tm.tv_usec); 27 | if (conveyor->pids[conveyor->current_remove] > 0) 28 | conveyor->t_status = LOADING; 29 | } 30 | 31 | void take_package(){ // LOADING 32 | sleep(1); 33 | int current = conveyor->current_remove; 34 | if (conveyor->pids[current] < 0){ 35 | printf("Current remove %d is less than zero: %d.\n", current, (int)conveyor->pids[current]); 36 | return; 37 | } 38 | 39 | int weight = conveyor->weights[current]; 40 | pid_t client_pid = conveyor->pids[current]; 41 | timeval c_time = conveyor->times[current]; 42 | tm = gettime(); 43 | if (conveyor->truck_left_space >= weight){ 44 | conveyor->curr_k -= 1; 45 | conveyor->curr_m -= weight; 46 | conveyor->pids[current] = -1; // zebym wiedzial ze puste 47 | conveyor->truck_left_space -= weight; 48 | conveyor->current_remove = (current + 1) % K; 49 | 50 | time_t secs; 51 | suseconds_t usecs; 52 | 53 | if (tm.tv_usec - c_time.tv_usec < 0){ 54 | secs = tm.tv_sec - c_time.tv_sec; 55 | usecs = c_time.tv_usec - tm.tv_usec; 56 | } 57 | else{ 58 | secs = tm.tv_sec - c_time.tv_sec; 59 | usecs = tm.tv_usec - c_time.tv_usec; 60 | } 61 | 62 | printf("Package %dkg from %d was being processed for %ld.%lds. %d/%d and %d/%d left.\n", 63 | weight, 64 | client_pid, 65 | secs, usecs, 66 | M - conveyor->curr_m, M, 67 | K - conveyor->curr_k, K 68 | ); 69 | } 70 | if (conveyor->truck_left_space >= weight){ 71 | conveyor->t_status = WAITING; 72 | } 73 | else { 74 | conveyor->t_status = DEPARTURE; 75 | } 76 | } 77 | 78 | void empty_the_truck(){ // DEPARTURE 79 | trucker_acquire(semid); // blokujemy wstawianie na tasme 80 | sleep(1); 81 | tm = current_time(); 82 | printf("Truck is full %d/%d: %ld.%ld\n", 83 | X-conveyor->truck_left_space, 84 | X, 85 | tm.tv_sec, tm.tv_usec 86 | ); 87 | conveyor->truck_left_space = X; 88 | conveyor->t_status = ARRIVAL; 89 | trucker_release(semid); 90 | } 91 | 92 | void clean_memory() { 93 | conveyor->t_status = ARRIVAL; // blokuje przez petle while 94 | trucker_acquire(semid); 95 | while (!is_conveyor_empty()){ 96 | if (conveyor->t_status == DEPARTURE) 97 | empty_the_truck(); 98 | else 99 | take_package(); 100 | } 101 | if(shmdt(conveyor) < 0) error("Detach shared memory.\n"); 102 | if(semid != 0) semctl(semid, 0, IPC_RMID); 103 | if(shmid != 0) shmctl(shmid, IPC_RMID, NULL); 104 | } 105 | 106 | void init_trucker(){ 107 | if (signal(SIGINT, SIGINT_handler) == SIG_ERR) error("signal"); 108 | if (atexit(clean_memory) != 0) error("atexit"); 109 | if ((key = ftok(PROJECT_PATH, PROJECT_ID)) == -1) /* --> */ error("ftok"); 110 | if ((shmid = shmget(key, sizeof(Conveyor), S_IRWXU|IPC_CREAT)) < 0) error("shmget"); 111 | if ((conveyor = shmat(shmid, NULL, 0)) == (void*) -1) /* --> */ error("shmat"); 112 | if ((semid = semget(key, 4, S_IRWXU|IPC_CREAT)) < 0) /* --> */ error("semget"); 113 | 114 | semun arg2; 115 | semun arg3; 116 | 117 | arg2.val = K; 118 | arg3.val = M; 119 | 120 | if (semctl(semid, 0, SETVAL, 0) < 0) /* --> */ error("semtctl 1"); 121 | if (semctl(semid, 1, SETVAL, 0) < 0) /* --> */ error("semtctl 2"); 122 | if (semctl(semid, 2, SETVAL, arg2) < 0) /* --> */ error("semtctl 3"); 123 | if (semctl(semid, 3, SETVAL, arg3) < 0) /* --> */ error("semtctl 4"); 124 | 125 | conveyor->t_status = ARRIVAL; 126 | conveyor->K = K; 127 | conveyor->curr_k = 0; 128 | conveyor->M = M; 129 | conveyor->curr_m = 0; 130 | conveyor->current_insert = 0; 131 | conveyor->current_remove = 0; 132 | conveyor->truck_left_space = X; 133 | 134 | for (size_t i = 0; i < K; ++i){ 135 | conveyor->pids[i] = (pid_t) -1; 136 | } 137 | } 138 | 139 | int main(int argv, char ** argc){ 140 | if (argv != 4) error("Bad args number"); 141 | X = atoi(argc[1]); 142 | K = atoi(argc[2]); 143 | M = atoi(argc[3]); 144 | init_trucker(); 145 | 146 | conveyor->s_time = gettime(); 147 | 148 | release_conveyor(semid); 149 | trucker_release(semid); 150 | 151 | while(1){ 152 | switch(conveyor->t_status){ 153 | case ARRIVAL: 154 | arrival(); 155 | break; 156 | case WAITING: 157 | waiting(); 158 | break; 159 | case LOADING: 160 | take_package(); 161 | break; 162 | case DEPARTURE: 163 | empty_the_truck(); 164 | break; 165 | } 166 | } 167 | 168 | return 0; 169 | } 170 | -------------------------------------------------------------------------------- /07. Inter-process communication(semaphore)/zad2/loader.c: -------------------------------------------------------------------------------- 1 | #include "shared_utils.h" 2 | 3 | int N; 4 | int loaders_num; 5 | 6 | int t_shmfd; 7 | int l_shmfd; 8 | 9 | sem_t * t_sem; 10 | sem_t * l_sem; 11 | 12 | timeval tm; 13 | 14 | void SIGUSR_handler(int signum){ 15 | printf("I gotta clean up after myself.\n"); 16 | 17 | if (sem_close(t_sem) == -1) /* -----------> */ error("sem_close(t_sem)"); 18 | if (sem_close(l_sem) == -1) /* -----------> */ error("sem_close(l_sem)"); 19 | 20 | if (sem_unlink(T_SEM_NAME) == -1) /* -----> */ error("sem_unlink T"); 21 | if (sem_unlink(L_SEM_NAME) == -1) /* -----> */ error("sem_unlink L"); 22 | 23 | if (munmap(conveyor, sizeof(conveyor)) == -1) error("munmap T"); 24 | if (munmap(acc, sizeof(acc)) == -1) error("munmap L"); 25 | 26 | if (shm_unlink(T_SEM_NAME) == -1) /* -----> */ error("shm_unlink T"); 27 | if (shm_unlink(L_SEM_NAME) == -1) /* -----> */ error("shm_unlink L"); 28 | 29 | exit(EXIT_SUCCESS); 30 | } 31 | 32 | void awaiting_for_conveyor(){ // AWAITING 33 | sleep(3); 34 | tm = current_time(); 35 | printf("%d is waiting for the production tape to be released: %ld.%ld\n", getpid(), tm.tv_sec, tm.tv_usec); 36 | } 37 | 38 | void put_package_on_conveyor(int w){ // SHIPING 39 | sleep(3); 40 | while (!is_conveyor_available()){ 41 | awaiting_for_conveyor(); 42 | } 43 | truckers_acquire(t_sem); // sprawdzamy, czy kierowca nie odjechal 44 | truckers_release(t_sem); 45 | loaders_acquire(l_sem); 46 | 47 | tm = gettime(); 48 | 49 | while (conveyor->curr_m + w > conveyor->M || conveyor->curr_k + 1 > conveyor->K){} 50 | int current = conveyor->current_insert; 51 | conveyor->times[current] = tm; 52 | conveyor->weights[current] = w; 53 | conveyor->pids[current] = getpid(); 54 | conveyor->curr_k += 1; 55 | conveyor->curr_m += w; 56 | 57 | tm = current_time(); 58 | printf("Placed %dkg by %d. %d/%dkg, %d/%dunits occupied. Time: %ld.%ld.\n\n", 59 | w, getpid(), 60 | conveyor->curr_m, 61 | conveyor->M, 62 | conveyor->curr_k, 63 | conveyor->K, 64 | tm.tv_sec, tm.tv_usec 65 | ); 66 | 67 | conveyor->current_insert = // insert inkrementujemy na koncu 68 | (conveyor->current_insert + 1) % conveyor->K; 69 | 70 | while (conveyor->pids[conveyor->current_insert] != -1){} 71 | loaders_release(l_sem); 72 | } 73 | 74 | void init_loaders(){ 75 | signal(SIGUSR1, SIGUSR_handler); 76 | if ((t_shmfd = shm_open(T_SEM_NAME, O_RDWR, S_IRWXU_G)) == -1) /* --------------------------> */ error("shmopen T"); 77 | if ((l_shmfd = shm_open(L_SEM_NAME, O_RDWR, S_IRWXU_G)) == -1) /* --------------------------> */ error("shmopen L"); 78 | 79 | if ((conveyor = mmap(NULL, sizeof(*conveyor), PROT_RD_WR, MAP_SHARED, t_shmfd, 0)) == (void*)-1) error("mmap T"); 80 | if ((acc = mmap(NULL, sizeof(*acc), PROT_RD_WR, MAP_SHARED, l_shmfd, 0)) == (void*)-1) error("mmap L"); 81 | 82 | if ((t_sem = sem_open(T_SEM_NAME, O_RDWR)) == (void*)-1) /* --------------------------------> */ error("sem_open T"); 83 | if ((l_sem = sem_open(L_SEM_NAME, O_RDWR)) == (void*)-1) /* --------------------------------> */ error("sem_open L"); 84 | } 85 | 86 | void limited_action(int C, int w){ 87 | for (int i = C-1; i >= 0; --i){ 88 | printf("W petelce, i = %d, pid = %d\n", i, getpid()); 89 | put_package_on_conveyor(w); 90 | } 91 | exit(0); 92 | } 93 | 94 | void infinite_action(int w){ 95 | while(1){ 96 | printf("PID = %d\n", getpid()); 97 | put_package_on_conveyor(w); 98 | } 99 | } 100 | 101 | int main(int argc, char ** argv){ 102 | if (argc > 4 || argc <= 2) error("Bad args number"); 103 | N = atoi(argv[1]); 104 | loaders_num = atoi(argv[2]); 105 | 106 | init_loaders(); 107 | conveyor->loaders_pid = getpid(); 108 | 109 | if (argc == 4){ // arg C provided 110 | int C = atoi(argv[3]); 111 | for(int i = 0; i < loaders_num; ++i){ 112 | if (fork() == 0){ 113 | /// Pracowników uruchamiamy fork i exec - argument programu 114 | limited_action(C, (i+1)%N); 115 | } 116 | } 117 | } 118 | else { // arg C not provided 119 | for(int i = 0; i < loaders_num; ++i){ 120 | if (fork() == 0){ 121 | infinite_action((i+1)%N); 122 | } 123 | } 124 | } 125 | 126 | while(wait(0)){ 127 | if(errno != ECHILD) 128 | break; 129 | } 130 | 131 | return 0; 132 | } 133 | -------------------------------------------------------------------------------- /07. Inter-process communication(semaphore)/zad2/makefile: -------------------------------------------------------------------------------- 1 | CC = gcc -Wall -o 2 | flags = -lpthread -lrt 3 | 4 | clean: 5 | rm -f loader 6 | rm -f trucker 7 | rm -f test 8 | rm -f *.o 9 | 10 | compile: 11 | $(CC) loader loader.c $(flags) 12 | $(CC) trucker trucker.c $(flags) 13 | 14 | run_trucker: 15 | ./trucker 100 16 50 16 | 17 | run_loader: 18 | ./loader 5 4 3 19 | -------------------------------------------------------------------------------- /07. Inter-process communication(semaphore)/zad2/shared_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef SHARED_UTILS_H 2 | #define SHARED_UTILS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | 21 | #define MAX_PCKGS_NUM 256 22 | #define T_SEM_NAME "/xAAAN" 23 | #define L_SEM_NAME "/xAABN" 24 | 25 | typedef struct timeval timeval; 26 | 27 | /** Arguments: 28 | - trucker.c: 29 | X to pojemnosc tira 30 | K to max liczba paczek na tasmie 31 | M to max masa paczek na tasmie 32 | - loader.c: 33 | N to maksymalna masa paczki 34 | loaders_num to liczba loaderow 35 | C to liczba cykli 36 | */ 37 | 38 | int * acc; 39 | int RDWR_CREAT_EXCL = O_RDWR | O_CREAT | O_EXCL; 40 | mode_t S_IRWXU_G = S_IRWXU | S_IRWXG|0666; 41 | int PROT_RD_WR = PROT_READ | PROT_WRITE; 42 | 43 | enum trucker_status{ 44 | ARRIVAL, 45 | WAITING, 46 | LOADING, 47 | DEPARTURE 48 | }; 49 | typedef enum trucker_status trucker_status; 50 | 51 | enum loader_status{ 52 | SHIPING, 53 | AWAITING 54 | }; 55 | typedef enum loader_status loader_status; 56 | 57 | struct Conveyor{ 58 | trucker_status t_status; 59 | pid_t loaders_pid; 60 | int K; // max liczba sztuk 61 | int curr_k; // aktualna liczba sztuk 62 | int M; // max waga 63 | int curr_m; // aktualna waga 64 | int current_insert; // miejsce pod ktorym mozemy (po weryfikacji) wsadzic loadera 65 | int current_remove; // stad pierwsza paczka do wziecia 66 | pid_t pids[MAX_PCKGS_NUM]; // kolejka pidow loaderow 67 | int weights[MAX_PCKGS_NUM]; // waga poszczegolnych paczek 68 | timeval times[MAX_PCKGS_NUM]; // czasy polozenia na tasmie 69 | int truck_left_space; 70 | timeval s_time; 71 | } *conveyor; 72 | typedef struct Conveyor Conveyor; 73 | 74 | void SIGINT_handler(int signum){ 75 | printf("Finished unloading.\n"); 76 | exit(EXIT_SUCCESS); 77 | } 78 | 79 | struct timeval gettime(){ 80 | struct timeval time; 81 | gettimeofday(&time, NULL); 82 | return time; 83 | } 84 | 85 | struct timeval current_time(){ 86 | struct timeval time, ret_time; 87 | gettimeofday(&time, NULL); 88 | if (time.tv_usec - conveyor->s_time.tv_usec < 0){ 89 | ret_time.tv_sec = time.tv_sec - conveyor->s_time.tv_sec-1; 90 | ret_time.tv_usec = conveyor->s_time.tv_usec - time.tv_usec; 91 | } 92 | else { 93 | ret_time.tv_sec = time.tv_sec - conveyor->s_time.tv_sec-1; 94 | ret_time.tv_usec = time.tv_usec - conveyor->s_time.tv_usec; 95 | } 96 | return ret_time; 97 | } 98 | 99 | void error(char * msg){ 100 | perror(msg); 101 | exit(EXIT_FAILURE); 102 | } 103 | 104 | /// ^^^^^ SEMAPHORES ^^^^^ 105 | void loaders_acquire(sem_t * sem){ 106 | if (sem_wait(sem) == -1) /* --> */ error("sem_wait"); 107 | } 108 | 109 | void loaders_release(sem_t * sem){ 110 | if (sem_post(sem) == -1) /* --> */ error("sem_post"); 111 | } 112 | 113 | // te ponizej robia to samo, ale latwiej w kodzie sie odnalezc 114 | void truckers_acquire(sem_t * sem){ 115 | if (sem_wait(sem) == -1) /* --> */ error("sem_wait"); 116 | } 117 | 118 | void truckers_release(sem_t * sem){ 119 | if (sem_post(sem) == -1) /* --> */ error("sem_post"); 120 | } 121 | /// $$$$$ SEMAPHORES $$$$$ 122 | 123 | int is_conveyor_available(){ 124 | return conveyor->t_status == WAITING || conveyor->t_status == LOADING; 125 | } 126 | 127 | int is_conveyor_empty(){ 128 | return conveyor->pids[conveyor->current_remove] < 0; 129 | } 130 | 131 | #endif // SHARED_UTILS_H 132 | -------------------------------------------------------------------------------- /07. Inter-process communication(semaphore)/zad2/trucker.c: -------------------------------------------------------------------------------- 1 | #include "shared_utils.h" 2 | 3 | int X, K, M; 4 | 5 | int t_shmfd; 6 | int l_shmfd; 7 | 8 | sem_t * t_sem; 9 | sem_t * l_sem; 10 | 11 | timeval tm; 12 | 13 | void arrival(){ // ARRIVAL 14 | sleep(1); 15 | tm = current_time(); 16 | printf("\nTruck just arrived: %ld.%ld.\n", tm.tv_sec, tm.tv_usec); 17 | conveyor->t_status = WAITING; 18 | } 19 | 20 | void waiting(){ // WAITING 21 | sleep(1); 22 | tm = current_time(); 23 | printf("\nconveyor->pids[%d] = %d\n", conveyor->current_remove, conveyor->pids[conveyor->current_remove]); 24 | printf("Truck is ready for loading: %ld.%ld.\n\n", tm.tv_sec, tm.tv_usec); 25 | if (conveyor->pids[conveyor->current_remove] > 0) 26 | conveyor->t_status = LOADING; 27 | } 28 | 29 | void take_package(){ // LOADING 30 | sleep(1); 31 | int current = conveyor->current_remove; 32 | if (conveyor->pids[current] < 0){ 33 | printf("Current remove %d is less than zero: %d.\n", current, (int)conveyor->pids[current]); 34 | return; 35 | } 36 | 37 | int weight = conveyor->weights[current]; 38 | pid_t client_pid = conveyor->pids[current]; 39 | timeval c_time = conveyor->times[current]; 40 | tm = gettime(); 41 | if (conveyor->truck_left_space >= weight){ 42 | conveyor->curr_k -= 1; 43 | conveyor->curr_m -= weight; 44 | conveyor->pids[current] = -1; // zebym wiedzial ze puste 45 | conveyor->truck_left_space -= weight; 46 | conveyor->current_remove = (current + 1) % K; 47 | 48 | time_t secs; 49 | suseconds_t usecs; 50 | 51 | if (tm.tv_usec - c_time.tv_usec < 0){ 52 | secs = tm.tv_sec - c_time.tv_sec; 53 | usecs = c_time.tv_usec - tm.tv_usec; 54 | } 55 | else{ 56 | secs = tm.tv_sec - c_time.tv_sec; 57 | usecs = tm.tv_usec - c_time.tv_usec; 58 | } 59 | 60 | printf("Package %dkg from %d was being processed for %ld.%lds. %d/%d and %d/%d left.\n", 61 | weight, 62 | client_pid, 63 | secs, usecs, 64 | M - conveyor->curr_m, M, 65 | K - conveyor->curr_k, K 66 | ); 67 | } 68 | if (conveyor->truck_left_space >= weight){ 69 | conveyor->t_status = WAITING; 70 | } 71 | else { 72 | conveyor->t_status = DEPARTURE; 73 | } 74 | } 75 | 76 | void empty_the_truck(){ // DEPARTURE 77 | truckers_acquire(t_sem); // blokujemy wstawianie na tasme ... 78 | sleep(1); 79 | tm = current_time(); 80 | printf("Truck is full %d/%d. Time: %ld.%ld.\n", 81 | X-conveyor->truck_left_space, 82 | X, 83 | tm.tv_sec, tm.tv_usec 84 | ); 85 | conveyor->truck_left_space = X; 86 | conveyor->t_status = ARRIVAL; 87 | truckers_release(t_sem); // ... i odblokowujemy 88 | } 89 | 90 | void clean_memory(){ 91 | conveyor->t_status = ARRIVAL; // blokuje przez petle while 92 | truckers_acquire(t_sem); 93 | while (!is_conveyor_empty()){ 94 | if (conveyor->t_status == DEPARTURE) 95 | empty_the_truck(); 96 | else 97 | take_package(); 98 | } 99 | 100 | kill(conveyor->loaders_pid, SIGUSR1); 101 | 102 | // zamykanie/usuwanie zasobow systemowych 103 | if (sem_close(t_sem) == -1) /* -----------> */ error("sem_close(t_sem)"); 104 | if (sem_close(l_sem) == -1) /* -----------> */ error("sem_close(l_sem)"); 105 | 106 | if (munmap(conveyor, sizeof(conveyor)) == -1) error("munmap T"); 107 | if (munmap(acc, sizeof(acc)) == -1) error("munmap L"); 108 | } 109 | 110 | void init_trucker(){ 111 | // handlers and exit 112 | if (signal(SIGINT, SIGINT_handler) < 0) /* -> */ error("signal"); 113 | if (atexit(clean_memory) < 0) /* -----------> */ error("atexit"); 114 | 115 | // shared memory 116 | if ((t_shmfd = shm_open(T_SEM_NAME, RDWR_CREAT_EXCL, S_IRWXU_G)) == -1) /* -----------------> */ error("shm_open"); 117 | if ((l_shmfd = shm_open(L_SEM_NAME, RDWR_CREAT_EXCL, S_IRWXU_G)) == -1) /* -----------------> */ error("shm_open"); 118 | 119 | if (ftruncate(t_shmfd, sizeof(*conveyor)) == -1) /* ----------------------------------------> */ error("ftruncate"); 120 | if (ftruncate(l_shmfd, sizeof(*acc)) == -1) /* ----------------------------------------> */ error("ftruncate"); 121 | 122 | if ((conveyor = mmap(NULL, sizeof(*conveyor), PROT_RD_WR, MAP_SHARED, t_shmfd, 0)) == (void*)-1) error("mmap"); 123 | if ((acc = mmap(NULL, sizeof(*acc), PROT_RD_WR, MAP_SHARED, l_shmfd, 0)) == (void*)-1) error("mmap"); 124 | 125 | // semaphores 126 | if ((t_sem = sem_open(T_SEM_NAME, RDWR_CREAT_EXCL, S_IRWXU_G, 0)) == (void*)-1) /* ---------> */ error("sem_open"); 127 | if ((l_sem = sem_open(L_SEM_NAME, RDWR_CREAT_EXCL, S_IRWXU_G, 0)) == (void*)-1) /* ---------> */ error("sem_open"); 128 | 129 | // initialization 130 | conveyor->t_status = ARRIVAL; 131 | conveyor->K = K; 132 | conveyor->curr_k = 0; 133 | conveyor->M = M; 134 | conveyor->curr_m = 0; 135 | conveyor->current_insert = 0; 136 | conveyor->current_remove = 0; 137 | conveyor->truck_left_space = X; 138 | 139 | for (int i = 0; i < K; ++i){ 140 | conveyor->pids[i] = -1; 141 | } 142 | } 143 | 144 | int main(int argc, char ** argv){ 145 | if (argc != 4) error("bad args number"); 146 | 147 | X = atoi(argv[1]); 148 | K = atoi(argv[2]); 149 | M = atoi(argv[3]); 150 | 151 | init_trucker(); 152 | conveyor->s_time = gettime(); 153 | 154 | truckers_release(t_sem); 155 | loaders_release(l_sem); 156 | 157 | while(1){ 158 | switch(conveyor->t_status){ 159 | case ARRIVAL: 160 | arrival(); 161 | break; 162 | case WAITING: 163 | waiting(); 164 | break; 165 | case LOADING: 166 | take_package(); 167 | break; 168 | case DEPARTURE: 169 | empty_the_truck(); 170 | break; 171 | } 172 | } 173 | 174 | return 0; 175 | } 176 | -------------------------------------------------------------------------------- /08. Threads - image filtering/README.md: -------------------------------------------------------------------------------- 1 | # Zadanie 1 2 | 3 | Napisz program, który wykonuje wielowątkową operację filtrowania obrazu. Program przyjmuje w argumentach wywołania: 4 | 5 | * liczbę wątków, 6 | * sposób podziału obrazu pomiędzy wątki, t.j. jedną z dwóch opcji: block / interleaved, 7 | * nazwę pliku z wejściowym obrazem, 8 | * nazwę pliku z definicją filtru, 9 | * nazwę pliku wynikowego. 10 | 11 | Po wczytaniu danych (wejściowy obraz i definicja filtru) wątek główny tworzy tyle nowych wątków, ile zażądano w argumencie wywołania. Utworzone wątki równolegle tworzą wyjściowy (filtrowany) obraz. Każdy stworzony wątek odpowiada za wygenerowanie części wyjściowego obrazu: 12 | 13 | Gdy program został uruchomiony z opcją block, k-ty wątek wylicza wartości pikseli w pionowym pasku o współrzędnych x-owych w przedziale od (k−1)∗ceil(N/m) do k∗ceil(N/m)−1, gdzie N to szerokość wyjściowego obrazu a m to liczba stworzonych wątków. 14 | Gdy program został uruchomiony z opcją interleaved, k-ty wątek wylicza wartości pikseli, których współrzędne x-owe to: k−1, k−1+m, k−1+2∗m, k−1+3∗m, itd. (ponownie, m to liczba stworzonych wątków). 15 | 16 | Po wykonaniu obliczeń wątek kończy pracę i zwraca jako wynik (patrz pthread_exit) czas rzeczywisty spędzony na tworzeniu przydzielonej mu części wyjściowego obrazu. Czas ten należy zmierzyć z dokładnością do mikrosekund. Wątek główny czeka na zakończenie pracy przez wątki wykonujące operację filtrowania. Po zakończeniu każdego wątku, wątek główny odczytuje wynik jego działania i wypisuje na ekranie informację o czasie, jaki zakończony wątek poświęcił na filtrowanie obrazu (wraz z identyfikatorem zakończonego wątku). Dodatkowo, po zakończeniu pracy przez wszystkie stworzone wątki, wątek główny zapisuje powstały obraz do pliku wynikowego i wypisuje na ekranie czas rzeczywisty spędzony w całej operacji filtrowania (z dokładnością do mikrosekund). W czasie całkowitym operacji filtrowania należy uwzględnić narzut związany z utworzeniem i zakończeniem wątków (ale bez czasu operacji wejścia/wyjścia). 17 | Wykonaj pomiary czasu operacji filtrowania dla obrazu o rozmiarze kilkaset na kilkaset pikseli i dla kilku filtrów (można wykorzystać losowe macierze filtrów). Testy przeprowadź dla 1, 2, 4, i 8 wątków. Rozmiar filtrów dobierz w zakresie 3≤c≤65 18 | , tak aby uwidocznić wpływ liczby wątków na czas operacji filtrowania. Eksperymenty wykonaj dla obu wariantów podziału obrazu pomiędzy wątki (block i interleaved). Wyniki zamieść w pliku Times.txt i dołącz do archiwum z rozwiązaniem zadania. 19 | 20 | ### Format wejścia-wyjścia 21 | 22 | Program powinien odczytywać i zapisywać obrazy w formacie ASCII PGM (Portable Gray Map). Pliki w tym formacie mają nagłówek postaci: 23 | 24 | P2 25 | W H 26 | M 27 | ... 28 | 29 | gdzie: W to szerokość obrazu w pikselach, H to wysokość obrazu w pikselach a M to maksymalna wartość piksela. Zakładamy, że obsługujemy jedynie obrazy w 256 odcieniach szarości: od 0 do 255 (a więc M=255). Po nagłówku, w pliku powinno być zapisanych W*H liczb całkowitych reprezentujących wartości kolejnych pikseli. Liczby rozdzielone są białymi znakami (np. spacją). Piksele odczytywane są wierszami, w kolejności od lewego górnego do prawego dolnego rogu obrazu. 30 | 31 | Przykładowe obrazy w formacie ASCII PGM (jak również opis formatu) można znaleźć pod adresem: 32 | http://people.sc.fsu.edu/~jburkardt/data/pgma/pgma.html 33 | 34 | W pierwszej linii pliku z definicją filtru powinna znajdować się liczba całkowita c 35 | określająca rozmiar filtru. Dalej, plik powinien zawierać c2 liczb zmiennoprzecinkowych określających wartości elementów filtru (w kolejności wierszy, od elementu K[1,1] do elementu K[c,c]). 36 | -------------------------------------------------------------------------------- /08. Threads - image filtering/apple.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wreczek/Operating-Systems/903f132c4b8089d0e875df0548d333be870cc13f/08. Threads - image filtering/apple.jpeg -------------------------------------------------------------------------------- /08. Threads - image filtering/blurry_c3.txt: -------------------------------------------------------------------------------- 1 | 3 2 | 0.1 0.2 0.05 3 | 0.25 0.1 0.1 4 | 0.1 0 0.1 5 | -------------------------------------------------------------------------------- /08. Threads - image filtering/contours_c3.txt: -------------------------------------------------------------------------------- 1 | 3 2 | -1 -1 -1 3 | -1 8 -1 4 | -1 -1 -1 5 | -------------------------------------------------------------------------------- /08. Threads - image filtering/contrast_c5.txt: -------------------------------------------------------------------------------- 1 | 5 2 | -4 2 3 2 -4 3 | 1 1 -4 1 1 4 | 2 4 -9 4 2 5 | 1 1 -4 1 1 6 | -4 2 3 2 -4 -------------------------------------------------------------------------------- /08. Threads - image filtering/distorted_c3.txt: -------------------------------------------------------------------------------- 1 | 3 2 | 2 2 2 3 | 2 -15 2 4 | 2 2 2 -------------------------------------------------------------------------------- /08. Threads - image filtering/filter_c40.txt: -------------------------------------------------------------------------------- 1 | 40 2 | -3 6 2 1 -1 -1 1 3 4 -2 3 3 -2 0 -1 2 7 1 -5 1 2 -4 -2 -1 0 -2 4 -1 -4 -1 5 0 5 -4 4 1 0 1 3 0 3 | -2 -4 6 6 1 5 -3 7 4 2 2 1 0 -3 3 -1 -5 3 0 4 1 6 -4 2 6 -4 0 -4 1 -4 -1 1 -3 -1 1 6 -4 -1 4 -2 4 | 0 2 -1 -5 -4 2 3 7 -4 2 -4 7 2 -3 1 -3 7 7 0 -4 -4 -3 7 2 -2 6 6 -4 6 -5 -5 7 -1 -5 -2 7 5 3 7 -3 5 | -5 -3 1 7 -3 1 -1 7 -2 -2 -2 -4 0 6 7 6 1 5 5 1 -4 -4 5 0 4 0 4 -4 3 2 2 3 2 3 0 0 3 4 4 -3 6 | 1 -2 6 4 7 -1 7 6 4 -2 -3 -5 6 -4 2 -5 -3 3 -1 6 3 2 1 3 -4 5 -5 -1 7 -4 4 5 2 5 7 3 -5 1 7 -2 7 | -5 6 4 -1 5 2 -5 0 7 -2 5 -5 0 6 6 -4 0 -5 7 -4 -2 1 -5 3 1 1 -1 2 0 0 -3 2 6 2 2 7 1 6 -5 7 8 | -5 -3 2 -1 -5 1 1 3 -5 -2 1 3 -1 4 4 1 -5 5 5 4 4 0 7 -5 -3 3 -2 1 -5 -5 3 -2 6 6 6 1 1 1 2 5 9 | -4 -1 -4 2 -3 6 4 4 3 7 -1 -3 1 2 -2 -3 -2 5 -1 3 6 0 7 3 6 -3 -3 1 5 -3 0 0 4 -2 4 -4 6 2 5 3 10 | 5 4 -3 2 0 -2 2 1 7 1 3 -1 3 -2 7 1 0 3 -2 1 -2 0 -1 -4 -3 1 -3 6 5 4 1 -5 1 6 -2 6 -4 -2 0 3 11 | -1 -1 4 3 2 2 1 -2 -2 -4 7 -3 -4 -2 6 -5 7 1 -1 7 5 4 5 5 7 5 5 5 4 -1 1 7 -5 6 -1 5 5 -3 4 -3 12 | 0 6 -3 5 4 0 1 7 2 -1 -2 2 -2 6 -3 2 -2 0 -1 -2 4 4 -3 1 2 7 -2 -5 4 -4 1 0 -4 7 0 -2 3 -1 4 3 13 | 3 5 5 -4 -3 -4 4 -2 1 -3 4 2 5 5 4 5 0 -1 2 2 4 -3 -2 0 -3 3 2 -2 3 2 5 4 -3 5 -2 -4 6 -4 6 6 14 | 6 2 7 3 5 2 -4 4 -1 -2 5 1 2 7 6 4 6 -2 6 0 6 7 7 3 -2 2 1 -3 6 -4 -3 1 5 -2 -4 -1 1 3 1 3 15 | 4 -5 6 -3 1 -5 -5 4 7 4 -5 2 2 6 4 -5 -4 -1 5 -1 7 -2 -1 1 -1 6 -4 -3 0 4 4 1 -5 3 4 1 -5 5 -1 -2 16 | 7 6 4 3 5 0 4 -2 2 6 -3 -1 -1 -3 0 -5 5 -1 -1 -2 0 -5 0 -4 4 -5 -4 0 4 3 0 1 -3 0 -1 6 -5 -3 6 2 17 | 7 -4 -2 -4 6 1 1 7 -5 6 7 3 -1 7 7 -2 6 -5 -5 2 5 -1 -3 7 -5 6 -2 4 0 -1 -2 5 1 0 4 -5 2 6 -2 -1 18 | -2 -5 3 -2 2 6 -3 -3 4 1 -4 7 -2 -1 -5 6 5 0 0 6 2 0 1 3 7 2 0 -3 4 3 -3 6 -4 -2 7 -2 -5 -5 3 7 19 | -5 3 4 -5 6 7 -3 1 1 1 6 -3 -2 0 -3 -3 -4 -3 -3 2 -2 -1 7 -5 4 -1 3 7 2 6 7 0 -3 5 0 5 4 -5 4 -3 20 | 2 4 -1 -1 2 4 7 -2 1 5 -5 7 -3 6 3 5 -5 -3 1 0 -4 -3 7 3 6 -3 0 5 2 -3 -1 -3 -4 3 3 -1 2 0 3 5 21 | -4 -2 6 -4 7 -3 1 0 -4 0 7 0 3 -4 -3 2 6 -2 -1 -2 3 -4 2 5 4 -3 -5 6 -5 -5 1 -4 7 -3 -1 6 -1 -4 -5 7 22 | -5 3 0 7 4 4 5 -3 2 -3 2 5 -5 -5 -4 7 -5 6 6 7 -4 5 2 -1 -5 4 7 6 4 2 1 4 -2 7 -5 -1 -2 0 1 6 23 | 5 3 5 2 7 5 2 7 2 4 1 7 -5 5 4 -3 2 1 7 0 -3 3 5 5 6 0 -4 5 7 -5 -3 -2 7 4 2 5 5 5 4 0 24 | 4 0 -5 4 -3 -4 4 -2 6 7 -1 3 -1 3 3 6 5 3 4 4 4 -2 -4 0 -1 -3 6 7 -4 -3 -3 -3 -1 -4 -4 3 -3 4 -5 0 25 | 3 4 1 -2 -3 7 4 2 2 -4 1 0 1 3 2 -3 5 -5 2 5 3 4 -3 -1 4 2 4 4 -4 6 4 4 6 1 0 -2 -2 0 7 -1 26 | 2 6 1 3 4 -2 -3 6 1 -4 3 7 -3 -3 3 0 5 -3 7 2 4 -3 6 7 -2 7 7 3 0 1 -4 4 5 5 5 -2 -2 5 -1 6 27 | -3 -4 2 1 5 1 -2 -1 -4 2 2 4 -5 -5 3 2 2 4 6 1 7 -2 -4 -5 5 4 -4 4 2 -3 6 5 4 -2 6 2 0 -4 -1 3 28 | -2 0 7 -4 6 7 6 -2 -3 3 -3 -1 3 6 0 -4 7 -3 4 4 -5 -2 6 -4 5 4 4 -4 0 6 6 1 3 -5 6 5 7 2 7 1 29 | 0 6 0 -3 1 5 3 5 -4 3 -5 -5 -1 -1 -3 6 0 3 -1 -3 -2 0 4 -2 7 -3 -4 7 0 4 3 0 -5 -2 6 4 0 4 6 -5 30 | -1 -1 -4 3 1 3 -5 5 3 -2 -2 -1 7 -2 5 -2 4 0 -1 -2 -2 2 0 4 -2 -4 -1 -5 5 6 1 0 4 5 1 1 -3 2 -5 2 31 | -4 0 4 5 5 -1 6 6 1 0 2 -1 1 -1 -5 3 -1 4 -3 -5 -4 2 7 0 5 7 -1 -1 2 -1 -5 4 -5 4 -1 6 0 4 -3 0 32 | 6 4 2 4 4 -5 -1 -3 5 2 -5 6 4 0 4 0 -5 0 -2 0 0 0 -2 -3 2 2 7 2 6 6 1 6 0 -4 -4 -3 6 0 -1 -1 33 | 7 -4 6 0 -1 3 -3 -4 5 -2 5 -3 -1 -4 -5 4 -2 -2 -3 -3 0 5 6 7 -3 -4 -4 1 -5 6 -2 -1 -3 7 -4 4 6 -5 -5 2 34 | 4 5 -4 -3 6 -3 -1 6 -1 0 -1 -2 -4 5 -3 7 -4 7 7 6 -2 5 5 3 1 2 -1 4 7 2 -5 -4 -1 7 5 -4 5 3 7 4 35 | -4 6 3 -3 7 6 1 -1 -3 -4 3 0 0 5 6 -2 -3 2 5 -4 -4 0 -3 0 1 2 4 6 -1 -5 0 5 -2 4 7 -4 -2 -4 2 2 36 | 5 4 0 0 7 2 -2 1 -5 6 -5 -4 6 -4 7 0 -5 -5 7 6 -2 2 2 -1 3 5 -3 1 5 -5 5 2 -4 -3 3 -3 2 -5 -5 -3 37 | 1 -2 6 2 7 -5 0 -4 -5 7 4 -1 7 -4 1 1 -2 2 5 4 -2 5 -1 7 6 0 -5 -5 2 1 -5 -3 0 -3 3 7 -5 4 6 3 38 | -3 2 -1 3 1 3 4 -4 0 0 -1 6 1 7 -2 4 1 -5 6 0 7 0 -5 4 7 7 3 -3 3 7 -3 2 2 -3 4 2 7 -2 1 7 39 | -5 5 1 4 7 4 4 7 3 7 5 1 6 3 -4 -1 -3 0 -1 -3 6 -1 4 7 3 -3 7 2 -4 -3 -1 0 4 5 -1 5 1 -4 -5 7 40 | 7 4 3 4 2 0 -4 -3 6 -5 4 2 3 4 -5 -3 2 5 5 2 0 -2 -5 1 6 2 -2 5 7 4 4 0 2 -5 7 -4 -2 5 -5 -3 41 | 4 -5 4 5 1 3 5 -4 -3 1 5 2 3 -5 6 4 1 3 -2 5 1 6 -5 5 4 -4 -1 0 -3 -3 5 -5 0 -4 -1 -3 -4 6 0 7 42 | -------------------------------------------------------------------------------- /08. Threads - image filtering/makefile: -------------------------------------------------------------------------------- 1 | CC = gcc -Wall -o 2 | 3 | clean: 4 | rm -f main 5 | rm -f *.o 6 | 7 | compile: 8 | make clean 9 | $(CC) main main.c -lpthread -lm 10 | 11 | run: 12 | ./main 1 interleaved apple.pgm distorted_c3.txt apple_res.pgm 13 | ./main 2 interleaved apple.pgm distorted_c3.txt apple_res.pgm 14 | ./main 4 interleaved apple.pgm distorted_c3.txt apple_res.pgm 15 | ./main 8 interleaved apple.pgm distorted_c3.txt apple_res.pgm 16 | 17 | ./main 1 block apple.pgm distorted_c3.txt apple_res.pgm 18 | ./main 2 block apple.pgm distorted_c3.txt apple_res.pgm 19 | ./main 4 block apple.pgm distorted_c3.txt apple_res.pgm 20 | ./main 8 block apple.pgm distorted_c3.txt apple_res.pgm 21 | -------------------------------------------------------------------------------- /08. Threads - image filtering/sharpness_c3.txt: -------------------------------------------------------------------------------- 1 | 3 2 | 4 -1 4 3 | -2 -2 -2 4 | 3 -2 -1 5 | -------------------------------------------------------------------------------- /09. Threads - synchronization methods/README.md: -------------------------------------------------------------------------------- 1 | # Opis problemu 2 | 3 | W ramach zadana należy zaimplementować rozwiązanie problemu synchronizacyjnego wagoników roller coaster. 4 | 5 | Po torze w wesołym miasteczku porusza się kilka wagoników roller coaster. Wagoniki nie mogą się wyprzedzać (poruszają się po jednym torze). Po podjechaniu do platformy wagonik otwiera drzwi. Następnie z wagonika wysiadają pasażerowie (jeśli wagonik nie był pusty). Gdy wszyscy pasażerowie wysiądą, do wagonika wsiada kolejna grupa pasażerów. Gdy do wagonika wsiądzie dokładnie c pasażerów jeden z nich (wybrany losowo) wciska przycisk start. Wówczas wagonik zamyka drzwi i odjeżdża. Do platformy może następnie podjechać kolejny wagonik. 6 | 7 | ## Zadanie 8 | 9 | Zaimplementuj poprawne rozwiązanie problemu synchronizacji wagoników roller coaster, w którym każdy pasażer i każdy wagonik to osobny wątek. Wagonik wypisuje komunikaty o następujących zdarzeniach: 10 | 11 | 1. Zamknięcie drzwi. 12 | 2. Rozpoczęcie jazdy. Zakładamy, że jazda trwa pewien losowy okres czasu. Na potrzeby zadania można przyjąć czas w przedziale od 0 do kilku milisekund. 13 | 3. Zakończenie jazdy. 14 | 4. Otwarcie drzwi. 15 | 5. Zakończenie pracy wątku. 16 | 17 | Pasażer wypisuje komunikaty o następujących zdarzeniach: 18 | 19 | 1. Wejście do wagonika. Komunikat ten zawiera aktualną liczbę pasażerów w wagoniku. 20 | 2. Opuszczenie wagonika. Komunikat ten zawiera aktualną liczbę pasażerów w wagoniku. 21 | 3. Naciśnięcie przycisku start. 22 | 4. Zakończenie pracy wątku. 23 | 24 | Każdy wypisywany komunikat musi zawierać znacznik czasowy z dokładnością do milisekund oraz identyfikator, odpowiednio, wagonika lub pasażera. Sekwencja zdarzeń musi gwarantować poprawy przewóz pasażerów. Niedopuszczalne jest na przykład: 25 | 26 | * wejście pasażera do wagonika gdy w wagoniku znajduje się pasażer z poprzedniej jazdy, 27 | * wejście do wagonika więcej niż c pasażerów, 28 | * naciśnięcie przycisku start gdy w wagoniku jest mniej niż c pasażerów, 29 | * zamknięcie drzwi przed naciśnięciem przycisku start, 30 | * podjechanie wagonika do platformy zanim poprzedni wagonik z niej odjedzie, 31 | * zmiana kolejności wagoników na torze (podjeżdżają do platformy w kolejności innej, niż z niej uprzednio odjechały), 32 | * etc. 33 | 34 | Niedopuszczalne jest również rozwiązanie, w którym niektóre wątki są głodzone (niektórzy pasażerowie w ogóle nie wsiadają do wagoników, podczas gdy inni jeżdżą wielokrotnie). 35 | 36 | Program należy zaimplementować korzystając z wątków i mechanizmów synchronizacji biblioteki POSIX Threads. Argumentami wywołania programu są: liczba wątków pasażerów, liczba wątków wagoników, pojemność wagonika (c) i liczba przejazdów (n). Po uruchomieniu programu wątek główny tworzy wątki dla pasażerów i dla wagoników. Następnie każdy wagonik wykonuje n przejazdów (wagoniki jadą po torze równocześnie, zachowując swoją początkową kolejność) po czym kończy pracę. Wątki pasażerów działają tak długo, jak długo pracuje choć jeden wagonik. W tym czasie wątek główny oczekuje na zakończenie wszystkich stworzonych wątków. Niedopuszczalne jest tworzenie dodatkowych wątków, których celem byłoby zapewnienie synchronizacji (lub wykorzystanie w tym celu wątku głównego). 37 | -------------------------------------------------------------------------------- /09. Threads - synchronization methods/makefile: -------------------------------------------------------------------------------- 1 | CC = gcc -Wall -o 2 | 3 | clean: 4 | rm -f *.o 5 | rm -f main 6 | 7 | compile: 8 | make clean 9 | $(CC) main main.c -lpthread 10 | 11 | run: 12 | make compile 13 | ./main 14 | #./main 100 5 10 20 15 | -------------------------------------------------------------------------------- /10. Network sockets/README.md: -------------------------------------------------------------------------------- 1 | Celem zadania jest napisanie prostego systemu pozwalającego na wykonywanie zadań na klastrze obliczeniowym. 2 | 3 | System oparty jest o centralny serwer oraz połączonych do niego klientów. 4 | Serwer nasłuchuje jednocześnie na gnieździe sieciowym i gnieździe lokalnym. Z jego poziomu zlecane są zadania. 5 | Klienci po uruchomieniu przesyłają do serwera swoją nazwę, a ten sprawdza czy klient o takiej nazwie już istnieje - jeśli tak, to odsyła klientowi komunikat że nazwa jest już w użyciu; jeśli nie, to zapamiętuje klienta. 6 | 7 | Obsługiwane obliczenia polegają na zliczeniu ilości wszystkich słów, oraz ilości poszczególnych słów w zadanym tekście 8 | Zlecenia obliczeń są wpisane bezpośrednio w konsoli serwera poprzez podanie ściezki do pliku z tekstem do przetworzenia. 9 | Serwer tworzy strukturę opisującą zlecenie (text), a następnie przesyła ją do klienta, który nie wykonuje w danym momencie obliczeń. 10 | Jeżeli wszyscy klienci wykonują w danym momencie obliczenia, serwer wysyła zlecenie do dowolnego klienta. 11 | Klient po odebraniu zlecenia oblicza wynik i odsyła go do serwera, który wyświetla wynik na standardowym wyjściu. 12 | Klient przy wyłączeniu Ctrl+C powinien wyrejestrować się z serwera. 13 | 14 | W procesie serwera obsługa wprowadzania zleceń z terminala i obsługa sieci powinny być zrealizowane w dwóch osobnych wątkach. 15 | Wątek obsługujący sieć powinien obsługiwać gniazdo sieciowe i gniazdo lokalne jednocześnie, wykorzystując w tym celu funkcje do monitorowania wielu deskryptorów (epollpollselect). 16 | Dodatkowo, osobny wątek powinien cyklicznie pingować zarejestrowanych klientów, aby zweryfikować że wciąż odpowiadają na żądania i jeśli nie - usuwać ich z listy klientów. 17 | Można przyjąć, że ilość klientów zarejestrowanych na serwerze jest ograniczona do maksymalnie kilkunastu. 18 | Należy zapewnić możliwość ustalenia dla którego zlecenia wyświetlony został wynik (np. umieścić w serwerze globalny licznik, wyświetlany i inkrementowany po dodaniu każdego nowego zlecenia i umieszczany jako dodatkowy identyfikator w komunikatach wysyłanych do klientów i odpowiedziach od nich przychodzących) i który klient go obliczył. 19 | 20 | Serwer przyjmuje jako swoje argumenty 21 | 22 | - numer portu TCPUDP (zależnie od zadania) 23 | - ścieżkę gniazda UNIX 24 | 25 | Klient przyjmuje jako swoje argumenty 26 | 27 | - swoją nazwę (string o z góry ograniczonej długości) 28 | - sposób połączenia z serwerem (sieć lub komunikacja lokalna przez gniazda UNIX) 29 | - adres serwera (adres IPv4 i numer portu lub ścieżkę do gniazda UNIX serwera) 30 | 31 | ## Zadanie 1 32 | Komunikacja klientów i serwera odbywa się z użyciem protokołu strumieniowego. 33 | 34 | ## Zadanie 2 35 | Komunikacja klientów i serwera odbywa się z użyciem protokołu datagramowego. 36 | -------------------------------------------------------------------------------- /10. Network sockets/zad1/client.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | #define BUFFER_SIZE 1024 4 | 5 | char * client_name; 6 | short socket_mode; 7 | int server_socket_fd = -1; 8 | 9 | char * server_IP_address; 10 | in_port_t server_inet_port; 11 | char * server_unix_socket_path_name; 12 | 13 | void sig_int(int signum) { 14 | printf("got SIGINT - closing the client\n"); 15 | if(server_socket_fd > 0) 16 | send_login_message(server_socket_fd, "logout"); 17 | exit(EXIT_SUCCESS); 18 | } 19 | 20 | void print_usage() { 21 | printf("example usage: ./client \n" 22 | "name: client's name (string)\n" 23 | "socket_mode: [ unix | inet ]\n" 24 | "server_address:\n" 25 | "\tif socket_mode == unix -> \n" 26 | "\tif socket_mode == inet -> \n" 27 | ); 28 | } 29 | 30 | void connect_to_server(){ 31 | if(socket_mode == MODE_UNIX){ 32 | // laczymy do serwera, UNIX socket 33 | struct sockaddr_un sa; 34 | strcpy(sa.sun_path, server_unix_socket_path_name); 35 | sa.sun_family = AF_UNIX; 36 | 37 | if((server_socket_fd = socket(AF_UNIX, SOCKET_PROTOCOL, 0)) == -1) 38 | error("socket"); 39 | 40 | if(connect(server_socket_fd, (struct sockaddr*) &sa, sizeof(sa)) == -1) 41 | error("connect"); 42 | 43 | printf("sent request to server's UNIX socket\n"); 44 | } 45 | else{ 46 | // lacyzmz do serwera, INET socket 47 | struct sockaddr_in sa_inet; 48 | sa_inet.sin_family = AF_INET; 49 | sa_inet.sin_addr.s_addr = inet_addr(server_IP_address); 50 | sa_inet.sin_port = htons(server_inet_port); 51 | 52 | if((server_socket_fd = socket(AF_INET, SOCKET_PROTOCOL, 0)) == -1) 53 | error("socket"); 54 | 55 | if(connect(server_socket_fd, (struct sockaddr*) &sa_inet, sizeof(sa_inet)) == -1) 56 | error("connect"); 57 | 58 | printf("sent request to server's INET socket\n"); 59 | } 60 | } 61 | 62 | // odczytaj wejscie socketa i przetworz wiadomosc do odczytu 63 | void process_message() { 64 | char buffer[RAW_MESSAGE_SIZE]; 65 | receive_message(server_socket_fd, buffer); 66 | 67 | int msg_type = check_message_type(buffer); 68 | if(msg_type == MSG_PING) { 69 | struct ping_message pm = get_ping_message(buffer); 70 | printf("got ping request, id: %d\n", pm.ping_id); 71 | send_ping_message(server_socket_fd, pm.ping_id); 72 | } 73 | else if(msg_type == MSG_TASK) { 74 | struct task_message tm = get_task_message(buffer); 75 | printf("got task, id: %d, type: %d, path: %s\n", tm.task_id, tm.task_type, tm.path_or_content); 76 | 77 | char * content; 78 | 79 | if (tm.task_type == ALL_WORDS){ // 1 80 | // all words 81 | FILE * fptr = fopen(tm.path_or_content, "r"); 82 | char delims[] = " ,.?!\t\n"; 83 | char str[BUFFER_SIZE]; 84 | 85 | int count = 0; 86 | 87 | while ((fgets(str, BUFFER_SIZE, fptr)) != NULL){ 88 | char * buff = strtok(str, delims); 89 | while (buff != NULL){ 90 | count++; 91 | buff = strtok(NULL, delims); 92 | } 93 | } 94 | 95 | fclose(fptr); 96 | char str2[3]; 97 | sprintf(str2, "%d", count); 98 | content = malloc(strlen(str2)+1); 99 | for (int i = 0; i < strlen(str2); ++i){ 100 | content[i] = str2[i]; 101 | } 102 | } 103 | else if (tm.task_type == ONE_WORD){ // 2 104 | // one word 105 | FILE * fptr = fopen(tm.path_or_content, "r"); 106 | const char * word = "nas"; 107 | char str[BUFFER_SIZE]; 108 | char * pos; 109 | 110 | int index, count; 111 | 112 | count = 0; 113 | 114 | // Read line from file till end of file. 115 | while ((fgets(str, BUFFER_SIZE, fptr)) != NULL) 116 | { 117 | index = 0; 118 | 119 | // Find next occurrence of word in str 120 | while ((pos = strstr(str + index, word)) != NULL) 121 | { 122 | // Index of word in str is 123 | // Memory address of pos - memory 124 | // address of str. 125 | index = (pos - str) + 1; 126 | count++; 127 | } 128 | } 129 | fclose(fptr); 130 | char str2[5]; 131 | sprintf(str2, "%d", count); 132 | content = malloc(strlen(str2)); 133 | for (int i = 0; i < strlen(str2); ++i){ 134 | content[i] = str2[i]; 135 | } 136 | } 137 | else { 138 | content = "bad_task_type"; 139 | } 140 | 141 | send_task_message(server_socket_fd, tm.task_id, tm.task_type, content); 142 | free(content); 143 | } 144 | } 145 | 146 | int main(int argc, char **argv) { 147 | struct sigaction act_int; 148 | act_int.sa_handler = sig_int; 149 | sigemptyset(&act_int.sa_mask); 150 | act_int.sa_flags = 0; 151 | 152 | // Setting handler for SIGINT 153 | if ((sigaction(SIGINT, &act_int, NULL)) < 0) error("sigaction"); 154 | 155 | client_name = argv[1]; 156 | 157 | if(strcmp(argv[2], "unix") == 0) { 158 | if(argc != 4) { 159 | error("bad args number"); 160 | print_usage(); 161 | } 162 | socket_mode = MODE_UNIX; 163 | server_unix_socket_path_name = argv[3]; 164 | } 165 | else if(strcmp(argv[2], "inet") == 0) { 166 | if(argc != 5) { 167 | error("bad args number"); 168 | print_usage(); 169 | } 170 | socket_mode = MODE_INET; 171 | server_IP_address = argv[3]; 172 | server_inet_port = (in_port_t) atoi(argv[4]); 173 | } 174 | else { 175 | print_usage(); 176 | error("bad args number"); 177 | } 178 | 179 | connect_to_server(); 180 | 181 | char message_buffer[RAW_MESSAGE_SIZE]; 182 | receive_message(server_socket_fd, message_buffer); 183 | struct login_message lm = get_login_message(message_buffer); 184 | 185 | if(strcmp(lm.string, "pending") == 0) 186 | printf("connection established\n"); 187 | else { 188 | error("server rejected connection\n"); 189 | } 190 | 191 | send_login_message(server_socket_fd, client_name); 192 | 193 | receive_message(server_socket_fd, message_buffer); 194 | lm = get_login_message(message_buffer); 195 | 196 | if(strcmp(lm.string, "accepted") == 0) 197 | printf("logged in successfully\n"); 198 | else 199 | error("login rejected"); 200 | 201 | while(1) { 202 | process_message(); 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /10. Network sockets/zad1/lib.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | void error(char * msg){ 4 | perror(msg); 5 | exit(EXIT_FAILURE); 6 | } 7 | 8 | int send_message(int socket_fd, const char message[RAW_MESSAGE_SIZE]) { 9 | return write(socket_fd, message, RAW_MESSAGE_SIZE); 10 | } 11 | 12 | int receive_message(int socket_fd, char message[RAW_MESSAGE_SIZE]) { 13 | int result = read(socket_fd, message, RAW_MESSAGE_SIZE); 14 | return result; 15 | } 16 | 17 | int check_message_type(const char message[RAW_MESSAGE_SIZE]) { 18 | int type; 19 | sscanf(message, "%d", &type); 20 | return type; 21 | } 22 | 23 | int send_login_message(int socket_fd, const char * string) { 24 | char buffer[RAW_MESSAGE_SIZE]; 25 | sprintf(buffer, "%d %s", MSG_LOGIN, string); 26 | return send_message(socket_fd, buffer); 27 | } 28 | 29 | int send_task_message(int socket_fd, int task_id, int task_type, char * path_or_content) { 30 | char buffer[RAW_MESSAGE_SIZE]; 31 | sprintf(buffer, "%d %d %d %s", MSG_TASK, task_id, task_type, path_or_content); 32 | return send_message(socket_fd, buffer); 33 | } 34 | 35 | int send_ping_message(int socket_fd, int ping_id) { 36 | char buffer[RAW_MESSAGE_SIZE]; 37 | sprintf(buffer, "%d %d", MSG_PING, ping_id); 38 | return send_message(socket_fd, buffer); 39 | } 40 | 41 | struct login_message get_login_message(const char raw_message[RAW_MESSAGE_SIZE]) { 42 | int tmp; 43 | struct login_message lm; 44 | sscanf(raw_message, "%d %s", &tmp, lm.string); 45 | return lm; 46 | } 47 | 48 | struct task_message get_task_message(const char raw_message[RAW_MESSAGE_SIZE]) { 49 | int tmp; 50 | struct task_message tm; 51 | sscanf(raw_message, "%d %d %d %s", &tmp, &tm.task_id, &tm.task_type, tm.path_or_content); 52 | return tm; 53 | } 54 | 55 | struct ping_message get_ping_message(const char raw_message[RAW_MESSAGE_SIZE]) { 56 | int tmp; 57 | struct ping_message pm; 58 | sscanf(raw_message, "%d %d", &tmp, &pm.ping_id); 59 | return pm; 60 | } 61 | -------------------------------------------------------------------------------- /10. Network sockets/zad1/lib.h: -------------------------------------------------------------------------------- 1 | #ifndef LIB_H 2 | #define LIB_G 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | // general settings: 23 | #define SOCKET_PROTOCOL SOCK_STREAM 24 | 25 | // server settings: 26 | #define SERVER_NAME "cluster_server" 27 | #define SERVER_CLIENTS_LIMIT 16 28 | #define PING_INTERVAL 5 29 | #define PING_TIMEOUT 5 30 | 31 | // client settings: 32 | #define CLIENT_MAX_NAME_LENGTH 32 33 | 34 | // socket modes: 35 | #define MODE_INET 1 36 | #define MODE_UNIX 2 37 | 38 | // task types: 39 | #define ALL_WORDS 1 40 | #define ONE_WORD 2 41 | 42 | // client representation 43 | struct client { 44 | char name[CLIENT_MAX_NAME_LENGTH + 1]; 45 | int socket_fd; 46 | int client_id; 47 | int registered; 48 | int active; 49 | }; 50 | 51 | // message settings: 52 | #define RAW_MESSAGE_SIZE 64 53 | #define CONTENT_SIZE 1024 54 | 55 | // message types: 56 | #define MSG_LOGIN 1 // format: "%d %s" -> msg_type, message 57 | #define MSG_TASK 2 // format: "%d %s" -> msg_type, task_id, path 58 | #define MSG_PING 3 // format: "%d %d" -> msg_type 59 | 60 | struct login_message { 61 | char string[CLIENT_MAX_NAME_LENGTH]; 62 | }; 63 | 64 | struct task_message { 65 | int task_id; 66 | int task_type; 67 | char path_or_content[CONTENT_SIZE]; 68 | }; 69 | 70 | struct ping_message { 71 | int ping_id; 72 | }; 73 | 74 | void error(char * msg); 75 | // lib API: 76 | int send_message(int socket_fd, const char message[RAW_MESSAGE_SIZE]); 77 | int receive_message(int socket_fd, char message[RAW_MESSAGE_SIZE]); 78 | int check_message_type(const char message[RAW_MESSAGE_SIZE]); 79 | 80 | int send_login_message(int socket_fd, const char * string); 81 | int send_task_message(int socket_fd, int task_id, int task_type, char * path_or_content); 82 | int send_ping_message(int socket_fd, int ping_id); 83 | 84 | struct login_message get_login_message(const char raw_message[RAW_MESSAGE_SIZE]); 85 | struct task_message get_task_message(const char raw_message[RAW_MESSAGE_SIZE]); 86 | struct ping_message get_ping_message(const char raw_message[RAW_MESSAGE_SIZE]); 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /10. Network sockets/zad1/makefile: -------------------------------------------------------------------------------- 1 | CC = gcc -Wall 2 | 3 | clean: 4 | rm -f server 5 | rm -f client 6 | rm -f *.o 7 | rm -f *.so 8 | rm -f *.a 9 | 10 | compile: 11 | make clean 12 | $(CC) server.c lib.c -o server -lrt -lpthread 13 | $(CC) client.c lib.c -o client -lrt -lpthread 14 | 15 | runserver: 16 | ./server 2137 "HOME" 17 | 18 | runclient: 19 | ./client client1 unix "HOME" 20 | #./client client2 inet 127.0.0.1 2137 21 | -------------------------------------------------------------------------------- /10. Network sockets/zad1/text1.txt: -------------------------------------------------------------------------------- 1 | There is a tide in the affairs of men, 2 | Which taken at the flood, 3 | leads on to fortune. Omitted, 4 | all the voyage of their life is bound in shallows and in miseries. 5 | On such a full sea are we now afloat. 6 | And we must take the current when it serves, 7 | or lose our ventures. 8 | -------------------------------------------------------------------------------- /10. Network sockets/zad1/text2.txt: -------------------------------------------------------------------------------- 1 | Nowe barwy starych sztandarow, 2 | Nowe klamstwa czerwonych swin, 3 | Cel ten sam - wykrwawic narod, 4 | Do ostatniej kropli krwi, 5 | Kamery patrza im na twarz, 6 | Lecz nikt juz nie patrzy im na rece, 7 | Minionej epoki wierna straz, 8 | Banda skur###ynow i nic wiecej, 9 | Synowie mordercow naszych ojcow, 10 | Ktorych brakuje dzisiaj nam, 11 | Obiecuja dobrobyt wolnosc rownosc, 12 | Byle tylko w urnie glos im dac, 13 | Wielu uwierzylo w piekne slowa, 14 | Zdradzilo czynem narod swoj, 15 | Lecz nie my szalency patrioci, 16 | Wierni idealom, az po grob. 17 | 18 | Dzis tylko idea pozostala w nas, 19 | Lecz przyjdzie kiedys taki czas, 20 | Ze na drzewach zamiast lisci, 21 | Beda wisiec komunisci, 22 | Tylko wiara pozostala w nas, 23 | Ze przyjdzie kiedys taki czas, 24 | Ze na drzewach zamiast lisci, 25 | Beda wisiec komunisci! 26 | -------------------------------------------------------------------------------- /10. Network sockets/zad1/text3.txt: -------------------------------------------------------------------------------- 1 | Nie rzucim ziemi skad nasz rod! 2 | Nie damy pogrzesc mowy. 3 | Polski my narod, polski lud, 4 | Krolewski szczep Piastowy. 5 | Nie damy, by nas zgnebil wrog! 6 | Tak nam dopomoz Bog! 7 | Tak nam dopomoz Bog! 8 | 9 | Do krwi ostatniej kropli z zyl 10 | Bronic bedziemy ducha, 11 | Az sie rozpadnie w proch i w pyl 12 | Krzyzacka zawierucha. 13 | Twierdza nam bedzie kazdy prog! 14 | Tak nam dopomoz Bog! 15 | Tak nam dopomoz Bog! 16 | 17 | Nie bedzie Niemiec plul nam w twarz 18 | Ni dzieci nam germanil, 19 | Orezny stanie hufiec nasz, 20 | Duch bedzie nam hetmanil. 21 | Pojdziemy, gdy zabrzmi zloty rog! 22 | Tak nam dopomoz Bog! 23 | Tak nam dopomoz Bog! 24 | 25 | Nie damy miana Polski zgniesc 26 | Nie pojdziem zywo w trumne 27 | Na Polski imie, na jej czesc 28 | Podnosi czola dumne. 29 | Odzyska ziemi dziadow wnuk! 30 | Tak nam dopomoz Bog! 31 | Tak nam dopomoz Bog! 32 | 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Operating-Systems 2 | - projects completed during the Operating Systems classes 3 | --------------------------------------------------------------------------------