├── .clang-format ├── .vscode ├── settings.json └── c_cpp_properties.json ├── readme.md ├── cw03 ├── zad1 │ ├── makefile │ └── main.c ├── zad2 │ ├── makefile │ ├── main.c │ ├── worker.c │ ├── util.c │ └── matrix.c ├── zad3 │ ├── makefile │ ├── worker.c │ ├── main.c │ ├── util.c │ └── matrix.c └── readme.md ├── cw04 ├── zad1 │ ├── makefile │ └── main.c ├── zad3 │ ├── makefile │ └── main.c ├── zad2 │ ├── makefile │ ├── ipc.h │ ├── exec.c │ ├── strings.h │ ├── main.c │ └── signal_test.c ├── zad4b │ ├── catcher.c │ ├── makefile │ ├── sender.c │ └── common.c ├── zad4a │ ├── makefile │ ├── catcher.c │ ├── sender.c │ └── common.c └── readme.md ├── cw09 ├── zad1 │ ├── makefile │ └── main.c └── readme.md ├── cw05 ├── zad2 │ ├── makefile │ └── main.c ├── zad1 │ ├── inc.c │ ├── makefile │ └── main.c ├── zad3 │ ├── common.h │ ├── customer.c │ ├── producer.c │ ├── makefile │ └── tester.c └── readme.md ├── cw10 ├── zad1 │ ├── makefile │ ├── message.h │ ├── common.h │ └── client.c ├── zad2 │ ├── makefile │ ├── message.h │ ├── common.h │ ├── client.c │ └── server.c └── readme.md ├── cw02 ├── zad2 │ ├── makefile │ └── main.c ├── zad1 │ ├── main.c │ ├── makefile │ ├── util.c │ ├── sys.c │ └── lib.c └── readme.md ├── cw06 ├── zad1 │ ├── makefile │ ├── client │ │ ├── logic.c │ │ ├── events.c │ │ └── main.c │ ├── server │ │ ├── main.c │ │ ├── events.c │ │ └── logic.c │ └── common │ │ ├── common.h │ │ └── message.h ├── zad2 │ ├── makefile │ ├── client │ │ ├── logic.c │ │ ├── events.c │ │ └── main.c │ ├── server │ │ ├── main.c │ │ ├── events.c │ │ └── logic.c │ └── common │ │ ├── common.h │ │ └── message.h └── readme.md ├── cw01 ├── zad2 │ ├── makefile │ ├── lib.h │ ├── main.c │ └── lib.c ├── zad1 │ ├── makefile │ ├── lib.h │ └── lib.c ├── zad3a │ ├── makefile │ ├── lib.h │ ├── main.c │ └── lib.c ├── zad3b │ ├── makefile │ ├── lib.h │ ├── main.c │ └── lib.c └── readme.md ├── cw07 ├── zad1 │ ├── makefile │ ├── worker1.c │ ├── worker3.c │ ├── worker2.c │ ├── manager.c │ ├── common.h │ └── worker.h ├── zad2 │ ├── makefile │ ├── worker1.c │ ├── worker3.c │ ├── worker2.c │ ├── common.h │ ├── manager.c │ └── worker.h └── readme.md ├── LICENSE ├── cw08 ├── zad1 │ ├── makefile │ ├── image.c │ ├── macros.h │ └── main.c └── readme.md └── .gitignore /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | IndentWidth: 2 -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.tabSize": 2, 3 | "editor.detectIndentation": false 4 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # sysopy 🙊 2 | Jeśli 👎 sysopy to jesteś w 👍 miejscu! 3 | Jeśli pomogłem zostaw ⭐❤ 4 | -------------------------------------------------------------------------------- /cw03/zad1/makefile: -------------------------------------------------------------------------------- 1 | cc = gcc -Wall -g 2 | 3 | main: 4 | $(cc) main.c -o main.out 5 | 6 | clean: 7 | rm main.out -------------------------------------------------------------------------------- /cw04/zad1/makefile: -------------------------------------------------------------------------------- 1 | cc = gcc -Wall -ggdb 2 | 3 | all: 4 | $(cc) main.c -o main.out 5 | 6 | clean: 7 | rm -Rf *.out 8 | -------------------------------------------------------------------------------- /cw04/zad3/makefile: -------------------------------------------------------------------------------- 1 | cc = gcc -Wall -ggdb 2 | 3 | all: main 4 | 5 | main: 6 | $(cc) main.c -o main.out 7 | 8 | clean: 9 | rm -Rf *.out 10 | 11 | -------------------------------------------------------------------------------- /cw09/zad1/makefile: -------------------------------------------------------------------------------- 1 | cc = gcc -Wall -ggdb 2 | lib = -lpthread 3 | 4 | all: main 5 | 6 | main: 7 | $(cc) main.c -o main.out $(lib) 8 | 9 | clean: 10 | rm -f *.out -------------------------------------------------------------------------------- /cw05/zad2/makefile: -------------------------------------------------------------------------------- 1 | cc = gcc -Wall -ggdb 2 | 3 | main: main.c 4 | $(cc) main.c -o main.out 5 | 6 | test: main 7 | @./main.out makefile 8 | 9 | clean: 10 | rm -f main.out 11 | -------------------------------------------------------------------------------- /cw10/zad1/makefile: -------------------------------------------------------------------------------- 1 | cc = gcc -Wall -ggdb 2 | 3 | all: client server 4 | 5 | client: 6 | $(cc) client.c -o client.out -lpthread 7 | 8 | server: 9 | $(cc) server.c -o server.out -lpthread 10 | 11 | clean: 12 | rm -f *.out -------------------------------------------------------------------------------- /cw10/zad2/makefile: -------------------------------------------------------------------------------- 1 | cc = gcc -Wall -ggdb 2 | 3 | all: client server 4 | 5 | client: 6 | $(cc) client.c -o client.out -lpthread 7 | 8 | server: 9 | $(cc) server.c -o server.out -lpthread 10 | 11 | clean: 12 | rm -f *.out -------------------------------------------------------------------------------- /cw02/zad2/makefile: -------------------------------------------------------------------------------- 1 | cc = gcc -Wall -ggdb 2 | 3 | all: main 4 | 5 | main: 6 | $(cc) -o find main.c 7 | 8 | main_nftw: 9 | $(cc) -o find main.c -D _XOPEN_SOURCE=500 -D use_nftw 10 | 11 | clean: 12 | rm -Rf find *.txt *.out 13 | -------------------------------------------------------------------------------- /cw05/zad1/inc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char** argv) { 5 | int value, inc = argc == 2 ? atoi(argv[1]) : 1; 6 | 7 | while(scanf("%d", &value) > 0) 8 | printf("%d\n", value + inc); 9 | } 10 | -------------------------------------------------------------------------------- /cw06/zad1/makefile: -------------------------------------------------------------------------------- 1 | cc = gcc -Wall -ggdb 2 | 3 | all: build_client build_server 4 | 5 | build_server: server/* 6 | $(cc) server/main.c -o server.out 7 | 8 | build_client: client/* 9 | $(cc) client/main.c -o client.out 10 | 11 | clean: 12 | rm -f *.out 13 | -------------------------------------------------------------------------------- /cw06/zad2/makefile: -------------------------------------------------------------------------------- 1 | cc = gcc -Wall -ggdb 2 | 3 | all: build_client build_server 4 | 5 | build_server: server/* 6 | $(cc) server/main.c -o server.out -lrt 7 | 8 | build_client: client/* 9 | $(cc) client/main.c -o client.out -lrt 10 | 11 | clean: 12 | rm -f *.out 13 | -------------------------------------------------------------------------------- /cw05/zad3/common.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_H 2 | #define COMMON_H 3 | 4 | #include 5 | #include 6 | #define panic(str, args...) {\ 7 | fprintf(stderr, "%s:%i ", __func__, __LINE__);\ 8 | fprintf(stderr, str, args);\ 9 | fprintf(stderr, ".\n");\ 10 | exit(1);\ 11 | } 12 | 13 | #endif -------------------------------------------------------------------------------- /cw04/zad2/makefile: -------------------------------------------------------------------------------- 1 | cc = gcc -Wall -ggdb 2 | 3 | all: test_signal main 4 | 5 | main: main.c 6 | $(cc) main.c -o main.out 7 | 8 | test_signal: signal_test.c 9 | $(cc) signal_test.c -o sig_test.out 10 | $(cc) exec.c -o exec.out 11 | 12 | test: all 13 | ./main.out 14 | 15 | clean: 16 | rm -Rf *.out 17 | -------------------------------------------------------------------------------- /cw04/zad4b/catcher.c: -------------------------------------------------------------------------------- 1 | #include "common.c" 2 | 3 | int main(int argc, char** argv) { 4 | on (SIGUSR1) do (count) 5 | on (SIGUSR2) do (finish) 6 | 7 | receive then 8 | printf("[catcher] %d\n", received) 9 | and post 10 | repeat(received) send(SIGUSR1) 11 | then send(SIGUSR2) 12 | } 13 | 14 | -------------------------------------------------------------------------------- /cw06/zad1/client/logic.c: -------------------------------------------------------------------------------- 1 | #ifndef logic_c 2 | #define logic_c 3 | 4 | #define CLIENT 5 | #include "../common/common.h" 6 | #include "../common/message.h" 7 | 8 | qid_t client_qid, server_qid; 9 | qid_t peer_qid, peer_id; 10 | id_t client_id = 0; 11 | 12 | void disconnect() { peer_qid = peer_id = 0; } 13 | 14 | #endif -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [{ 3 | "name": "WSL", 4 | "intelliSenseMode": "gcc-x64", 5 | "compilerPath": "/usr/bin/gcc", 6 | "includePath": [ "${workspaceFolder}/**" ], 7 | "defines": [ 8 | "__USE_POSIX", 9 | "_GNU_SOURCE" 10 | ] 11 | }], 12 | "version": 4 13 | } -------------------------------------------------------------------------------- /cw04/zad4b/makefile: -------------------------------------------------------------------------------- 1 | cc = gcc -Wall -ggdb 2 | 3 | all: sender catcher 4 | 5 | sender: sender.c 6 | $(cc) sender.c -o sender.out 7 | 8 | catcher: catcher.c 9 | $(cc) catcher.c -o catcher.out 10 | 11 | n = 1000000 12 | test: all 13 | @echo "expected [$n]" 14 | @./catcher.out - & 15 | @./sender.out `pidof catcher.out` $n 16 | 17 | clean: 18 | rm -Rf *.out 19 | -------------------------------------------------------------------------------- /cw01/zad2/makefile: -------------------------------------------------------------------------------- 1 | cc = gcc -Wall -std=c11 -g 2 | 3 | all: main 4 | 5 | dirs: 6 | mkdir -p build 7 | 8 | static_lib: dirs lib.c 9 | $(cc) -c lib.c -o build/lib.o 10 | ar rcs build/lib.a build/lib.o 11 | 12 | main: main.c static_lib 13 | $(cc) -c main.c -o build/main.o 14 | $(cc) build/main.o build/lib.a -o main.out 15 | 16 | clean: 17 | rm -Rf build *.out *.so *.o *.a -------------------------------------------------------------------------------- /cw07/zad1/makefile: -------------------------------------------------------------------------------- 1 | cc = gcc -Wall -ggdb 2 | 3 | all: manager worker1 worker2 worker3 4 | 5 | manager: manager.c 6 | $(cc) manager.c -o manager.out 7 | 8 | worker1: worker1.c 9 | $(cc) worker1.c -o worker1.out 10 | 11 | worker2: worker2.c 12 | $(cc) worker2.c -o worker2.out 13 | 14 | worker3: worker3.c 15 | $(cc) worker3.c -o worker3.out 16 | 17 | clean: 18 | rm -f *.out -------------------------------------------------------------------------------- /cw01/zad1/makefile: -------------------------------------------------------------------------------- 1 | cc = gcc -Wall -std=c11 -g 2 | 3 | all: static_lib shared_lib 4 | 5 | dirs: 6 | mkdir -p build 7 | 8 | static_lib: dirs lib.c 9 | $(cc) -c lib.c -o build/lib.o 10 | ar rcs lib.a build/lib.o 11 | 12 | shared_lib: dirs lib.c 13 | $(cc) -c -fPIC lib.c -o build/lib.o 14 | $(cc) -shared -fPIC -o libdiff.so build/lib.o 15 | 16 | clean: 17 | rm -Rf build *.out *.so *.o *.a 18 | -------------------------------------------------------------------------------- /cw07/zad2/makefile: -------------------------------------------------------------------------------- 1 | cc = gcc -Wall -ggdb -lrt -lpthread 2 | 3 | all: manager worker1 worker2 worker3 4 | 5 | manager: manager.c 6 | $(cc) manager.c -o manager.out 7 | 8 | worker1: worker1.c 9 | $(cc) worker1.c -o worker1.out 10 | 11 | worker2: worker2.c 12 | $(cc) worker2.c -o worker2.out 13 | 14 | worker3: worker3.c 15 | $(cc) worker3.c -o worker3.out 16 | 17 | clean: 18 | rm -f *.out 19 | -------------------------------------------------------------------------------- /cw03/zad2/makefile: -------------------------------------------------------------------------------- 1 | cc = gcc -Wall -ggdb 2 | 3 | all: main util dirs 4 | 5 | dirs: 6 | mkdir -p data 7 | 8 | main: main.c 9 | $(cc) -o main.out main.c 10 | 11 | util: 12 | $(cc) -o util.out util.c 13 | 14 | clean: 15 | rm -Rf *.out *.txt data ipc 16 | 17 | test: all 18 | ./util.out -min 10 -max 100 -c 100 -g list.txt 19 | ./main.out list.txt 10 10 flock | less 20 | ./util.out -t list.txt | less -------------------------------------------------------------------------------- /cw03/zad3/makefile: -------------------------------------------------------------------------------- 1 | cc = gcc -Wall -ggdb 2 | 3 | all: main util dirs 4 | 5 | dirs: 6 | mkdir -p data 7 | 8 | main: main.c 9 | $(cc) -o main.out main.c 10 | 11 | util: 12 | $(cc) -o util.out util.c 13 | 14 | clean: 15 | rm -Rf *.out *.txt data ipc 16 | 17 | test: all 18 | ./util.out -min 10 -max 100 -c 100 -g list.txt 19 | ./main.out list.txt 10 100 100 flock | less 20 | ./util.out -t list.txt | less -------------------------------------------------------------------------------- /cw05/zad1/makefile: -------------------------------------------------------------------------------- 1 | cc = gcc -Wall -ggdb 2 | 3 | all: main inc 4 | 5 | main: main.c 6 | $(cc) main.c -o main.out 7 | 8 | inc: inc.c 9 | $(cc) inc.c -o inc.out 10 | 11 | test: SHELL:=/bin/bash 12 | test: all 13 | @./main.out <(\ 14 | echo "ls / | wc";\ 15 | echo "./asdfasjlkfadsl";\ 16 | echo "ls -al | sort | head -3";\ 17 | echo "echo 9 | ./inc.out 10 | ./inc.out 80") 18 | 19 | clean: 20 | rm -Rf *.out 21 | -------------------------------------------------------------------------------- /cw06/zad2/client/logic.c: -------------------------------------------------------------------------------- 1 | #ifndef logic_c 2 | #define logic_c 3 | 4 | #define CLIENT 5 | #include "../common/common.h" 6 | #include "../common/message.h" 7 | 8 | mqd_t client_qid, server_qid; 9 | mqd_t peer_qid, peer_id; 10 | pid_t peer_pid; 11 | id_t client_id = 0; 12 | 13 | void disconnect() { 14 | if (peer_pid == 0) return; 15 | mq_close(peer_qid); 16 | peer_pid = peer_qid = peer_id = 0; 17 | } 18 | 19 | #endif -------------------------------------------------------------------------------- /cw07/zad1/worker1.c: -------------------------------------------------------------------------------- 1 | #include "worker.h" 2 | 3 | worker { 4 | loop using(semid) { 5 | if (shared->unused == 0) continue; 6 | package *package = find(shared, status == unused); 7 | update(shared, package, unused, recived); 8 | package->size = rand() % 10; 9 | log("Dodałem liczbę: %d. Liczba zamówień do przygotowania: %d, Liczba " 10 | "zamówień do wyslania: %d", 11 | package->size, shared->recived, shared->processed); 12 | } 13 | } -------------------------------------------------------------------------------- /cw07/zad2/worker1.c: -------------------------------------------------------------------------------- 1 | #include "worker.h" 2 | 3 | worker { 4 | loop using(semid) { 5 | if (shared->unused == 0) continue; 6 | package *package = find(shared, status == unused); 7 | update(shared, package, unused, recived); 8 | package->size = rand() % 10; 9 | log("Dodałem liczbę: %d. Liczba zamówień do przygotowania: %d, Liczba " 10 | "zamówień do wyslania: %d", 11 | package->size, shared->recived, shared->processed); 12 | } 13 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Maciej Kozieja 2 | 3 | This code is provided for educational purposes and intended to illustrate an exemplary solution to a given problem. 4 | Within one year of the author's code being published all uses must be consulted with the author. 5 | After one year, all license terms expire and the code can be used without restrictions. 6 | 7 | The above copyright notice and this permission notice shall be included in all 8 | copies or substantial portions of the Software. -------------------------------------------------------------------------------- /cw07/zad1/worker3.c: -------------------------------------------------------------------------------- 1 | #include "worker.h" 2 | 3 | worker { 4 | loop using(semid) { 5 | if (shared->processed == 0) continue; 6 | package *package = find(shared, status == processed); 7 | update(shared, package, processed, unused); 8 | package->size *= 3; 9 | log("Wysłąłem zamówienie o wielkości: %d. Liczba zamówień do " 10 | "przygotowania: %d, Liczba zamówień do wyslania: %d", 11 | package->size, shared->recived, shared->processed); 12 | } 13 | } -------------------------------------------------------------------------------- /cw07/zad2/worker3.c: -------------------------------------------------------------------------------- 1 | #include "worker.h" 2 | 3 | worker { 4 | loop using(semid) { 5 | if (shared->processed == 0) continue; 6 | package *package = find(shared, status == processed); 7 | update(shared, package, processed, unused); 8 | package->size *= 3; 9 | log("Wysłąłem zamówienie o wielkości: %d. Liczba zamówień do " 10 | "przygotowania: %d, Liczba zamówień do wyslania: %d", 11 | package->size, shared->recived, shared->processed); 12 | } 13 | } -------------------------------------------------------------------------------- /cw07/zad1/worker2.c: -------------------------------------------------------------------------------- 1 | #include "worker.h" 2 | 3 | worker { 4 | loop using(semid) { 5 | if (shared->recived == 0) continue; 6 | package *package = find(shared, status == recived); 7 | update(shared, package, recived, processed); 8 | package->size *= 2; 9 | log("Przygotowałem zamówienie o wielkości: %d. Liczba zamówień do " 10 | "przygotowania: %d, Liczba zamówień do wyslania: %d", 11 | package->size, shared->recived, shared->processed); 12 | } 13 | } -------------------------------------------------------------------------------- /cw07/zad2/worker2.c: -------------------------------------------------------------------------------- 1 | #include "worker.h" 2 | 3 | worker { 4 | loop using(semid) { 5 | if (shared->recived == 0) continue; 6 | package *package = find(shared, status == recived); 7 | update(shared, package, recived, processed); 8 | package->size *= 2; 9 | log("Przygotowałem zamówienie o wielkości: %d. Liczba zamówień do " 10 | "przygotowania: %d, Liczba zamówień do wyslania: %d", 11 | package->size, shared->recived, shared->processed); 12 | } 13 | } -------------------------------------------------------------------------------- /cw10/zad1/message.h: -------------------------------------------------------------------------------- 1 | struct game_state { char move; char board[9]; }; 2 | 3 | typedef struct message { 4 | enum message_type { 5 | msg_disconnect, 6 | msg_play, msg_move, 7 | msg_state, msg_win, 8 | msg_ping, msg_username_taken, 9 | msg_server_full, msg_wait 10 | } type; 11 | union message_payload { 12 | struct { char nickname[16]; char symbol; } play; 13 | int move; 14 | struct game_state state; 15 | char win; 16 | } payload; 17 | } message; 18 | -------------------------------------------------------------------------------- /cw04/zad4b/sender.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "common.c" 7 | 8 | int main(int argc, char** argv) { 9 | pid_t pid = atoi(argv[1]); 10 | int n = atoi(argv[2]); 11 | 12 | post to (pid) 13 | repeat(n) send(SIGUSR1); 14 | then send(SIGUSR2); 15 | 16 | listen 17 | on (SIGUSR1) do (count) 18 | on (SIGUSR2) do (finish) 19 | 20 | then receive and printf("[sender] %d\n", received); 21 | } 22 | -------------------------------------------------------------------------------- /cw10/zad2/message.h: -------------------------------------------------------------------------------- 1 | struct game_state { char move; char board[9]; }; 2 | 3 | typedef struct message { 4 | enum message_type { 5 | msg_connect, msg_disconnect, 6 | msg_play, msg_move, 7 | msg_state, msg_win, 8 | msg_ping, msg_username_taken, 9 | msg_server_full, msg_wait 10 | } type; 11 | union message_payload { 12 | char nickname[16]; 13 | struct { char nickname[16]; char symbol; } play; 14 | int move; 15 | struct game_state state; 16 | char win; 17 | } payload; 18 | } message; 19 | -------------------------------------------------------------------------------- /cw04/zad2/ipc.h: -------------------------------------------------------------------------------- 1 | #ifndef IPC 2 | #define IPC 3 | 4 | #include 5 | #include 6 | 7 | #define PARENT_OK SIGUSR1 8 | #define CHILD_OK SIGUSR2 9 | 10 | #ifdef IPC_MAIN 11 | 12 | bool parent_ok, child_ok; 13 | #define CHILD_STATUS (child_ok ? "true" : "false") 14 | #define PARENT_STATUS (parent_ok ? "true" : "false") 15 | 16 | static void on_parent_ok(int _) { parent_ok = true; } 17 | static void on_child_ok(int _) { child_ok = true; } 18 | 19 | #define IPC_INIT \ 20 | signal(PARENT_OK, on_parent_ok);\ 21 | signal(CHILD_OK, on_child_ok); 22 | 23 | #endif 24 | 25 | #endif -------------------------------------------------------------------------------- /cw04/zad4a/makefile: -------------------------------------------------------------------------------- 1 | cc = gcc -Wall -ggdb 2 | 3 | all: sender catcher 4 | 5 | sender: sender.c 6 | $(cc) sender.c -o sender.out 7 | 8 | catcher: catcher.c 9 | $(cc) catcher.c -o catcher.out 10 | 11 | n = 10000 12 | test: all 13 | @echo "\n [kill]" 14 | @./catcher.out kill - & 15 | @./sender.out `pidof catcher.out` $n kill 16 | @echo "\n [sigqueue]" 17 | @./catcher.out sigqueue - & 18 | @./sender.out `pidof catcher.out` $n sigqueue 19 | @echo "\n [sigrt]" 20 | @./catcher.out sigrt - & 21 | @./sender.out `pidof catcher.out` $n sigrt 22 | 23 | 24 | clean: 25 | rm -Rf *.out 26 | -------------------------------------------------------------------------------- /cw04/zad4a/catcher.c: -------------------------------------------------------------------------------- 1 | #include "common.c" 2 | 3 | int main(int argc, char** argv) { 4 | bool use_sigqueue = is_arg(1, "sigqueue"); 5 | bool use_sigrt = is_arg(1, "sigrt"); 6 | bool use_kill = is_arg(1, "kill"); 7 | 8 | if (argc < 3) printf("%d\n", getpid()); 9 | 10 | init(use_sigrt); 11 | receive then printf("[catcher] received: %d\n", received); 12 | 13 | if (use_kill or use_sigrt) { 14 | repeat(received) kill(pid, SIG1); 15 | then kill(pid, SIG2); 16 | } 17 | else if (use_sigqueue) { 18 | repeat(received) sigqueue(pid, SIG1, val); 19 | val.sival_int = received; 20 | then sigqueue(pid, SIG2, val); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /cw05/zad2/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define BUFFER_SIZE 100 7 | char buffer[BUFFER_SIZE]; 8 | 9 | static char* __tmp; 10 | #define sprintfn(additional_size, pattern, args...) \ 11 | (sprintf(__tmp = calloc(strlen(pattern) + additional_size, sizeof(char)), pattern, args), __tmp) 12 | 13 | int main(int argc, char** argv) { 14 | if (argc != 2) return 1; 15 | int read; 16 | char* program = sprintfn(strlen(argv[1]), "sort %s", argv[1]); 17 | FILE* file = popen(program, "r"); 18 | while((read = fread(buffer, sizeof(char), BUFFER_SIZE, file))) 19 | write(STDOUT_FILENO, buffer, read); 20 | } 21 | -------------------------------------------------------------------------------- /cw01/zad3a/makefile: -------------------------------------------------------------------------------- 1 | cc = gcc -Wall -std=c11 -g 2 | 3 | all: main_static 4 | 5 | dirs: 6 | mkdir -p build 7 | 8 | static_lib: dirs lib.c 9 | $(cc) -c lib.c -o build/lib.o 10 | ar rcs build/lib.a build/lib.o 11 | 12 | shared_lib: dirs lib.c 13 | $(cc) -c -fPIC lib.c -o build/lib.o 14 | $(cc) -shared -fPIC -o libdiff.so build/lib.o 15 | 16 | main_static: main.c static_lib 17 | $(cc) -c main.c -o build/main.o 18 | $(cc) build/main.o build/lib.a -o main.out 19 | 20 | main_shared: main.c shared_lib 21 | $(cc) main.c -L. -o main.out -ldiff -Wl,-rpath=. 22 | 23 | main_dynamic: main.c shared_lib 24 | $(cc) main.c -o main.out -ldl -D dynamic 25 | 26 | clean: 27 | rm -Rf build *.out *.so *.o *.a -------------------------------------------------------------------------------- /cw04/zad2/exec.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "ipc.h" 6 | 7 | void failure_handler(int _) { _exit(0); } 8 | int main(int _, char** argv) { 9 | int sig = atoi(argv[2]); 10 | int ppid = atoi(argv[3]); 11 | if (strcmp(argv[1], "-i") == 0) { 12 | raise(sig); 13 | kill(ppid, CHILD_OK); 14 | } 15 | else if (strcmp(argv[1], "-m") == 0) { 16 | signal(sig, failure_handler); 17 | raise(sig); 18 | kill(ppid, CHILD_OK); 19 | } 20 | else if (strcmp(argv[1], "-p") == 0) { 21 | sigset_t mask; 22 | sigpending(&mask); 23 | if (sigismember(&mask, sig)) 24 | kill(ppid, CHILD_OK); 25 | } 26 | } -------------------------------------------------------------------------------- /cw08/zad1/makefile: -------------------------------------------------------------------------------- 1 | cc = gcc -Wall -ggdb 2 | lib = -lpthread 3 | 4 | all: main 5 | 6 | main: 7 | $(cc) main.c -o main.out $(lib) 8 | 9 | clean: 10 | rm -f *.out *.pgm *.txt 11 | 12 | get-data: 13 | [ -f 'apollonian_gasket.ascii.pgm' ] || wget 'https://people.sc.fsu.edu/~jburkardt/data/pgma/apollonian_gasket.ascii.pgm' 14 | 15 | times = Times.txt 16 | test: get-data main 17 | @echo > $(times) 18 | @for thread_count in 1 2 4 8; do\ 19 | for type in sign block interleaved; do\ 20 | echo "threads: $$thread_count $$type" >> $(times);\ 21 | ./main.out $$thread_count $$type apollonian_gasket.ascii.pgm /dev/null >> $(times);\ 22 | echo >> $(times);\ 23 | done; done 24 | @echo Done! 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | *.pgm 10 | 11 | # Linker output 12 | *.ilk 13 | *.map 14 | *.exp 15 | 16 | # Precompiled Headers 17 | *.gch 18 | *.pch 19 | 20 | # Libraries 21 | *.lib 22 | *.a 23 | *.la 24 | *.lo 25 | 26 | # Shared objects (inc. Windows DLLs) 27 | *.dll 28 | *.so 29 | *.so.* 30 | *.dylib 31 | 32 | # Executables 33 | *.exe 34 | *.out 35 | *.app 36 | *.i*86 37 | *.x86_64 38 | *.hex 39 | 40 | # Debug files 41 | *.dSYM/ 42 | *.su 43 | *.idb 44 | *.pdb 45 | 46 | # Kernel Module Compile Results 47 | *.mod* 48 | *.cmd 49 | .tmp_versions/ 50 | modules.order 51 | Module.symvers 52 | Mkfile.old 53 | dkms.conf 54 | *.txt 55 | ipc -------------------------------------------------------------------------------- /cw05/zad3/customer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "common.h" 5 | 6 | int main(int argc, char** argv) { 7 | if (argc != 4) panic("Invalid number of arguments (recived %d; expected 3).", argc - 1); 8 | FILE* fifo = fopen(argv[1], "r"); 9 | if (!fifo) panic("Can not open file '%s': %s", argv[1], strerror(errno)); 10 | FILE* file = fopen(argv[2], "w+"); 11 | if (!file) panic("Can not open file '%s': %s", argv[2], strerror(errno)); 12 | int N = atoi(argv[3]), read; 13 | 14 | char* buffer = malloc(N * sizeof(char)); 15 | while((read = fread(buffer, sizeof(char), N, fifo)) > 0) { 16 | fwrite(buffer, sizeof(char), read, file); 17 | fflush(file); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /cw01/zad3b/makefile: -------------------------------------------------------------------------------- 1 | cc = gcc -Wall -std=c11 -g 2 | opt_lvl = 0 3 | 4 | all: main_static 5 | 6 | dirs: 7 | mkdir -p build 8 | 9 | static_lib: dirs lib.c 10 | $(cc) -c lib.c -o build/lib.o 11 | ar rcs build/lib.a build/lib.o 12 | 13 | shared_lib: dirs lib.c 14 | $(cc) -c -fPIC lib.c -o build/lib.o 15 | $(cc) -shared -fPIC -o libdiff.so build/lib.o 16 | 17 | main_static: main.c static_lib 18 | $(cc) -c main.c -o build/main.o -O$(opt_lvl) 19 | $(cc) build/main.o build/lib.a -o main.out 20 | 21 | main_shared: shared_lib 22 | $(cc) main.c -L. -o main.out -ldiff -Wl,-rpath=. -O$(opt_lvl) 23 | 24 | main_dynamic: shared_lib 25 | $(cc) main.c -o main.out -ldl -D dynamic -O$(opt_lvl) 26 | 27 | clean: 28 | rm -Rf build *.out *.so *.o *.a -------------------------------------------------------------------------------- /cw04/zad4a/sender.c: -------------------------------------------------------------------------------- 1 | #include "common.c" 2 | 3 | int main(int argc, char** argv) { 4 | bool use_sigqueue = is_arg(3, "sigqueue"); 5 | bool use_sigrt = is_arg(3, "sigrt"); 6 | bool use_kill = is_arg(3, "kill"); 7 | 8 | pid_t pid = atoi(argv[1]); 9 | int sig_usr1_total = atoi(argv[2]); 10 | 11 | init(use_sigrt); 12 | 13 | if (use_kill or use_sigrt) { 14 | repeat(sig_usr1_total) kill(pid, SIG1); 15 | then kill(pid, SIG2); 16 | } 17 | else if (use_sigqueue) { 18 | repeat(sig_usr1_total) sigqueue(pid, SIG1, val); 19 | then sigqueue(pid, SIG2, val); 20 | } 21 | 22 | receive then 23 | if (use_sigqueue) printf("[sender] received: %d (catcher %d)\n", received, sent); 24 | else printf("[sender] received: %d\n", received); 25 | } 26 | -------------------------------------------------------------------------------- /cw07/zad2/common.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | enum package_status { 12 | unused = 0, 13 | recived = 1, 14 | processed = 2, 15 | }; 16 | 17 | #define MAX_PACKAGES 10 18 | #define PERMISSIONS 0600 19 | typedef struct package { 20 | enum package_status status; 21 | int size; 22 | } package; 23 | 24 | struct shared { 25 | int unused, recived, processed; 26 | struct package packages[MAX_PACKAGES]; 27 | } * shared; 28 | 29 | #define using(semid) \ 30 | for (int x = 1; x && (sem_wait(sem), 1); x = (sem_post(sem), 0)) 31 | #define loop for (;;) 32 | #define repeat(n) for (int i = 0; i < n; i++) -------------------------------------------------------------------------------- /cw06/zad2/server/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "events.c" 4 | 5 | mqd_t server_qid; 6 | 7 | def init { // this code runs at the start of the program 8 | server_qid = mq_open(SERVER_PATH, O_CREAT | O_RDWR | O_EXCL, QUEUE_PERMISSIONS, QUEUE_ATTR); 9 | assert(server_qid != -1); 10 | } 11 | 12 | def finish { // this code runs atexit and on SIGINT 13 | foreach(c, clients, 1, MAX_CLIENTS) 14 | if (c->qid) { 15 | send0(Stop, c->qid); 16 | mq_close(c->qid); 17 | } 18 | mq_close(server_qid); 19 | mq_unlink(SERVER_PATH); 20 | } 21 | 22 | def event_loop { // this code is run after init is done 23 | repeat recive (server_qid) 24 | switch(msg.mtype) { 25 | handle(Init) 26 | handle(Connect) 27 | handle(Disconnect) 28 | handle(List) 29 | handle(Stop) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /cw05/zad3/producer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "common.h" 6 | 7 | int main(int argc, char** argv) { 8 | if (argc != 4) panic("Invalid number of arguments (recived %d; expected 3).", argc - 1); 9 | FILE* fifo = fopen(argv[1], "r+"); 10 | if (!fifo) panic("Can not open file '%s': %s", argv[1], strerror(errno)); 11 | FILE* file = fopen(argv[2], "r"); 12 | if (!file) panic("Can not open file '%s': %s", argv[2], strerror(errno)); 13 | int N = atoi(argv[3]), read; 14 | srand(time(0)); 15 | 16 | char* buffer = calloc(N + 1, sizeof(char)); 17 | pid_t pid = getpid(); 18 | while((read = fread(buffer, sizeof(char), N, file)) > 0) { 19 | sleep(rand() % 5 + 1); 20 | buffer[read] = 0; 21 | fprintf(fifo, "#%d#%s\n", pid, buffer); 22 | fflush(fifo); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /cw06/zad1/server/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "events.c" 4 | 5 | qid_t server_qid; 6 | 7 | def init { // this code runs at the start of the program 8 | key_t server_key = ftok(SERVER_KEY_PATHNAME, PROJECT_ID); 9 | assert(server_key != -1); 10 | 11 | server_qid = msgget(server_key, IPC_CREAT | IPC_EXCL | QUEUE_PERMISSIONS); 12 | assert(server_qid != -1); 13 | } 14 | 15 | def finish { // this code runs atexit and on SIGINT 16 | foreach(c, clients, 1, MAX_CLIENTS) 17 | if (c->qid) send0(Stop, c->qid); 18 | msgctl(server_qid, IPC_RMID, NULL); 19 | } 20 | 21 | def event_loop { // this code is run after init is done 22 | repeat recive (server_qid) { 23 | switch(msg.mtype) { 24 | handle(Init) 25 | handle(Connect) 26 | handle(Disconnect) 27 | handle(List) 28 | handle(Stop) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /cw05/zad3/makefile: -------------------------------------------------------------------------------- 1 | cc = gcc -Wall -ggdb 2 | fifo = test.fifo 3 | file = test.txt 4 | filesize = 25 5 | buffsize = 5 6 | 7 | all: customer producer 8 | 9 | customer: 10 | $(cc) customer.c -o customer.out 11 | 12 | producer: 13 | $(cc) producer.c -o producer.out 14 | 15 | test: SHELL:=/bin/bash 16 | test: generate 17 | @rm -f "$(fifo)" 18 | mkfifo "$(fifo)" 19 | ./producer.out "$(fifo)" "$(file)" $(buffsize) & 20 | ./customer.out "$(fifo)" "conf.txt" $(buffsize) 21 | @diff -w test.txt <(echo $$(sed -E 's/^#[0-9]+#//g' conf.txt)) > /dev/null && echo 'test passed' || echo 'test failed' 22 | 23 | testmany: generate 24 | @rm -f "$(fifo)" 25 | $(cc) tester.c -o tester.out 26 | ./tester.out 27 | 28 | generate: all 29 | # generate random alphanumeric string 30 | cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w $(filesize) | head -n 1 | tr -d '\n' > "$(file)" 31 | 32 | clean: 33 | rm -f *.out *.fifo *.txt 34 | -------------------------------------------------------------------------------- /cw08/zad1/image.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "macros.h" 5 | 6 | #define SHADES 256 7 | 8 | typedef unsigned char shade; 9 | typedef struct image { 10 | int width, height; 11 | shade **data; // [x][y] 12 | } image; 13 | 14 | image* load_image(char* path) { 15 | FILE* file = fopen(path, "r"); 16 | assert(file != NULL); 17 | image* img = malloc(sizeof *img); 18 | int shades; 19 | int read = fscanf(file, "P2\n%d %d\n%d\n", &img->width, &img->height, &shades); 20 | assert(shades <= SHADES); 21 | 22 | assert(read == 3); 23 | img->data = malloc(sizeof *img->data * img->width); 24 | repeat(img->width) img->data[i] = malloc(sizeof **img->data * img->height); 25 | 26 | for (int y = 0; y < img->height; y++) 27 | for (int x = 0; x < img->width; x++) 28 | fscanf(file, "%hhu", &img->data[x][y]); 29 | 30 | fclose(file); 31 | return img; 32 | } 33 | -------------------------------------------------------------------------------- /cw04/zad3/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define on(signal, block)\ 8 | void on_##signal(int sig, siginfo_t* info, void* __) { block; _exit(0); } 9 | #define no(signal) {\ 10 | struct sigaction act = {.sa_flags=SA_SIGINFO,.sa_sigaction=on_##signal};\ 11 | sigaction(signal, &act, NULL); } 12 | #define test if (fork() == 0) { 13 | #define end ;exit(0); } else wait(NULL); 14 | 15 | on(SIGSEGV, printf("si_addr (%p)\n", info->si_addr)); 16 | on(SIGINT, printf("si_uid (%u)\n", info->si_uid)); 17 | on(SIGFPE, printf("si_code (%u)\n", info->si_code)); 18 | 19 | int main() { 20 | no(SIGSEGV); 21 | no(SIGINT); 22 | no(SIGFPE); 23 | 24 | int zero = 0; 25 | test int x = 1 / zero end 26 | test { 27 | int* memory_violation = (int*) 12345; 28 | *memory_violation = 213; 29 | } end 30 | test raise(SIGINT) end 31 | } 32 | -------------------------------------------------------------------------------- /cw08/zad1/macros.h: -------------------------------------------------------------------------------- 1 | #ifndef MACROS_H 2 | #define MACROS_H 3 | 4 | #include 5 | #include 6 | 7 | #define copy(arg) ({ typeof(arg)* copy = malloc(sizeof *copy); *copy = arg; copy; }) 8 | #define p_creat(thread_ptr, fn, arg) pthread_create(thread_ptr, NULL, (void* (*)(void*)) fn, copy(arg)) 9 | #define p_join(thread, data_ptr) pthread_join(thread, (void*) data_ptr); 10 | #define ceil_div(a, b) (a / b) + (a % b ? 1 : 0) 11 | #define min(a, b) ({ __auto_type A = a; __auto_type B = b; A < B ? A : B; }) 12 | #define repeat(n) for(int i = 0; i < n; ++i) 13 | 14 | #define measure_time \ 15 | int time;\ 16 | for (\ 17 | struct timespec _time_start, _time_end, *_run = (clock_gettime(CLOCK_MONOTONIC, &_time_start), NULL);\ 18 | _run == NULL;\ 19 | _run = (clock_gettime(CLOCK_MONOTONIC, &_time_end), time = (_time_end.tv_sec - _time_start.tv_sec) * 1000000 + (_time_end.tv_nsec - _time_start.tv_nsec) / 1000, (void*) 1)\ 20 | ) 21 | 22 | #endif -------------------------------------------------------------------------------- /cw04/zad4a/common.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int received = 0, sent; 10 | bool wait = true; 11 | pid_t pid; 12 | union sigval val = {.sival_int=0}; 13 | 14 | void on_sig1(int _) { received++; } 15 | void on_sig2(int sig, siginfo_t * info, void * ucontext) { 16 | pid = info->si_pid; 17 | wait = false; 18 | sent = info->si_value.sival_int; 19 | } 20 | 21 | #define init(use_sigrt) \ 22 | int SIG1 = use_sigrt ? SIGRTMIN : SIGUSR1;\ 23 | int SIG2 = use_sigrt ? SIG1 + 1 : SIGUSR2;\ 24 | signal(SIG1, on_sig1);\ 25 | struct sigaction act = {\ 26 | .sa_flags = SA_SIGINFO,\ 27 | .sa_sigaction = on_sig2\ 28 | };\ 29 | sigaction(SIG2, &act, NULL); 30 | 31 | #define repeat(n) for (int i = 0; i < n; i++) 32 | #define is_arg(n, s) (argc > n && (strcmp(argv[n], s) == 0)) 33 | #define receive while(wait); 34 | #define then 35 | #define or || -------------------------------------------------------------------------------- /cw01/zad1/lib.h: -------------------------------------------------------------------------------- 1 | #ifndef lib 2 | #define lib 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define use(type, var_name, count, code_block){\ 9 | type* var_name = calloc(count, sizeof(type));\ 10 | code_block\ 11 | free(var_name);\ 12 | } 13 | 14 | #define use_malloc(type, var_name, size, code_block){\ 15 | type* var_name = malloc(size);\ 16 | code_block\ 17 | free(var_name);\ 18 | } 19 | 20 | typedef struct block { 21 | unsigned int size; 22 | char* files[2]; 23 | char** operations; 24 | } block; 25 | 26 | typedef struct table { 27 | unsigned int size; 28 | block** values; 29 | } table; 30 | 31 | table* create_table(int size); 32 | block* compare_files(char* file1, char* file2); 33 | void compare_file_sequence(table* table, char** file_sequence); 34 | void remove_block(table* table, int block_index); 35 | void remove_operation(table* table, int block_index, int operation_index); 36 | 37 | int operation_count(table* table, int block_index); 38 | int blocks_count(table* table); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /cw01/zad3a/lib.h: -------------------------------------------------------------------------------- 1 | #ifndef lib 2 | #define lib 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define use(type, var_name, count, code_block){\ 9 | type* var_name = calloc(count, sizeof(type));\ 10 | code_block\ 11 | free(var_name);\ 12 | } 13 | 14 | #define use_malloc(type, var_name, size, code_block){\ 15 | type* var_name = malloc(size);\ 16 | code_block\ 17 | free(var_name);\ 18 | } 19 | 20 | typedef struct block { 21 | unsigned int size; 22 | char* files[2]; 23 | char** operations; 24 | } block; 25 | 26 | typedef struct table { 27 | unsigned int size; 28 | block** values; 29 | } table; 30 | 31 | table* create_table(int size); 32 | block* compare_files(char* file1, char* file2); 33 | void compare_file_sequence(table* table, char** file_sequence); 34 | void remove_block(table* table, int block_index); 35 | void remove_operation(table* table, int block_index, int operation_index); 36 | 37 | int operation_count(table* table, int block_index); 38 | int blocks_count(table* table); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /cw01/zad3b/lib.h: -------------------------------------------------------------------------------- 1 | #ifndef lib 2 | #define lib 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define use(type, var_name, count, code_block){\ 9 | type* var_name = calloc(count, sizeof(type));\ 10 | code_block\ 11 | free(var_name);\ 12 | } 13 | 14 | #define use_malloc(type, var_name, size, code_block){\ 15 | type* var_name = malloc(size);\ 16 | code_block\ 17 | free(var_name);\ 18 | } 19 | 20 | typedef struct block { 21 | unsigned int size; 22 | char* files[2]; 23 | char** operations; 24 | } block; 25 | 26 | typedef struct table { 27 | unsigned int size; 28 | block** values; 29 | } table; 30 | 31 | table* create_table(int size); 32 | block* compare_files(char* file1, char* file2); 33 | void compare_file_sequence(table* table, char** file_sequence); 34 | void remove_block(table* table, int block_index); 35 | void remove_operation(table* table, int block_index, int operation_index); 36 | 37 | int operation_count(table* table, int block_index); 38 | int blocks_count(table* table); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /cw01/zad2/lib.h: -------------------------------------------------------------------------------- 1 | #ifndef lib 2 | #define lib 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define use(type, var_name, count, code_block){\ 9 | type* var_name = calloc(count, sizeof(type));\ 10 | code_block\ 11 | free(var_name);\ 12 | } 13 | 14 | #define use_malloc(type, var_name, size, code_block){\ 15 | type var_name = malloc(size);\ 16 | code_block\ 17 | free(var_name);\ 18 | } 19 | 20 | typedef struct block { 21 | unsigned int size; 22 | char* files[2]; 23 | char** operations; 24 | } block; 25 | 26 | typedef struct table { 27 | unsigned int size; 28 | block** values; 29 | } table; 30 | 31 | table* create_table(int size); 32 | block* compare_files(char* file1, char* file2); 33 | void compare_file_sequence(table* table, char** file_sequence); 34 | void remove_block(table* table, int block_index); 35 | void remove_operation(table* table, int block_index, int operation_index); 36 | 37 | int operation_count(table* table, int block_index); 38 | int blocks_count(table* table); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /cw02/zad1/main.c: -------------------------------------------------------------------------------- 1 | #include "sys.c" 2 | #include "lib.c" 3 | 4 | int main(int argc, char** argv) { 5 | if (strcmp(argv[1], "generate") == 0) { 6 | int word_count = atoi(argv[3]); 7 | int word_size = atoi(argv[4]); 8 | generate(argv[2], word_count, word_size); 9 | } 10 | 11 | else if (strcmp(argv[1], "sort") == 0) { 12 | char* file = argv[2]; 13 | int word_count = atoi(argv[3]); 14 | int word_size = atoi(argv[4]); 15 | bool use_sys = strcmp(arg(5, "sys"), "sys") == 0; 16 | 17 | if (use_sys) time_it({ sort_sys(file, word_count, word_size); }) 18 | else time_it({ sort_lib(file, word_count, word_size); }) 19 | 20 | } 21 | 22 | else if (strcmp(argv[1], "copy") == 0) { 23 | char* source = argv[2]; 24 | char* target = argv[3]; 25 | 26 | int word_count = atoi(argv[4]); 27 | buffer_size = atoi(arg(5, "512")); 28 | bool use_sys = strcmp(arg(6, "sys"), "sys") == 0; 29 | buffer = malloc(buffer_size * sizeof(char)); 30 | 31 | if (use_sys) time_it({ copy_sys(source, target, word_count); }) 32 | else time_it({ copy_lib(source, target, word_count); }) 33 | } 34 | } -------------------------------------------------------------------------------- /cw07/zad1/manager.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "common.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define spawn(exe) if (fork() == 0 && execlp(exe, exe, NULL) == -1) exit(1); 12 | 13 | int semid, shmid; 14 | void at_exit() { 15 | shmctl(shmid, IPC_RMID, NULL); 16 | semctl(semid, 10, IPC_RMID, NULL); 17 | } 18 | 19 | int main() { 20 | atexit(at_exit); 21 | signal(SIGINT, exit); 22 | 23 | key_t key = ftok(HOME_PATH, PROJECT_ID); 24 | shmid = shmget(key, sizeof(struct shared), IPC_CREAT | IPC_EXCL | PERMISSIONS); 25 | assert(shmid != -1); 26 | 27 | shared = shmat(shmid, NULL, 0); 28 | assert(shared != NULL); 29 | shared->unused = MAX_PACKAGES; 30 | 31 | semid = semget(key, 100, IPC_CREAT | IPC_EXCL | PERMISSIONS); 32 | assert(semid != -1); 33 | semop(semid, &sem_inc, 1); 34 | 35 | repeat (10) spawn("./worker1.out"); 36 | repeat (10) spawn("./worker2.out"); 37 | repeat (10) spawn("./worker3.out"); 38 | 39 | while(wait(NULL) != -1); 40 | 41 | return 0; 42 | } -------------------------------------------------------------------------------- /cw07/zad1/common.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | enum package_status { 13 | unused = 0, 14 | recived = 1, 15 | processed = 2, 16 | }; 17 | 18 | #define MAX_PACKAGES 10 19 | #define PERMISSIONS 0600 20 | #define HOME_PATH (getpwuid(getuid())->pw_dir) 21 | #define PROJECT_ID 'M' 22 | 23 | typedef struct package { 24 | enum package_status status; 25 | int size; 26 | } package; 27 | 28 | struct shared { 29 | int unused, recived, processed; 30 | struct package packages[MAX_PACKAGES]; 31 | } *shared; 32 | 33 | struct sembuf sem_wait = {1, 0, SEM_UNDO}; 34 | struct sembuf sem_inc = {1, 1, SEM_UNDO}; 35 | struct sembuf sem_dec = {1, -1, SEM_UNDO}; 36 | #define using(semid) \ 37 | for (int x = 1; x && (semop(semid, &sem_dec, 1), 1); \ 38 | x = (semop(semid, &sem_inc, 1), 0)) 39 | #define loop for (;;) 40 | #define repeat(n) for (int i = 0; i < n; i++) -------------------------------------------------------------------------------- /cw03/zad1/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | char* join_path(char* path1, char* path2) { 10 | char* path = malloc(sizeof(char) * (strlen(path1) + strlen(path2)) + 2); 11 | sprintf(path, "%s/%s", path1, path2); 12 | return path; 13 | } 14 | 15 | void scan_dir(char* path) { 16 | if (!path) return; 17 | DIR* dir = opendir(path); 18 | if (!dir) return; // can not read 19 | 20 | struct dirent* d; 21 | struct stat s; 22 | while ((d = readdir(dir))) { 23 | if (strcmp(d->d_name, "..") == 0) continue; 24 | if (strcmp(d->d_name, ".") == 0) continue; 25 | 26 | char* dir = join_path(path, d->d_name); 27 | if (lstat(dir, &s) < 0) continue; // can not read 28 | if (S_ISDIR(s.st_mode) && fork() == 0) { 29 | printf("\npid(%i) path(%s)\n", getpid(), dir); 30 | execlp("ls", "ls", dir, "-l", NULL); 31 | } else wait(NULL); // wait for preatier printing 32 | 33 | free(dir); 34 | } 35 | closedir(dir); 36 | } 37 | 38 | int main(int argc, char** argv) { 39 | char* search_path = argc > 1 ? argv[1] : "."; 40 | scan_dir(search_path); 41 | return 0; 42 | } -------------------------------------------------------------------------------- /cw07/zad2/manager.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "common.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define spawn(exe) if (fork() == 0 && execlp(exe, exe, NULL) == -1) exit(1); 12 | 13 | int shmid; 14 | sem_t* sem; 15 | void at_exit() { 16 | signal(SIGINT, SIG_IGN); 17 | kill(0, SIGINT); 18 | munmap(shared, sizeof(struct shared)); 19 | shm_unlink("/shared"); 20 | sem_close(sem); 21 | sem_unlink("/shared"); 22 | } 23 | 24 | int main() { 25 | atexit(at_exit); 26 | signal(SIGINT, exit); 27 | 28 | shmid = shm_open("/shared", O_CREAT | O_RDWR | O_EXCL, PERMISSIONS); 29 | ftruncate(shmid, sizeof(struct shared)); 30 | assert(shmid != -1); 31 | 32 | shared = mmap(0, sizeof(struct shared), PROT_READ | PROT_WRITE, MAP_SHARED, shmid, 0); 33 | assert(shared != NULL); 34 | shared->unused = MAX_PACKAGES; 35 | 36 | sem = sem_open("/shared", O_CREAT | O_EXCL, PERMISSIONS, 1); 37 | assert(sem != NULL); 38 | 39 | repeat (10) spawn("./worker1.out"); 40 | repeat (10) spawn("./worker2.out"); 41 | repeat (10) spawn("./worker3.out"); 42 | 43 | while(wait(NULL) != -1); 44 | 45 | return 0; 46 | } -------------------------------------------------------------------------------- /cw04/zad2/strings.h: -------------------------------------------------------------------------------- 1 | #define FORK_HEADER \ 2 | " │ fork() │ ignore │ chandler │ mask │ pending │\n"\ 3 | "┌────┬─────────────────┴────────┼─────────┬──────────┼─────────┬──────────┼─────────┬──────────┼─────────┬──────────┤\n"\ 4 | "│ no │ signal │ child │ parent │ child │ parent │ child │ parent │ child │ parent │\n"\ 5 | "├────┼──────────────────────────┼─────────┼──────────┼─────────┼──────────┼─────────┼──────────┼─────────┼──────────┤\n"\ 6 | 7 | #define FORK_FOOTER \ 8 | "└────┴──────────────────────────┴─────────┴──────────┴─────────┴──────────┴─────────┴──────────┴─────────┴──────────┘\n" 9 | 10 | #define EXEC_HEADER \ 11 | " │ exec() │ ignore │ mask │ pending │\n"\ 12 | "┌────┬─────────────────┴────────┼─────────┬──────────┼─────────┬──────────┼─────────┬──────────┤\n"\ 13 | "│ no │ signal │ child │ parent │ child │ parent │ child │ parent │\n"\ 14 | "├────┼──────────────────────────┼─────────┼──────────┼─────────┼──────────┼─────────┼──────────┤\n" 15 | 16 | #define EXEC_FOOTER \ 17 | "└────┴──────────────────────────┴─────────┴──────────┴─────────┴──────────┴─────────┴──────────┘\n" 18 | -------------------------------------------------------------------------------- /cw04/zad1/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define repeat for(;;) 9 | #define foreach(var, f) for (__auto_type var = f; var; var = f) 10 | #define not(val) (!(val)) 11 | 12 | #define on(sig, fn) void ON_##sig fn 13 | #define no(sig) signal(sig, ON_##sig) 14 | #define no_block(sig) {\ 15 | struct sigaction act = {.sa_handler=ON_##sig, .sa_flags=SA_NODEFER};\ 16 | sigemptyset(&act.sa_mask);\ 17 | sigaction(sig, &act, NULL);} 18 | 19 | static DIR* dir; 20 | 21 | on(SIGTSTP, (int sig) { 22 | static bool wait = false; 23 | if not (wait = !wait) return; 24 | static const char message[] = "\nOczekuję na CTRL+Z - kontynuacja albo CTR+C - zakończenie programu.\n"; 25 | write(STDOUT_FILENO, message, sizeof(message)); 26 | pause(); 27 | }) 28 | 29 | on(SIGINT, (int sig) { 30 | static const char message[] = "\nOdebrano sygnał SIGINT.\n"; 31 | write(STDERR_FILENO, message, sizeof(message)); 32 | exit(0); 33 | }) 34 | 35 | int main(int argc, char** argv) { 36 | no_block(SIGTSTP); 37 | no(SIGINT); 38 | 39 | repeat { 40 | dir = opendir("."); 41 | foreach(entry, readdir(dir)) 42 | printf("%s\n", entry->d_name); 43 | closedir(dir); 44 | } 45 | } -------------------------------------------------------------------------------- /cw10/zad1/common.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #define safe(expr) \ 21 | ({ \ 22 | typeof(expr) __tmp = expr; \ 23 | if (__tmp == -1) { \ 24 | printf("%s:%d "#expr" failed: %s\n", __FILE__, __LINE__, strerror(errno));\ 25 | exit(EXIT_FAILURE); \ 26 | } \ 27 | __tmp; \ 28 | }) 29 | #define loop for(;;) 30 | #define find(init, cond) ({ int index = -1; for (init) if (cond) { index = i; break; } index; }) 31 | #define repeat(n) for(int i = 0; i < n; i++) 32 | #define print(x) write(STDOUT_FILENO, x, sizeof(x)) -------------------------------------------------------------------------------- /cw10/zad2/common.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #define safe(expr) \ 21 | ({ \ 22 | typeof(expr) __tmp = expr; \ 23 | if (__tmp == -1) { \ 24 | printf("%s:%d "#expr" failed: %s\n", __FILE__, __LINE__, strerror(errno));\ 25 | exit(EXIT_FAILURE); \ 26 | } \ 27 | __tmp; \ 28 | }) 29 | #define loop for(;;) 30 | #define find(init, cond) ({ int index = -1; for (init) if (cond) { index = i; break; } index; }) 31 | #define repeat(n) for(int i = 0; i < n; i++) 32 | #define print(x) write(STDOUT_FILENO, x, sizeof(x)) -------------------------------------------------------------------------------- /cw02/zad1/makefile: -------------------------------------------------------------------------------- 1 | cc = gcc -Wall -ggdb 2 | 3 | all: main 4 | 5 | main: 6 | $(cc) -o main.out main.c 7 | 8 | clean: 9 | rm -Rf *.out *.txt data* 10 | 11 | test: main 12 | 13 | echo "type\tcount\tsize\treal\tsys\tuser" > wyniki.txt 14 | for word_count in 100 10000; do\ 15 | for word_size in 1 4 512 1024 4096 8192; do\ 16 | ./main.out generate data $$word_count $$word_size >> wyniki.txt;\ 17 | echo -n "lib\t$$word_count\t$$word_size\t" >> wyniki.txt;\ 18 | ./main.out copy data data-$$word_count-$$word_size-lib.txt $$word_count $$word_size lib >> wyniki.txt;\ 19 | echo -n "sys\t$$word_count\t$$word_size\t" >> wyniki.txt;\ 20 | ./main.out copy data data-$$word_count-$$word_size-sys.txt $$word_count $$word_size sys >> wyniki.txt;\ 21 | done;\ 22 | done 23 | 24 | echo >> wyniki.txt 25 | echo "type\tcount\tsize\treal\tsys\tuser" >> wyniki.txt 26 | for word_count in 100 10000; do\ 27 | for word_size in 1 4 512 1024 4096 8192; do\ 28 | echo -n "lib\t$$word_count\t$$word_size\t" >> wyniki.txt;\ 29 | ./main.out sort data-$$word_count-$$word_size-lib.txt $$word_count $$word_size lib >> wyniki.txt;\ 30 | echo -n "sys\t$$word_count\t$$word_size\t" >> wyniki.txt;\ 31 | ./main.out sort data-$$word_count-$$word_size-sys.txt $$word_count $$word_size sys >> wyniki.txt;\ 32 | done;\ 33 | done 34 | 35 | rm -f data* -------------------------------------------------------------------------------- /cw04/zad2/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "strings.h" 9 | #define IPC_MAIN 10 | #include "ipc.h" 11 | 12 | #define exec_and_wait(program, args...) {\ 13 | child_ok = parent_ok = false;\ 14 | if (fork() == 0) execl(program, program, args, NULL);\ 15 | waitpid(WAIT_ANY, NULL, WUNTRACED);\ 16 | printf(" %5s │ %5s │", CHILD_STATUS, PARENT_STATUS);\ 17 | } 18 | 19 | #define EXE "./sig_test.out" 20 | char* itoa(int value) { 21 | static char buff[12]; 22 | sprintf(buff, "%i", value); 23 | return strdup(buff); 24 | } 25 | 26 | const char* const flags_fork[] = { "-i", "-h", "-m", "-p"}; 27 | const char* const flags_exec[] = { "-i", "-m", "-p"}; 28 | 29 | int main() { 30 | IPC_INIT; 31 | 32 | printf(FORK_HEADER); 33 | for (int signal = 1; signal <= 22; signal++) { 34 | char* sig = itoa(signal); 35 | printf("│ %2i │ %24s │", signal, strsignal(signal)); 36 | for (int i = 0; i < 4; i++) 37 | exec_and_wait(EXE, "-s", sig, flags_fork[i]); 38 | printf("\n"); 39 | } 40 | printf(FORK_FOOTER "\n\n"); 41 | 42 | printf(EXEC_HEADER); 43 | for (int signal = 1; signal <= 22; signal++) { 44 | char* sig = itoa(signal); 45 | printf("│ %2i │ %24s │", signal, strsignal(signal)); 46 | for (int i = 0; i < 3; i++) 47 | exec_and_wait(EXE, "-e", "-s", sig, flags_exec[i]); 48 | printf("\n"); 49 | } 50 | printf(EXEC_FOOTER); 51 | } -------------------------------------------------------------------------------- /cw06/zad1/server/events.c: -------------------------------------------------------------------------------- 1 | #ifndef events_c 2 | #define events_c 3 | 4 | #include "logic.c" 5 | 6 | on(Init) { 7 | client* client = new_client(payload->qid); 8 | return client ? sendi(Init, client->qid, { client->id }) : server_full; 9 | } 10 | 11 | on(Stop) { 12 | return remove_client(payload->qid), Ok; 13 | } 14 | 15 | on(Disconnect) { 16 | return disconnect(payload->qid), Ok; 17 | } 18 | 19 | on(List) { 20 | message msg = { List }; 21 | int size = 0; 22 | 23 | struct client_info* info; 24 | for (int i = 0; i < MAX_CLIENTS; i++) 25 | if (clients[i].qid) { 26 | info = msg.payload.response.List.clients + size; 27 | info->id = clients[i].id; 28 | info->available = clients[i].peer == NULL; 29 | size++; 30 | } 31 | 32 | msg.payload.response.List.size = size; 33 | assert(msgsnd(payload->qid, &msg, (sizeof *info) * size + (sizeof size), 0) != -1); 34 | return Ok; 35 | } 36 | 37 | on(Connect) { 38 | struct client* client = find_client_by_qid(payload->qid); 39 | if (client == NULL) return bad_qid; 40 | if (client->peer != NULL) return self_occupied; 41 | 42 | struct client* peer = find_client_by_id(payload->peer_id); 43 | if (peer == NULL) return bad_id; 44 | if (peer->peer != NULL) return occupied; 45 | 46 | if (client == peer) return self; 47 | client->peer = peer; 48 | peer->peer = client; 49 | 50 | sendi(Connect, client->qid, { peer->id, peer->qid }); 51 | sendi(Connect, peer->qid, { client->id, client->qid }); 52 | return Ok; 53 | } 54 | 55 | #endif -------------------------------------------------------------------------------- /cw04/zad4b/common.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define listen \ 10 | sigset_t mask;\ 11 | sigprocmask(SIG_SETMASK, &mask, NULL); 12 | #define to(p) pid = p; 13 | #define then 14 | #define and ; 15 | 16 | static pid_t pid; 17 | static sigset_t send_mask; 18 | static bool waiting; 19 | static union sigval val = {.sival_int = 0}; 20 | 21 | int received; 22 | void count(int sig, siginfo_t* info, void* ucontext) { 23 | received++; 24 | sigqueue(info->si_pid, SIGUSR1, val); 25 | } 26 | 27 | void finish(int sig, siginfo_t* info, void* ucontext) { 28 | pid = info->si_pid; 29 | waiting = false; 30 | sigqueue(info->si_pid, SIGUSR1, val); 31 | } 32 | 33 | #define post \ 34 | struct sigaction act = {\ 35 | .sa_flags = SA_SIGINFO,\ 36 | .sa_sigaction = ignore_sig };\ 37 | sigaction(SIGUSR1, &act, NULL);\ 38 | sigset_t post_mask;\ 39 | sigaddset(&post_mask, SIGUSR1);\ 40 | sigprocmask(SIG_SETMASK, &post_mask, NULL);\ 41 | 42 | void ignore_sig(int sig, siginfo_t* info, void* ucontext) {} 43 | #define repeat(n) for (int i = 0; i < n; i++) 44 | #define send(sig) {\ 45 | kill(pid, sig);\ 46 | sigemptyset(&send_mask);\ 47 | sigsuspend(&send_mask); } 48 | 49 | #define on(signal) { int sig = signal; struct sigaction act = {.sa_flags=SA_SIGINFO}; 50 | #define do(action) act.sa_sigaction = action; sigaction(sig, &act, NULL); } 51 | #define receive { waiting = true; while(waiting); } -------------------------------------------------------------------------------- /cw05/zad1/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define spawn(command) if (fork() == 0) \ 8 | for (char **__x = command;; (execvp(__x[0], __x) != -1) || (exit(1), 1)) 9 | #define wait_all while (wait(NULL) > 0) ; 10 | 11 | #define redirect(x) dup2(x); 12 | #define output(pipe) (close(pipe[1]), pipe[0]) 13 | #define input(pipe) (close(pipe[0]), pipe[1]) 14 | #define to , 15 | #define MAX_ARGS 10 16 | #define unless(x) if (!(x)) 17 | 18 | char **parse(char *line) { 19 | static char *elements[MAX_ARGS + 1]; 20 | 21 | int i = 0; 22 | while (line != NULL && i < MAX_ARGS) { 23 | char *arg = strsep(&line, " \n"); 24 | if (*arg) elements[i++] = arg; 25 | } 26 | 27 | while (i < MAX_ARGS) 28 | elements[i++] = NULL; 29 | 30 | return elements; 31 | } 32 | 33 | int main(int argc, char **argv) { 34 | if (argc != 2) return 1; 35 | FILE *commands = fopen(argv[1], "r"); 36 | 37 | int current[2], previous[2] = {-1, -1}; 38 | char *line = NULL, *process_info; 39 | #define last line == NULL 40 | size_t line_len = 0; 41 | 42 | while (getline(&line, &line_len, commands) > 0) { 43 | while ((process_info = strsep(&line, "|")) != NULL) { 44 | pipe(current); 45 | spawn(parse(process_info)) { 46 | redirect(output(previous) to STDIN_FILENO); 47 | unless(last) redirect(input(current) to STDOUT_FILENO); 48 | } 49 | 50 | previous[0] = output(current); 51 | previous[1] = current[1]; 52 | } 53 | wait_all; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /cw06/zad1/common/common.h: -------------------------------------------------------------------------------- 1 | #ifndef common_h 2 | #define common_h 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define SERVER_KEY_PATHNAME (getpwuid(getuid())->pw_dir) 12 | #define PROJECT_ID 'M' 13 | #define QUEUE_PERMISSIONS 0620 14 | 15 | #define def 16 | #define event_loop void event_loop_fn() 17 | #define init void init_fn(int argc, char **argv) 18 | #define finish void finish_fn() 19 | void init_fn(int argc, char **argv); 20 | void finish_fn(); 21 | void event_loop_fn(); 22 | 23 | #define repeat for (;;) 24 | #define foreach(var, ptr, from, length) \ 25 | for (typeof(*ptr) *var = ptr, *last = ptr + length - 1; var <= last; ++var) 26 | 27 | // ansi escape codes 28 | #define left(n) "\033[" #n "D" 29 | #define clearline(n) "\033[" #n "K" 30 | 31 | #define red "\033[31m" 32 | #define green "\033[32m" 33 | #define yellow "\033[93m" 34 | #define cyan "\033[96m" 35 | #define cdefault "\033[0m" 36 | 37 | #define print(x) write(STDOUT_FILENO, x, sizeof(x)) 38 | 39 | // rutime 40 | void on_sigint(int _) { 41 | print(left(10) "Recived " red "SIGINT" cdefault " shutting down gracefully.\n"); 42 | exit(0); 43 | } 44 | 45 | void at_exit() { 46 | finish_fn(); 47 | print("Finish: " green "OK" cdefault "\n"); 48 | } 49 | 50 | int main(int argc, char **argv) { 51 | print("Initializing"); 52 | signal(SIGINT, on_sigint); 53 | atexit(at_exit); 54 | init_fn(argc, argv); 55 | print(left(100) "Init:" clearline() green "\tOK\n" cdefault); 56 | print("Event loop\n"); 57 | event_loop_fn(); 58 | } 59 | 60 | #endif -------------------------------------------------------------------------------- /cw06/zad1/server/logic.c: -------------------------------------------------------------------------------- 1 | #define SERVER 2 | #include "../common/message.h" 3 | #include "../common/common.h" 4 | 5 | struct client { 6 | qid_t qid; 7 | id_t id; 8 | struct client *peer; 9 | } clients[MAX_CLIENTS]; 10 | typedef struct client client; 11 | 12 | client *new_client(qid_t qid) { 13 | static int id = 1; 14 | for (int i = 0; i < MAX_CLIENTS; i++) 15 | if (clients[i].qid == 0) { 16 | client *c = clients + i; 17 | c->qid = qid; 18 | c->id = id++; 19 | c->peer = NULL; 20 | return c; 21 | } 22 | return NULL; 23 | } 24 | 25 | static void disconnect_pear(client* c) { 26 | if (c->peer == NULL) return; 27 | send0(Disconnect, c->peer->qid); 28 | send0(Disconnect, c->qid); 29 | c->peer->peer = NULL; 30 | c->peer = NULL; 31 | } 32 | 33 | void remove_client(qid_t qid) { 34 | for (int i = 0; i < MAX_CLIENTS; i++) { 35 | if (clients[i].qid == qid) { 36 | disconnect_pear(clients + i); 37 | clients[i].qid = 0; 38 | clients[i].id = 0; 39 | clients[i].peer = NULL; 40 | } 41 | } 42 | send0(Stop, qid); 43 | } 44 | 45 | void disconnect(qid_t qid) { 46 | for (int i = 0; i < MAX_CLIENTS; i++) 47 | if (clients[i].qid == qid) 48 | disconnect_pear(clients + i); 49 | } 50 | 51 | client* find_client_by_id(id_t id) { 52 | for (int i = 0; i < MAX_CLIENTS; i++) 53 | if (clients[i].id == id) 54 | return clients + i; 55 | return NULL; 56 | } 57 | 58 | client* find_client_by_qid(qid_t qid) { 59 | for (int i = 0; i < MAX_CLIENTS; i++) 60 | if (clients[i].qid == qid) 61 | return clients + i; 62 | return NULL; 63 | } -------------------------------------------------------------------------------- /cw05/zad3/tester.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define READ_SIZE "10" 11 | #define PRODUCER "./producer.out" 12 | #define CONSUMENT "./customer.out" 13 | #define FIFO "test.fifo" 14 | #define CONFIRM "conf.txt" 15 | #define TESTS 5 16 | 17 | #define wait_all while (wait(NULL) > 0) ; 18 | #define do if (fork() == 0) 19 | #define exec(exe, args...) execlp(exe, exe, args, NULL) 20 | #define repeat(n) for (int i = 0; i < n; i++) 21 | #define then 22 | 23 | char* itoa(int value) { 24 | static char buff[12]; 25 | sprintf(buff, "%i", value); 26 | return strdup(buff); 27 | } 28 | 29 | char* generate(char* base, int id) { 30 | char* filename = calloc(strlen(base) + 12, sizeof(char)); 31 | sprintf(filename, "%s_%i.txt", base, id); 32 | FILE* file = fopen(filename, "w+"); 33 | repeat (25) fprintf(file, "%i", id); 34 | fclose(file); 35 | return filename; 36 | } 37 | 38 | int main() { 39 | if (mkfifo(FIFO, 0644) != 0) 40 | panic("Can not create fifo '%s': %s", FIFO, strerror(errno)); 41 | 42 | do { 43 | exec(CONSUMENT, FIFO, CONFIRM, READ_SIZE); 44 | panic("Can not exec '%s': %s", CONSUMENT, strerror(errno)); 45 | } 46 | 47 | repeat (TESTS) { 48 | char* size = itoa(rand() % 10 + 5); 49 | do { 50 | char* test_file = generate("test", i); 51 | exec(PRODUCER, FIFO, test_file, size); 52 | panic("Can not exec '%s': %s", PRODUCER, strerror(errno)); 53 | } 54 | } 55 | 56 | wait_all then remove(FIFO); 57 | } 58 | -------------------------------------------------------------------------------- /cw01/zad2/main.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | #include 3 | #include 4 | 5 | static struct tms tms_start, tms_end; 6 | static clock_t clock_start, clock_end; 7 | 8 | #define time_it(name, code_block)\ 9 | clock_start = times(&tms_start);\ 10 | code_block\ 11 | clock_end = times(&tms_end);\ 12 | printf("\n%s\n", name);\ 13 | printf("real time: %ld\n", clock_end - clock_start);\ 14 | printf(" sys time: %ld\n", tms_end.tms_stime - tms_start.tms_stime);\ 15 | printf("user time: %ld\n", tms_end.tms_utime - tms_start.tms_utime) 16 | 17 | int main(int argc, char **argv) { 18 | 19 | table* main_table = NULL; 20 | 21 | for (int i = 1; i < argc; i++) { 22 | char* arg = argv[i]; 23 | 24 | if(strcmp(arg, "create_table") == 0) { 25 | if (main_table) free(main_table); 26 | int size = atoi(argv[++i]); 27 | main_table = create_table(size); 28 | } 29 | 30 | else if (strcmp(arg, "compare_pairs") == 0) { 31 | time_it("compare_pairs", { 32 | compare_file_sequence(main_table, argv + i + 1); 33 | }); 34 | i = i + main_table->size; 35 | } 36 | 37 | else if (strcmp(arg, "remove_block") == 0) { 38 | int block_index = atoi(argv[++i]); 39 | time_it("remove_block", { 40 | remove_block(main_table, block_index); 41 | }); 42 | } 43 | 44 | else if (strcmp(arg, "remove_operation") == 0) { 45 | int block_index = atoi(argv[++i]); 46 | int operation_index = atoi(argv[++i]); 47 | time_it("remove_operation", { 48 | remove_operation(main_table, block_index, operation_index); 49 | }); 50 | } 51 | 52 | } 53 | return 0; 54 | } -------------------------------------------------------------------------------- /cw06/zad2/common/common.h: -------------------------------------------------------------------------------- 1 | #ifndef common_h 2 | #define common_h 3 | 4 | #define SERVER_PATH "/server" 5 | #define PROJECT_ID 'M' 6 | #define QUEUE_PERMISSIONS 0620 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define def 15 | #define event_loop void event_loop_fn() 16 | #define init void init_fn(int argc, char **argv) 17 | #define finish void finish_fn() 18 | void init_fn(int argc, char **argv); 19 | void finish_fn(); 20 | void event_loop_fn(); 21 | 22 | #define repeat for (;;) 23 | #define foreach(var, ptr, from, length) \ 24 | for (typeof(ptr[0]) *var = ptr, *last = ptr + length - 1; var <= last; ++var) 25 | 26 | // ansi escape codes 27 | #define left(n) "\033[" #n "D" 28 | #define clearline(n) "\033[" #n "K" 29 | 30 | #define red "\033[31m" 31 | #define green "\033[32m" 32 | #define yellow "\033[93m" 33 | #define cyan "\033[96m" 34 | #define cdefault "\033[0m" 35 | 36 | #define print(x) write(STDOUT_FILENO, x, sizeof(x)) 37 | 38 | // rutime 39 | void on_sigint(int _) { 40 | print(left(10) "Recived " red "SIGINT" cdefault " shutting down gracefully.\n"); 41 | exit(0); 42 | } 43 | 44 | void at_exit() { 45 | finish_fn(); 46 | print("Finish: " green "OK" cdefault "\n"); 47 | } 48 | 49 | char* path(pid_t pid) { // do not store result 50 | static char path[15]; 51 | sprintf(path, "/c%d", pid); 52 | return path; 53 | } 54 | 55 | int main(int argc, char **argv) { 56 | print("Initializing"); 57 | signal(SIGINT, on_sigint); 58 | atexit(at_exit); 59 | init_fn(argc, argv); 60 | print(left(100) "Init:" clearline() green "\tOK\n" cdefault); 61 | print("Event loop\n"); 62 | event_loop_fn(); 63 | } 64 | 65 | #endif -------------------------------------------------------------------------------- /cw06/zad2/server/events.c: -------------------------------------------------------------------------------- 1 | #ifndef events_c 2 | #define events_c 3 | 4 | #include "logic.c" 5 | 6 | on(Init) { 7 | client* client = new_client(payload->id); 8 | return client ? sendi(Init, client->qid, { client->id }) : server_full; 9 | } 10 | 11 | on(Stop) { 12 | return remove_client(payload->id), Ok; 13 | } 14 | 15 | on(Disconnect) { 16 | return disconnect(payload->id), Ok; 17 | } 18 | 19 | on(List) { 20 | message msg = { List }; 21 | int size = 0; 22 | 23 | struct client_info* info; 24 | mqd_t qid; 25 | for (int i = 0; i < MAX_CLIENTS; i++) { 26 | if (clients[i].id == payload->id) qid = clients[i].qid; 27 | if (clients[i].qid) { 28 | info = msg.payload.response.List.clients + size; 29 | info->id = clients[i].id; 30 | info->available = clients[i].peer == NULL; 31 | size++; 32 | } 33 | } 34 | 35 | msg.payload.response.List.size = size; 36 | mq_send(qid, (char*) &msg, (sizeof *info) * size + (sizeof size) + sizeof(long), List); 37 | return Ok; 38 | } 39 | 40 | on(Connect) { 41 | struct client* client = find_client_by_id(payload->id); 42 | if (client == NULL) return bad_qid; 43 | if (client->peer != NULL) return self_occupied; 44 | 45 | struct client* peer = find_client_by_id(payload->peer_id); 46 | if (peer == NULL) return bad_id; 47 | if (peer->peer != NULL) return occupied; 48 | 49 | if (client == peer) return self; 50 | client->peer = peer; 51 | peer->peer = client; 52 | 53 | sendi(Connect, client->qid, { peer->id, peer->pid }); 54 | sendi(Connect, peer->qid, { client->id, client->pid }); 55 | return Ok; 56 | } 57 | 58 | void on_error(id_t id, enum error_t error) { 59 | client* c = find_client_by_id(id); 60 | if (c) sendi(Error, c->qid, error); 61 | } 62 | #endif -------------------------------------------------------------------------------- /cw06/zad2/server/logic.c: -------------------------------------------------------------------------------- 1 | #define SERVER 2 | #include "../common/message.h" 3 | #include "../common/common.h" 4 | 5 | struct client { 6 | mqd_t qid; 7 | pid_t pid; 8 | id_t id; 9 | struct client *peer; 10 | } clients[MAX_CLIENTS]; 11 | typedef struct client client; 12 | 13 | client *new_client(pid_t pid) { 14 | static int id = 1; 15 | for (int i = 0; i < MAX_CLIENTS; i++) 16 | if (clients[i].qid == 0) { 17 | client *c = clients + i; 18 | c->qid = mq_open(path(pid), O_RDWR, QUEUE_PERMISSIONS, NULL); 19 | c->id = id++; 20 | c->pid = pid; 21 | c->peer = NULL; 22 | return c; 23 | } 24 | return NULL; 25 | } 26 | 27 | static void disconnect_pear(client* c) { 28 | if (c->peer == NULL) return; 29 | send0(Disconnect, c->peer->qid); 30 | send0(Disconnect, c->qid); 31 | c->peer->peer = NULL; 32 | c->peer = NULL; 33 | } 34 | 35 | void remove_client(id_t id) { 36 | for (int i = 0; i < MAX_CLIENTS; i++) { 37 | if (clients[i].id == id) { 38 | disconnect_pear(clients + i); 39 | clients[i].id = 0; 40 | send0(Stop, clients[i].qid); 41 | mq_close(clients[i].qid); 42 | clients[i].pid = 0; 43 | clients[i].qid = 0; 44 | clients[i].peer = NULL; 45 | } 46 | } 47 | } 48 | 49 | void disconnect(id_t id) { 50 | for (int i = 0; i < MAX_CLIENTS; i++) 51 | if (clients[i].id == id) 52 | disconnect_pear(clients + i); 53 | } 54 | 55 | client* find_client_by_id(id_t id) { 56 | for (int i = 0; i < MAX_CLIENTS; i++) 57 | if (clients[i].id == id) 58 | return clients + i; 59 | return NULL; 60 | } 61 | 62 | client* find_client_by_qid(qid_t qid) { 63 | for (int i = 0; i < MAX_CLIENTS; i++) 64 | if (clients[i].qid == qid) 65 | return clients + i; 66 | return NULL; 67 | } -------------------------------------------------------------------------------- /cw06/zad1/client/events.c: -------------------------------------------------------------------------------- 1 | #ifndef events_c 2 | #define events_c 3 | 4 | #include "logic.c" 5 | 6 | on(Init) { 7 | assert(client_id == 0); // trying to reinitialize client_id is not permited 8 | client_id = payload->id; 9 | return Ok; 10 | } 11 | 12 | on(Stop) { 13 | server_qid = -1; // prevent request to the server at exit 14 | return exit(0), Ok; 15 | } 16 | 17 | on(Disconnect) { 18 | printf(cyan "Disconnected " cdefault "from %d\n", peer_id); 19 | return disconnect(), Ok; 20 | } 21 | 22 | on(List) { 23 | assert(payload->size > 0); 24 | print("id\tstate\n"); 25 | foreach (c, payload->clients, 0, payload->size) { 26 | printf(cdefault "%u\t", c->id); 27 | if (c->id == peer_id) printf(green "peer\n"); 28 | else if (c->id == client_id) printf(yellow "you\n"); 29 | else if (c->available) printf(cdefault "available\n"); 30 | else printf(red "not available\n"); 31 | } 32 | print(cdefault); 33 | return Ok; 34 | } 35 | 36 | on(Connect) { 37 | peer_qid = payload->peer_qid; 38 | peer_id = payload->peer_id; 39 | printf(cyan "Connected " cdefault "to %d\n", peer_id); 40 | return Ok; 41 | } 42 | 43 | on (Message) { // message from peer 44 | printf(cyan "Recived " cdefault "%s\n", *payload); 45 | return Ok; 46 | } 47 | 48 | on(Error) { // on server error 49 | switch (*payload) { 50 | case Ok: break; 51 | case server_full: printf("Server is full.\n"); break; 52 | case bad_id: printf("Bad id.\n"); break; 53 | case bad_qid: printf("Bad qid.\n"); break; 54 | case self: printf("You can not connect to " yellow "yourself" cdefault ".\n"); break; 55 | case self_occupied: printf("You are currently " red "occupied" cdefault ";" cyan " Disconnect " cdefault "first.\n"); break; 56 | case occupied: printf("Client you'r trying to connect to is " red "occupied" cdefault "client.\n"); break; 57 | } 58 | return Ok; 59 | } 60 | 61 | #endif -------------------------------------------------------------------------------- /cw07/zad1/worker.h: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include 3 | 4 | long int now() { 5 | static struct timespec ts; 6 | clock_gettime(CLOCK_MONOTONIC, &ts); 7 | return ts.tv_sec * 1000000 + ts.tv_nsec / 1000; 8 | } 9 | 10 | #define log(x, args...) printf("(%d %ld) " x "\n", getpid(), now(), args); 11 | 12 | #define find(mem, x) \ 13 | ({ \ 14 | struct package *y = 0; \ 15 | for (int i = 0; i < MAX_PACKAGES; i++) \ 16 | if (mem->packages[i].x) { \ 17 | y = mem->packages + i; \ 18 | break; \ 19 | } \ 20 | y; \ 21 | }) 22 | #define update(shared, package, from, to) \ 23 | { \ 24 | shared->from -= 1; \ 25 | shared->to += 1; \ 26 | package->status = to; \ 27 | } 28 | 29 | #define worker void worker_fn() 30 | void worker_fn(); 31 | 32 | int shmid, semid; 33 | int main() { 34 | key_t key = ftok(HOME_PATH, PROJECT_ID); 35 | shmid = shmget(key, 0, PERMISSIONS); 36 | assert(shmid != -1); 37 | 38 | shared = shmat(shmid, NULL, 0); 39 | assert(shared != NULL); 40 | 41 | semid = semget(key, 0, PERMISSIONS); 42 | assert(semid != -1); 43 | 44 | worker_fn(); 45 | } 46 | -------------------------------------------------------------------------------- /cw06/zad2/client/events.c: -------------------------------------------------------------------------------- 1 | #ifndef events_c 2 | #define events_c 3 | 4 | #include "logic.c" 5 | 6 | on(Init) { 7 | assert(client_id == 0); // trying to reinitialize client_id is not permited 8 | client_id = payload->id; 9 | return Ok; 10 | } 11 | 12 | on(Stop) { 13 | server_qid = -1; // prevent request to the server at exit 14 | return exit(0), Ok; 15 | } 16 | 17 | on(Disconnect) { 18 | printf(cyan "Disconnected " cdefault "from %d\n", peer_id); 19 | return disconnect(), Ok; 20 | } 21 | 22 | on(List) { 23 | assert(payload->size > 0); 24 | print("id\tstate\n"); 25 | foreach (c, payload->clients, 0, payload->size) { 26 | printf(cdefault "%u\t", c->id); 27 | if (c->id == peer_id) printf(green "peer\n"); 28 | else if (c->id == client_id) printf(yellow "you\n"); 29 | else if (c->available) printf(cdefault "available\n"); 30 | else printf(red "not available\n"); 31 | } 32 | print(cdefault); 33 | return Ok; 34 | } 35 | 36 | on(Connect) { 37 | peer_pid = payload->peer_pid; 38 | peer_qid = mq_open(path(peer_pid), O_WRONLY, QUEUE_PERMISSIONS, QUEUE_ATTR); 39 | peer_id = payload->peer_id; 40 | printf(cyan "Connected " cdefault "to %d\n", peer_id); 41 | return Ok; 42 | } 43 | 44 | on (Message) { // message from peer 45 | printf(cyan "Recived " cdefault "%s\n", *payload); 46 | return Ok; 47 | } 48 | 49 | on(Error) { // on server error 50 | switch (*payload) { 51 | case Ok: break; 52 | case server_full: printf("Server is full.\n"); break; 53 | case bad_id: printf("Bad id.\n"); break; 54 | case bad_qid: printf("Bad qid.\n"); break; 55 | case self: printf("You can not connect to " yellow "yourself" cdefault ".\n"); break; 56 | case self_occupied: printf("You are currently " red "occupied" cdefault ";" cyan " Disconnect " cdefault "first.\n"); break; 57 | case occupied: printf("Client you'r trying to connect to is " red "occupied" cdefault "client.\n"); break; 58 | } 59 | return Ok; 60 | } 61 | 62 | #endif -------------------------------------------------------------------------------- /cw07/zad2/worker.h: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include 3 | 4 | long int now() { 5 | static struct timespec ts; 6 | clock_gettime(CLOCK_MONOTONIC, &ts); 7 | return ts.tv_sec * 1000000 + ts.tv_nsec / 1000; 8 | } 9 | 10 | #define log(x, args...) printf("(%d %ld) " x "\n", getpid(), now(), args); 11 | 12 | #define find(mem, x) \ 13 | ({ \ 14 | struct package *y = 0; \ 15 | for (int i = 0; i < MAX_PACKAGES; i++) \ 16 | if (mem->packages[i].x) { \ 17 | y = mem->packages + i; \ 18 | break; \ 19 | } \ 20 | y; \ 21 | }) 22 | #define update(shared, package, from, to) \ 23 | { \ 24 | shared->from -= 1; \ 25 | shared->to += 1; \ 26 | package->status = to; \ 27 | } 28 | 29 | #define worker void worker_fn() 30 | void worker_fn(); 31 | 32 | int shmid; 33 | sem_t *sem; 34 | void at_exit() { 35 | munmap(shared, sizeof(struct shared)); 36 | sem_close(sem); 37 | } 38 | 39 | int main() { 40 | atexit(at_exit); 41 | signal(SIGINT, exit); 42 | shmid = shm_open("/shared", O_RDWR, PERMISSIONS); 43 | assert(shmid != -1); 44 | 45 | shared = mmap(0, sizeof(struct shared), PROT_READ | PROT_WRITE, MAP_SHARED, shmid, 0); 46 | assert(shared != NULL); 47 | 48 | sem = sem_open("/shared", 0); 49 | assert(sem != NULL); 50 | 51 | worker_fn(); 52 | } 53 | -------------------------------------------------------------------------------- /cw02/zad1/util.c: -------------------------------------------------------------------------------- 1 | #ifndef util 2 | #define util 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | typedef unsigned int uint; 17 | 18 | static char* buffer = 0; 19 | static uint buffer_size = 0; 20 | static uint word_size, word_count; 21 | static const uint new_line_size = 1; 22 | 23 | #define min(a, b) a > b ? b : a 24 | #define max(a, b) a > b ? a : b 25 | 26 | #define use(type, var_name, count, code_block){\ 27 | type* var_name = calloc(count, sizeof(type));\ 28 | uint var_name##_size = count;\ 29 | code_block\ 30 | free(var_name);\ 31 | } 32 | 33 | #define panic(str, args...) {\ 34 | fprintf(stderr, "%s:%i ", __func__, __LINE__);\ 35 | fprintf(stderr, str, args);\ 36 | fprintf(stderr, ".\n");\ 37 | exit(1);\ 38 | } 39 | 40 | #define arg(i, default) argc <= i ? default : argv[i] 41 | 42 | static struct tms tms_start, tms_end; 43 | static clock_t clock_start, clock_end; 44 | 45 | // real time, sys time, user time 46 | #define time_it(code_block) {\ 47 | clock_start = times(&tms_start);\ 48 | code_block\ 49 | clock_end = times(&tms_end);\ 50 | printf("%ld\t%ld\t%ld\n", clock_end - clock_start, tms_end.tms_stime - tms_start.tms_stime, tms_end.tms_utime - tms_start.tms_utime);\ 51 | } 52 | 53 | 54 | void generate_word(char *word_buffer, uint word_size) { 55 | for (uint i = 0; i < word_size; i++) 56 | word_buffer[i] = 'a' + (rand() % ('z' - 'a')); 57 | } 58 | 59 | void generate(char *file, uint word_size, uint word_count) { 60 | int fd = open(file, O_WRONLY | O_CREAT | O_TRUNC); 61 | if (fd < 0) panic("Can not open file '%s': %s", file, strerror(errno)); 62 | 63 | use(char, word_buffer, word_size + 1, { 64 | word_buffer[word_size] = '\n'; 65 | for (uint i = 0; i < word_count; i++) { 66 | generate_word(word_buffer, word_size); 67 | write(fd, word_buffer, word_buffer_size); 68 | } 69 | }); 70 | 71 | close(fd); 72 | } 73 | 74 | #endif -------------------------------------------------------------------------------- /cw03/zad3/worker.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "matrix.c" 13 | 14 | char 15 | A_file_path[PATH_MAX], 16 | B_file_path[PATH_MAX], 17 | C_file_path[PATH_MAX]; 18 | 19 | void worker(char* list_file, uint id, uint workers, bool use_flock) { 20 | FILE* list = fopen(list_file, "r"); 21 | int multiplied = 0; 22 | int ipc = open("ipc", O_CREAT | O_RDWR, 0644); 23 | lseek(ipc, id * sizeof(int), SEEK_SET); 24 | write(ipc, &multiplied, sizeof(int)); 25 | 26 | while (fscanf(list, "%s %s %s\n", A_file_path, B_file_path, C_file_path) == 3) { 27 | int b_fd = open(B_file_path, O_RDONLY, 0644); 28 | uint rows, cols; 29 | read_size(b_fd, &rows, &cols); 30 | 31 | int cols_to_process = cols / workers + (cols % workers ? 1 : 0); 32 | int min_col = cols_to_process * id; 33 | int max_col = min(cols_to_process + min_col, cols - 1) - 1; 34 | if (max_col < min_col) { 35 | close(b_fd); 36 | continue; 37 | } 38 | 39 | matrix* A = open_matrix(A_file_path); 40 | matrix* B = open_partial(b_fd, min_col, max_col, rows, cols); 41 | matrix* C = multiply(A, B); 42 | 43 | if (use_flock) { 44 | int fd = open(C_file_path, O_CREAT | O_RDWR, 0644); 45 | dump_to_file(fd, min_col, cols, id, C); 46 | close(fd); 47 | } 48 | else dump_to_fragment_file(C_file_path, cols, id, C); 49 | 50 | free_matrix(A); 51 | free_matrix(B); 52 | free_matrix(C); 53 | multiplied++; 54 | lseek(ipc, id * sizeof(int), SEEK_SET); 55 | write(ipc, &multiplied, sizeof(int)); 56 | } 57 | 58 | exit((multiplied << 1) | 1); 59 | } 60 | 61 | void time_manager(char* list_file, uint id, uint workers, bool use_flock, uint time_limit, uint mem_limit) { 62 | struct rlimit cpu, mem; 63 | cpu.rlim_cur = time_limit; 64 | cpu.rlim_max = time_limit; 65 | mem.rlim_cur = mem_limit; 66 | mem.rlim_max = mem_limit; 67 | setrlimit(RLIMIT_CPU, &cpu); 68 | setrlimit(RLIMIT_AS, &mem); 69 | 70 | worker(list_file, id, workers, use_flock); 71 | } -------------------------------------------------------------------------------- /cw01/zad3a/main.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | #include 3 | #include 4 | #ifdef dynamic 5 | #include 6 | #endif 7 | 8 | static struct tms tms_start, tms_end; 9 | static clock_t clock_start, clock_end; 10 | 11 | #define time_it(name, code_block)\ 12 | clock_start = times(&tms_start);\ 13 | code_block\ 14 | clock_end = times(&tms_end);\ 15 | printf("\n%s\n", name);\ 16 | printf("real time: %ld\n", clock_end - clock_start);\ 17 | printf(" sys time: %ld\n", tms_end.tms_stime - tms_start.tms_stime);\ 18 | printf("user time: %ld\n", tms_end.tms_utime - tms_start.tms_utime) 19 | 20 | int main(int argc, char **argv) { 21 | 22 | #ifdef dynamic 23 | void* handle = dlopen("./libdiff.so", RTLD_NOW); 24 | if( !handle ) { 25 | fprintf(stderr, "dlopen() %s\n", dlerror()); 26 | exit(1); 27 | } 28 | table* (*create_table)(int) = dlsym(handle, "create_table"); 29 | void (*compare_file_sequence)(table*, char**) = dlsym(handle, "compare_file_sequence"); 30 | void (*remove_block)(table*, int) = dlsym(handle, "remove_block"); 31 | void (*remove_operation)(table*, int, int) = dlsym(handle, "remove_operation"); 32 | #endif 33 | 34 | table* main_table = NULL; 35 | 36 | for (int i = 1; i < argc; i++) { 37 | char* arg = argv[i]; 38 | 39 | if(strcmp(arg, "create_table") == 0) { 40 | if (main_table) free(main_table); 41 | int size = atoi(argv[++i]); 42 | main_table = create_table(size); 43 | } 44 | 45 | else if (strcmp(arg, "compare_pairs") == 0) { 46 | time_it("compare_pairs", { 47 | compare_file_sequence(main_table, argv + i + 1); 48 | }); 49 | i = i + main_table->size; 50 | } 51 | 52 | else if (strcmp(arg, "remove_block") == 0) { 53 | int block_index = atoi(argv[++i]); 54 | time_it("remove_block", { 55 | remove_block(main_table, block_index); 56 | }); 57 | } 58 | 59 | else if (strcmp(arg, "remove_operation") == 0) { 60 | int block_index = atoi(argv[++i]); 61 | int operation_index = atoi(argv[++i]); 62 | time_it("remove_operation", { 63 | remove_operation(main_table, block_index, operation_index); 64 | }); 65 | } 66 | 67 | } 68 | return 0; 69 | } -------------------------------------------------------------------------------- /cw01/zad3b/main.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | #include 3 | #include 4 | #ifdef dynamic 5 | #include 6 | #endif 7 | 8 | static struct tms tms_start, tms_end; 9 | static clock_t clock_start, clock_end; 10 | 11 | #define time_it(name, code_block)\ 12 | clock_start = times(&tms_start);\ 13 | code_block\ 14 | clock_end = times(&tms_end);\ 15 | printf("\n%s\n", name);\ 16 | printf("real time: %ld\n", clock_end - clock_start);\ 17 | printf(" sys time: %ld\n", tms_end.tms_stime - tms_start.tms_stime);\ 18 | printf("user time: %ld\n", tms_end.tms_utime - tms_start.tms_utime) 19 | 20 | int main(int argc, char **argv) { 21 | 22 | #ifdef dynamic 23 | 24 | void* handle = dlopen("./libdiff.so", RTLD_NOW); 25 | if( !handle ) { 26 | fprintf(stderr, "dlopen() %s\n", dlerror()); 27 | exit(1); 28 | } 29 | table* (*create_table)(int) = dlsym(handle, "create_table"); 30 | void (*compare_file_sequence)(table*, char**) = dlsym(handle, "compare_file_sequence"); 31 | void (*remove_block)(table*, int) = dlsym(handle, "remove_block"); 32 | void (*remove_operation)(table*, int, int) = dlsym(handle, "remove_operation"); 33 | 34 | #endif 35 | 36 | table* main_table = NULL; 37 | 38 | for (int i = 1; i < argc; i++) { 39 | char* arg = argv[i]; 40 | 41 | if(strcmp(arg, "create_table") == 0) { 42 | if (main_table) free(main_table); 43 | int size = atoi(argv[++i]); 44 | main_table = create_table(size); 45 | } 46 | 47 | else if (strcmp(arg, "compare_pairs") == 0) { 48 | time_it("compare_pairs", { 49 | compare_file_sequence(main_table, argv + i + 1); 50 | }); 51 | i = i + main_table->size; 52 | } 53 | 54 | else if (strcmp(arg, "remove_block") == 0) { 55 | int block_index = atoi(argv[++i]); 56 | time_it("remove_block", { 57 | remove_block(main_table, block_index); 58 | }); 59 | } 60 | 61 | else if (strcmp(arg, "remove_operation") == 0) { 62 | int block_index = atoi(argv[++i]); 63 | int operation_index = atoi(argv[++i]); 64 | time_it("remove_operation", { 65 | remove_operation(main_table, block_index, operation_index); 66 | }); 67 | } 68 | 69 | } 70 | return 0; 71 | } -------------------------------------------------------------------------------- /cw06/zad1/client/main.c: -------------------------------------------------------------------------------- 1 | #define CLIENT 2 | #include "events.c" 3 | #include 4 | 5 | def init { // this code runs at the start of the program 6 | key_t server_key = ftok(SERVER_KEY_PATHNAME, PROJECT_ID); 7 | assert(server_key != -1); 8 | 9 | server_qid = msgget(server_key, QUEUE_PERMISSIONS); 10 | assert(server_qid != -1); 11 | 12 | client_qid = msgget(IPC_PRIVATE, QUEUE_PERMISSIONS); 13 | assert(client_qid != -1); 14 | 15 | sendi(Init, server_qid, { client_qid }); 16 | recive (client_qid) 17 | switch(msg.mtype) { 18 | handle(Init) 19 | case Error: 20 | print(left(100) "Init: " clearline() red "ERROR " cdefault); 21 | on_Error(&msg.payload.response.Error); 22 | exit(0); 23 | } 24 | assert(client_id != 0); 25 | assert(fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK) != -1); 26 | } 27 | 28 | def finish { // this code runs atexit and on SIGINT 29 | sendi(Stop, server_qid, { client_qid }); 30 | msgctl(client_qid, IPC_RMID, NULL); 31 | } 32 | 33 | def event_loop { 34 | char action_str[10]; 35 | 36 | repeat { 37 | if (scanf("%s %99[^\n]", action_str, msg.payload.response.Message) > 0) { 38 | switch(parse_msg_t(action_str)) { 39 | case List: sendi(List, server_qid, { client_qid }); break; 40 | case Stop: sendi(Stop, server_qid, { client_qid }); break; 41 | case Disconnect: sendi(Disconnect, server_qid, { client_qid }); break; 42 | case Connect: 43 | peer_id = atoi(msg.payload.response.Message); 44 | sendi(Connect, server_qid, { client_qid, peer_id }); 45 | break; 46 | case Message: 47 | if (peer_qid) { 48 | msg.mtype = Message; 49 | msgsnd(peer_qid, &msg, MAX_MESSAGE, 0); 50 | } else print(red "Not connected\n" cdefault); 51 | break; 52 | default: 53 | print(red "Invalid action\n" cdefault); 54 | break; 55 | } 56 | } 57 | recive_async (client_qid) { 58 | switch(msg.mtype) { 59 | handle(Stop) 60 | handle(Disconnect) 61 | handle(List) 62 | handle(Connect) 63 | handle(Error) 64 | handle(Message) 65 | } 66 | } 67 | usleep(250); 68 | } 69 | } -------------------------------------------------------------------------------- /cw09/readme.md: -------------------------------------------------------------------------------- 1 | # Zadania - Zestaw 9 2 | 3 | Opis problemu: 4 | W ramach zadania należy zaimplementować rozwiązanie problemu śpiącego golibrody. 5 | Salon składa się z gabinetu oraz poczekalni. W gabinecie znajduje się jedno krzesło dla aktualnie obsługiwanego klienta. W poczekalni znajduje się określona liczba krzeseł (K) dla oczekujących. 6 | 7 | Zachowania golibrody: 8 | 9 | - Gdy kończy golić brodę klienta, pozwala mu opuścić gabinet, po czym idzie do poczekalni sprawdzić, czy jakiś klient tam czeka: 10 | - Jeśli tak, przyprowadza go do gabinetu, sadza na krześle i goli jego brodę. (Komunikat: Golibroda: czeka ___ klientow, gole klienta ID) 11 | - Jeśli nie, to idzie spać. (Komunikat: Golibroda: ide spac) 12 | 13 | Zachowanie klientów: 14 | 15 | - Jeśli przyszedł do salonu, golibroda jest zajęty oraz wszystkie krzesła w poczekalni są zajęte to wychodzi. (Komunikat: Zajete; ID) 16 | - Jeśli przyszedł do salonu i golibroda jest zajęty, ale są wolne miejsca w poczekalni to zajmuje jedno z krzeseł. (Komunikat: Poczekalnia, wolne miejsca: ___; ID) 17 | - Jeśli przyszedł do salonu i golibroda śpi to go budzi i zajmuje krzesło w gabinecie. (Komunikat: Budze golibrode; ID) 18 | 19 | Należy zaimplementować program, w którym golibroda oraz klienci to osobne wątki. Powinny one podczas działania wypisywać komunikaty o podejmowanych akcjach. Użycie odpowiednich mechanizmów ma zagwarantować niedopouszczenie, np. do zdarzeń: 20 | 21 | - W których dwóch klientów zajmuje jedno krzesło w poczekalni. 22 | - Golibroda śpi, choć jest klient w poczekalni. 23 | 24 | Golenie brody przez golibrode powinno zajmować mu losową liczbę sekund. Do spania golibrody powinny być wykorzystane Warunki Sprawdzające (Condition Variables). 25 | Gdy klient wychodzi z salonu z powodu braku miejsca w poczekalni, powinien odczekać losową liczbe sekund i spróbować wejść jeszcze raz. 26 | 27 | Program należy zaimplementować korzystając z wątków i mechanizmów synchronizacji biblioteki POSIX Threads. Argumentami wywołania programu są: liczba krzeseł K i liczba klientów N. Po uruchomieniu programu wątek główny tworzy wątki dla golibrody i dla klientów (dla klientów wątki powinny być tworzone z losowym opóźnieniem). Należy doprowadzić do sytuacji w której wszystkie krzesła w poczekalni są zajęte. -------------------------------------------------------------------------------- /cw10/readme.md: -------------------------------------------------------------------------------- 1 | # Zadania - Zestaw 10 2 | ## Celem zadania jest napisanie prostego systemu pozwalającego na granie w kółko i krzyżyk w architekturze klient/serwer. 3 | 4 | Serwer nasłuchuje jednocześnie na gnieździe sieciowym i gnieździe lokalnym. 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 | Serwer ma za zadanie łączyć klientów w pary - w przypadku pierwszego klienta wysyła mu informacje o tym, że oczekuje na drugiego klienta. Gdy drugi klient dołączy się do serwera informuje ich o połączeniu w parę, losuje zaczynającego gracza i wysyła do nich pustą planszę wraz z informacją o przydzielonym znaku (X/O). 7 | Klienci następnie na zmianę wykonują ruchy aż do wygranej lub remisu - wybór pól może być wykonany poprzez ich numeracje (1-9). Wiadomości o ruchach powinny być wysyłane do serwera, który je przekaże drugiemu klientowi. Po zakończonej rozgrywce klient powinien wyrejestrować się z serwera. 8 | 9 | Serwer przyjmuje jako swoje argumenty: 10 | 11 | - numer portu TCP/UDP (zależnie od zadania) 12 | - ścieżkę gniazda UNIX 13 | 14 | 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 (epoll/poll/select). 15 | 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. 16 | Można przyjąć, że ilość klientów zarejestrowanych na serwerze jest ograniczona do maksymalnie kilkunastu. 17 | 18 | 19 | Klient przyjmuje jako swoje argumenty: 20 | 21 | - swoją nazwę (string o z góry ograniczonej długości) 22 | - sposób połączenia z serwerem (sieć lub komunikacja lokalna przez gniazda UNIX) 23 | - adres serwera (adres IPv4 i numer portu lub ścieżkę do gniazda UNIX serwera) 24 | 25 | Klient przy wyłączeniu Ctrl+C powinien wyrejestrować się z serwera. 26 | 27 | 28 | Zadanie 1 (50%) 29 | Komunikacja klientów i serwera odbywa się z użyciem protokołu strumieniowego. 30 | 31 | Zadanie 2 (50%) 32 | Komunikacja klientów i serwera odbywa się z użyciem protokołu datagramowego. -------------------------------------------------------------------------------- /cw03/zad2/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "worker.c" 13 | #define list_file argv[1] 14 | 15 | int main(int argc, char** argv) { 16 | 17 | int processes = atoi(argv[2]), status; 18 | bool use_flock = strcmp(argv[4], "flock") == 0; 19 | int time_limit = atoi(argv[3]); 20 | pid_t pid; 21 | 22 | for (int id = 0; id < processes; id++) 23 | if (fork() == 0) time_manager(list_file, id, processes, use_flock, time_limit); 24 | 25 | bool all_ok = true; 26 | while((pid = wait(&status)) != -1) { 27 | int mult = WEXITSTATUS(status); 28 | bool ok = mult & 1; 29 | if (!ok) all_ok = false; 30 | int time = mult >> 1; 31 | printf("pid(%i)\tmultiplied(%i)\tok(%s)\n", pid, time, ok ? "true" : "false"); 32 | } 33 | 34 | if (!all_ok) { 35 | printf("Some process have reached their limits."); 36 | return 0; 37 | } 38 | if (use_flock) return 0; 39 | 40 | // merge files with paste 41 | FILE* list = fopen(list_file, "r"); 42 | int out = fileno(stdout); 43 | while(fscanf(list, "%s %s %s\n", A_file_path, B_file_path, C_file_path) == 3) { 44 | int fd = open(B_file_path, O_RDONLY); 45 | uint rows, cols; 46 | read_size(fd, &rows, &cols); 47 | 48 | int cols_to_process = cols / processes + (cols % processes ? 1 : 0); 49 | int argc = cols / cols_to_process + (cols % cols_to_process ? 1 : 0); 50 | char** argv = malloc((argc + 2) * sizeof(char*)); 51 | int len = strlen(C_file_path) + 14; // max_int size with sign is 12 + '-' + terminator 52 | argv[0] = "paste"; 53 | for (int i = 1; i <= argc; i++) { 54 | argv[i] = calloc(len, sizeof(char)); 55 | sprintf(argv[i], "%s-%i", C_file_path, i - 1); 56 | } 57 | close(fd); 58 | fd = open(C_file_path, O_RDWR | O_CREAT | O_TRUNC, 0644); 59 | dup2(fd, out); 60 | if (fork() == 0) execvp("paste", argv); 61 | wait(NULL); 62 | if (fork() == 0) execvp("rm", argv); 63 | wait(NULL); 64 | 65 | for (int i = 1; i <= argc; i++) free(argv[i]); 66 | free(argv); 67 | 68 | dprintf(fd, "%11u\t%11u\n", rows, cols); 69 | 70 | close(fd); 71 | } 72 | 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /cw03/zad2/worker.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "matrix.c" 12 | 13 | char 14 | A_file_path[PATH_MAX], 15 | B_file_path[PATH_MAX], 16 | C_file_path[PATH_MAX]; 17 | 18 | void worker(char* list_file, uint id, uint workers, bool use_flock) { 19 | FILE* list = fopen(list_file, "r"); 20 | int multiplied = 0, tmp; 21 | int ipc = open("ipc", O_CREAT | O_RDWR, 0644); 22 | lseek(ipc, id * sizeof(int), SEEK_SET); 23 | write(ipc, &multiplied, sizeof(int)); 24 | 25 | while (fscanf(list, "%s %s %s\n", A_file_path, B_file_path, C_file_path) == 3) { 26 | int b_fd = open(B_file_path, O_RDONLY, 0644); 27 | uint rows, cols; 28 | read_size(b_fd, &rows, &cols); 29 | 30 | int cols_to_process = cols / workers + (cols % workers ? 1 : 0); 31 | int min_col = cols_to_process * id; 32 | int max_col = min(cols_to_process + min_col, cols - 1) - 1; 33 | if (max_col < min_col) { 34 | close(b_fd); 35 | continue; 36 | } 37 | 38 | matrix* A = open_matrix(A_file_path); 39 | matrix* B = open_partial(b_fd, min_col, max_col, rows, cols); 40 | matrix* C = multiply(A, B); 41 | 42 | if (use_flock) { 43 | int fd = open(C_file_path, O_CREAT | O_RDWR, 0644); 44 | dump_to_file(fd, min_col, cols, id, C); 45 | close(fd); 46 | } 47 | else dump_to_fragment_file(C_file_path, cols, id, C); 48 | 49 | free_matrix(A); 50 | free_matrix(B); 51 | free_matrix(C); 52 | multiplied++; 53 | 54 | tmp = multiplied << 1; 55 | lseek(ipc, id * sizeof(int), SEEK_SET); 56 | write(ipc, &tmp, sizeof(int)); 57 | } 58 | 59 | tmp = (multiplied << 1) | 1; 60 | lseek(ipc, id * sizeof(int), SEEK_SET); 61 | write(ipc, &tmp, sizeof(int)); 62 | } 63 | 64 | void time_manager(char* list_file, uint id, uint workers, bool use_flock, uint time_limit) { 65 | if (fork() == 0) { 66 | sleep(time_limit); 67 | exit(0); 68 | } 69 | if (fork() == 0) { 70 | worker(list_file, id, workers, use_flock); 71 | exit(0); 72 | } 73 | 74 | wait(NULL); 75 | int ipc = open("ipc", O_RDONLY, 0644), ret; 76 | lseek(ipc, id * sizeof(int), 1); 77 | read(ipc, &ret, sizeof(int)); 78 | 79 | exit(ret); 80 | } -------------------------------------------------------------------------------- /cw06/zad2/client/main.c: -------------------------------------------------------------------------------- 1 | #define CLIENT 2 | #include "events.c" 3 | #include 4 | #include 5 | 6 | char client_path[15]; 7 | def init { // this code runs at the start of the program 8 | server_qid = mq_open(SERVER_PATH, O_RDWR, QUEUE_PERMISSIONS, NULL); 9 | assert(server_qid != -1); 10 | 11 | pid_t pid = getpid(); 12 | sprintf(client_path, "/c%d", pid); 13 | client_qid = mq_open(client_path, O_CREAT | O_RDWR | O_EXCL, QUEUE_PERMISSIONS, QUEUE_ATTR); 14 | assert(client_qid != -1); 15 | 16 | sendi(Init, server_qid, { pid }); 17 | recive (client_qid) switch(msg.mtype) { 18 | handle(Init); 19 | case Error: 20 | exit(0); 21 | } 22 | assert(client_id != 0); 23 | assert(fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK) != -1); 24 | } 25 | 26 | def finish { // this code runs atexit and on SIGINT 27 | send0(Stop, server_qid); 28 | mq_close(server_qid); 29 | 30 | mq_close(client_qid); 31 | mq_unlink(client_path); 32 | } 33 | 34 | def event_loop { 35 | struct mq_attr async, old; 36 | async.mq_flags = O_NONBLOCK; 37 | mq_getattr(client_qid, &old); 38 | mq_setattr(client_qid, &async, &old); 39 | char action_str[10]; 40 | 41 | repeat { 42 | if (scanf("%s %99[^\n]", action_str, msg.payload.response.Message) > 0) { 43 | switch(parse_msg_t(action_str)) { 44 | case List: sendi(List, server_qid, { client_id }); break; 45 | case Stop: sendi(Stop, server_qid, { client_id }); break; 46 | case Disconnect: sendi(Disconnect, server_qid, { client_id }); break; 47 | case Connect: 48 | peer_id = atoi(msg.payload.response.Message); 49 | sendi(Connect, server_qid, { client_id, peer_id }); 50 | break; 51 | case Message: 52 | if (peer_qid) { 53 | msg.mtype = Message; 54 | mq_send(peer_qid, (char*) &msg, MAX_MESSAGE, 0); 55 | } else print(red "Not connected\n" cdefault); 56 | break; 57 | default: 58 | print(red "Invalid action\n" cdefault); 59 | break; 60 | } 61 | } 62 | recive_async (client_qid) { 63 | switch(msg.mtype) { 64 | handle(Stop) 65 | handle(Disconnect) 66 | handle(List) 67 | handle(Connect) 68 | handle(Error) 69 | handle(Message) 70 | } 71 | } 72 | usleep(250); 73 | } 74 | } -------------------------------------------------------------------------------- /cw07/readme.md: -------------------------------------------------------------------------------- 1 | # Zestaw 7 2 | Wykorzystując semafory i pamięć wspólną z IPC Systemu V napisz program symulujący działanie sklepu wysyłkowego. 3 | W sklepie wysyłkowym pracują 3 typy pracowników: 4 | 1) odbierający zamówienie oraz przygotowujący odpowiednie paczki 5 | 2) pakujący zamówienie do paczki 6 | 3) zaklejający paczki oraz wysyłający je kurierem 7 | 8 | Po uruchomieniu, pracownik 1) cyklicznie odbiera zamównienia - losuje dodatnią liczbę całkowitą (wielkość zamówienia/paczki) i umieszcza ją w tablicy przechowywanej w pamięci wspólnej. Po odebraniu nowego zamównienia pracownik 1) wypisuje na ekranie komunikat postaci: 9 | 10 | (pid timestamp) Dodałem liczbę : n. Liczba zamównień do przygotowania: m. Liczba zamównień do wysłania: x. 11 | 12 | gdzie pid to PID procesu pracownika 1), timestamp to aktualny czas (z dokładnością do milisekund), n to wylosowana liczba (wielkość zamówienia), m to liczba zamównień do przygotowania w pamięci wspólnej (licząc z utworzonym zamówieniem), a x to liczba zamównień do wysłania w pamięci wspólnej. 13 | 14 | Po pobraniu zamówienia pracownik 2) pomnaża liczbę przez 2 i wypisuje na ekranie komunikat: 15 | 16 | (pid timestamp) Przygotowałem zamówienie o wielkości n. Liczba zamównień do przygotowania: m. Liczba zamównień do wysłania: x. 17 | 18 | gdzie n to liczba pomnożona przez 2, a m jest bez aktualnie przygotowanego. 19 | 20 | Po pobraniu przygotowanego zamówienia pracownik 3) pomnaża liczbę przez 3 i wypisuje na ekranie komunikat: 21 | 22 | (pid timestamp) Wysłałem zamówienie o wielkości n. Liczba zamównień do przygotowania: m. Liczba zamównień do wysłania: x. 23 | 24 | gdzie n to liczba pomnożona przez 3, a x jest bez aktualnie wysłanego. 25 | 26 | Zakładamy, że równocześnie pracuje wielu pracowników 1), 2) i 3). Rozmiar tablicy z zamówieniami (w pamięci wspólnej) jest ograniczony i ustalony na etapie kompilacji. Tablica ta indeksowana jest w sposób cykliczny - po dodaniu zamówienia na końcu tablicy, kolejne zamówienia dodawane są od indeksu 0. Korzystając w odpowiedni sposób z semaforów należy zagwarantować, że liczba oczekujących zamówień nie przekroczy rozmiaru tablicy oraz że tablica nie będzie modyfikowana przez kilka procesów równocześnie. Rozmiar tablicy zamówień dobierz tak, aby mogła zajść sytuacja, w której tablica jest całkowicie zapełniona. W pamięci wspólnej oprócz tablicy można przechowywać także inne dane dzielone pomiędzy procesami. 27 | Kolejni pracownicy są uruchamiani w pętli przez jeden proces macierzysty (za pomocą funkcji fork oraz exec). 28 | 29 | Zrealizuj powyższy problem synchronizacyjny , wykorzystując mechanizmy synchronizacji procesów oraz pamięć współdzieloną ze standardu: 30 | 31 | 1) IPC - System V (50%) 32 | 2) IPC - Posix (50%) -------------------------------------------------------------------------------- /cw03/zad3/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "worker.c" 13 | #define list_file argv[1] 14 | 15 | long int usage_time(struct timeval * t){ 16 | return (long int)t->tv_sec * 1000000 + (long int)t->tv_usec; 17 | } 18 | 19 | void report_usage(struct rusage usage1, struct rusage usage2){ 20 | long int user = abs(usage_time(&usage2.ru_utime) - usage_time(&usage1.ru_stime)); 21 | long int system = abs(usage_time(&usage2.ru_stime) - usage_time(&usage1.ru_stime)); 22 | printf("CPU:\t\tuser(%lf)\tsystem(%lf)\n\n", (double)user / 1000000, (double)system / 1000000); 23 | } 24 | 25 | int main(int argc, char** argv) { 26 | 27 | int processes = atoi(argv[2]), status; 28 | int time_limit = atoi(argv[3]); 29 | int mem_limit = 1048576 * atoi(argv[4]); 30 | bool use_flock = strcmp(argv[5], "flock") == 0; 31 | pid_t pid; 32 | 33 | for (int id = 0; id < processes; id++) 34 | if (fork() == 0) time_manager(list_file, id, processes, use_flock, time_limit, mem_limit); 35 | 36 | struct rusage usage1, usage2; 37 | getrusage(RUSAGE_CHILDREN, &usage1); 38 | bool all_ok = true; 39 | while((pid = wait(&status)) != -1) { 40 | getrusage(RUSAGE_CHILDREN, &usage2); 41 | int mult = WEXITSTATUS(status); 42 | bool ok = mult & 1; 43 | if (!ok) all_ok = false; 44 | int time = mult >> 1; 45 | printf("pid(%i)\tmultiplied(%i)\tok(%s)\n", pid, time, ok ? "true" : "false"); 46 | report_usage(usage1, usage2); 47 | } 48 | 49 | if (!all_ok) { 50 | printf("Some process have reached their limits."); 51 | return 0; 52 | } 53 | if (use_flock) return 0; 54 | 55 | // merge files with paste 56 | FILE* list = fopen(list_file, "r"); 57 | int out = fileno(stdout); 58 | while(fscanf(list, "%s %s %s\n", A_file_path, B_file_path, C_file_path) == 3) { 59 | int fd = open(B_file_path, O_RDONLY); 60 | uint rows, cols; 61 | read_size(fd, &rows, &cols); 62 | 63 | int cols_to_process = cols / processes + (cols % processes ? 1 : 0); 64 | int argc = cols / cols_to_process + (cols % cols_to_process ? 1 : 0); 65 | char** argv = malloc((argc + 2) * sizeof(char*)); 66 | int len = strlen(C_file_path) + 14; // max_int size with sign is 12 + '-' + terminator 67 | argv[0] = "paste"; 68 | for (int i = 1; i <= argc; i++) { 69 | argv[i] = calloc(len, sizeof(char)); 70 | sprintf(argv[i], "%s-%i", C_file_path, i - 1); 71 | } 72 | close(fd); 73 | fd = open(C_file_path, O_RDWR | O_CREAT | O_TRUNC, 0644); 74 | dup2(fd, out); 75 | if (fork() == 0) execvp("paste", argv); 76 | if (fork() == 0) execvp("rm", argv); 77 | 78 | for (int i = 1; i <= argc; i++) free(argv[i]); 79 | free(argv); 80 | while(wait(NULL) != -1); 81 | dprintf(fd, "%11u\t%11u\n", rows, cols); 82 | 83 | close(fd); 84 | } 85 | 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /cw06/zad1/common/message.h: -------------------------------------------------------------------------------- 1 | #ifndef message_h 2 | #define message_h 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #define MAX_CLIENTS 10 13 | #define MAX_MESSAGE 100 14 | 15 | typedef int qid_t; 16 | 17 | typedef enum msg_t { 18 | Stop = 1L, 19 | Disconnect = 2L, 20 | List = 3L, 21 | Connect, 22 | Init, 23 | Error, 24 | Message 25 | } msg_t; 26 | 27 | #define parse(x) if (strcmp(c, #x) == 0) return x; 28 | enum msg_t parse_msg_t(char* c) { 29 | if (strcmp(c, "exit") == 0) return Stop; 30 | parse(Stop) 31 | parse(Disconnect) 32 | if (strcmp(c, "ls") == 0) return List; 33 | parse(List) 34 | parse(Connect) 35 | parse(Message) 36 | if (strcmp(c, "Send") == 0) return Message; 37 | if (strcmp(c, "echo") == 0) return Message; 38 | return Error; 39 | } 40 | #undef parse 41 | 42 | typedef enum error_t { 43 | Ok = 0, 44 | server_full, 45 | bad_id, 46 | bad_qid, 47 | occupied, 48 | self_occupied, 49 | self 50 | } error_t; 51 | 52 | struct message { 53 | long mtype; 54 | union payload { 55 | 56 | union request { 57 | struct { qid_t qid; } Init, Stop, Disconnect, List; 58 | struct { qid_t qid; id_t peer_id; } Connect; 59 | char Message[MAX_MESSAGE]; 60 | } request; 61 | 62 | union response { 63 | struct { id_t id; } Init; 64 | struct { id_t peer_id; qid_t peer_qid; } Connect; 65 | struct { } Stop, Disconnect; 66 | struct { 67 | int size; 68 | struct client_info { id_t id; bool available; } clients[MAX_CLIENTS]; 69 | } List; 70 | char Message[MAX_MESSAGE]; 71 | enum error_t Error; 72 | } response; 73 | 74 | } payload; 75 | }; 76 | typedef struct message message; 77 | 78 | #define sendi(type, qid, init...) ({\ 79 | message msg = { type };\ 80 | typeof(msg.payload._SND_T.type) res = init;\ 81 | msg.payload._SND_T.type = res;\ 82 | msgsnd(qid, &msg, sizeof res, 0);\ 83 | }) 84 | #if defined(CLIENT) 85 | #define _SND_T request 86 | #define _RCV_T response 87 | #define handle(type) case type: on_##type(&msg.payload._RCV_T.type); break; 88 | #elif defined(SERVER) 89 | #define _SND_T response 90 | #define _RCV_T request 91 | enum error_t __error; 92 | #define handle(type) case type: if ((__error = on_##type(&msg.payload._RCV_T.type)) != Ok) { on_error(msg.payload._RCV_T.type.qid); } break; 93 | void on_error(qid_t qid) { 94 | sendi(Error, qid, __error); 95 | } 96 | #endif 97 | 98 | 99 | #define send0(type, qid) ({ message msg = { type };\ 100 | msgsnd(qid, &msg, 0, 0); }) 101 | 102 | struct message msg; 103 | #define on(type) enum error_t on_##type(typeof(msg.payload._RCV_T.type)* payload) 104 | #define recive(qid) if (msgrcv(qid, &msg, sizeof msg.payload, -100, 0) == -1) { } else 105 | #define recive_async(qid) for (;msgrcv(qid, &msg, sizeof msg.payload, -100, IPC_NOWAIT) != -1;) 106 | 107 | #endif -------------------------------------------------------------------------------- /cw04/zad2/signal_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "ipc.h" 9 | 10 | #define foreach_ref(var, f) for (var; f >= 0;) 11 | #define case(name, code) case opt_##name##_i: code; break 12 | #define exec(EXE, args...) execl(EXE, EXE, args, NULL); 13 | 14 | static int sig; 15 | bool use_exec = false; 16 | static pid_t ppid; 17 | char* itoa(int value) { 18 | static char buff[12]; 19 | sprintf(buff, "%i", value); 20 | return strdup(buff); 21 | } 22 | 23 | void test_ignore() { 24 | signal(sig, SIG_IGN); 25 | if (fork() == 0) { 26 | if (use_exec) exec("./exec.out", "-i", itoa(sig), itoa(ppid)); 27 | raise(sig); 28 | kill(ppid, CHILD_OK); 29 | } 30 | waitpid(WAIT_ANY, NULL, WUNTRACED); 31 | raise(sig); 32 | kill(ppid, PARENT_OK); 33 | } 34 | 35 | int sig_handler_success = CHILD_OK; 36 | void sig_handler(int _) { kill(ppid, sig_handler_success); } 37 | void test_handler() { 38 | signal(sig, sig_handler); 39 | if (fork() == 0) raise(sig); 40 | waitpid(WAIT_ANY, NULL, WUNTRACED); 41 | sig_handler_success = PARENT_OK; 42 | raise(sig); 43 | } 44 | 45 | void failure_handler(int _) { _exit(0); } 46 | void test_mask() { 47 | sigset_t mask; 48 | sigemptyset(&mask); 49 | sigaddset(&mask, sig); 50 | sigprocmask(SIG_SETMASK, &mask, NULL); 51 | signal(sig, failure_handler); 52 | if (fork() == 0) { 53 | if (use_exec) exec("./exec.out", "-m", itoa(sig), itoa(ppid)); 54 | raise(sig); 55 | kill(ppid, CHILD_OK); 56 | } 57 | waitpid(WAIT_ANY, NULL, WUNTRACED); 58 | raise(sig); 59 | kill(ppid, PARENT_OK); 60 | } 61 | 62 | void test_pending() { 63 | sigset_t newmask; 64 | sigemptyset(&newmask); 65 | sigaddset(&newmask, sig); 66 | sigprocmask(SIG_SETMASK, &newmask, NULL); 67 | 68 | raise(sig); 69 | sigset_t mask; 70 | if (fork() == 0) { 71 | raise(sig); 72 | if (use_exec) exec("./exec.out", "-p", itoa(sig), itoa(ppid)); 73 | sigpending(&mask); 74 | if (sigismember(&mask, sig)) 75 | kill(ppid, CHILD_OK); 76 | } 77 | waitpid(WAIT_ANY, NULL, WUNTRACED); 78 | sigpending(&mask); 79 | if (sigismember(&mask, sig)) kill(ppid, PARENT_OK); 80 | } 81 | 82 | #define opt_signal_i 0 83 | #define opt_ignore_i 1 84 | #define opt_handler_i 2 85 | #define opt_mask_i 3 86 | #define opt_pending_i 4 87 | #define opt_exec_i 5 88 | 89 | const struct option options[] = { 90 | {"signal" , required_argument, 0, 's'}, 91 | {"ignore" , no_argument , 0, 'i'}, 92 | {"handler", no_argument , 0, 'h'}, 93 | {"mask" , no_argument , 0, 'm'}, 94 | {"pending", no_argument , 0, 'p'}, 95 | {"exec" , no_argument , 0, 'e'}, 96 | {0, 0, 0, 0} 97 | }; 98 | 99 | int main(int argc, char** argv) { 100 | ppid = getppid(); 101 | foreach_ref(int opt, getopt_long_only(argc, argv, "", options, &opt)) { 102 | switch (opt) { 103 | case(signal , sig = atoi(optarg)); 104 | case(exec , use_exec = true); 105 | case(pending, test_pending()); 106 | case(handler, test_handler()); 107 | case(ignore , test_ignore()); 108 | case(mask , test_mask()); 109 | } 110 | } 111 | } -------------------------------------------------------------------------------- /cw06/zad2/common/message.h: -------------------------------------------------------------------------------- 1 | #ifndef message_h 2 | #define message_h 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #define MAX_CLIENTS 10 15 | #define MAX_MESSAGE 70 16 | 17 | typedef int qid_t; 18 | 19 | typedef enum msg_t { 20 | Stop = 10, 21 | Disconnect = 9, 22 | List = 8, 23 | Connect = 7, 24 | Init = 6, 25 | Error = 5, 26 | Message = 4 27 | } msg_t; 28 | 29 | #define parse(x) if (strcmp(c, #x) == 0) return x; 30 | enum msg_t parse_msg_t(char* c) { 31 | if (strcmp(c, "exit") == 0) return Stop; 32 | parse(Stop) 33 | parse(Disconnect) 34 | if (strcmp(c, "ls") == 0) return List; 35 | parse(List) 36 | parse(Connect) 37 | parse(Message) 38 | if (strcmp(c, "Send") == 0) return Message; 39 | if (strcmp(c, "echo") == 0) return Message; 40 | return Error; 41 | } 42 | #undef parse 43 | 44 | typedef enum error_t { 45 | Ok = 0, 46 | server_full, 47 | bad_id, 48 | bad_qid, 49 | occupied, 50 | self_occupied, 51 | self 52 | } error_t; 53 | 54 | struct message { 55 | unsigned int mtype; 56 | union payload { 57 | 58 | union request { 59 | struct { id_t id; } Init, Stop, Disconnect, List; 60 | struct { id_t id; id_t peer_id; } Connect; 61 | char Message[MAX_MESSAGE]; 62 | } request; 63 | 64 | union response { 65 | struct { id_t id; } Init; 66 | struct { id_t peer_id; pid_t peer_pid; } Connect; 67 | struct { } Stop, Disconnect; 68 | struct { 69 | int size; 70 | struct client_info { id_t id; bool available; } clients[MAX_CLIENTS]; 71 | } List; 72 | char Message[MAX_MESSAGE]; 73 | enum error_t Error; 74 | } response; 75 | 76 | } payload; 77 | }; 78 | typedef struct message message; 79 | 80 | #if defined(CLIENT) 81 | #define _SND_T request 82 | #define _RCV_T response 83 | #define handle(type) case type: on_##type(&msg.payload._RCV_T.type); break; 84 | #elif defined(SERVER) 85 | #define _SND_T response 86 | #define _RCV_T request 87 | enum error_t __error; 88 | void on_error(id_t id, enum error_t error); 89 | #define handle(type) case type: if ((__error = on_##type(&msg.payload._RCV_T.type)) != Ok) { on_error(msg.payload._RCV_T.type.id, __error); } break; 90 | #endif 91 | 92 | #define sendi(type, qid, init...) ({\ 93 | struct message msg = { type };\ 94 | typeof(msg.payload._SND_T.type) payload = init;\ 95 | msg.payload._SND_T.type = payload;\ 96 | mq_send(qid, (char*) &msg, sizeof payload + sizeof(enum msg_t), type);\ 97 | }) 98 | 99 | #define send0(type, qid) ({\ 100 | struct message msg = { type };\ 101 | mq_send(qid, (char*) &msg, sizeof(enum msg_t), type);\ 102 | }) 103 | 104 | #define QUEUE_ATTR ({\ 105 | struct mq_attr info;\ 106 | info.mq_msgsize = sizeof(message);\ 107 | info.mq_maxmsg = 10;\ 108 | &info;\ 109 | }) 110 | 111 | message msg; 112 | #define on(type) enum error_t on_##type(typeof(msg.payload._RCV_T.type)* payload) 113 | #define recive(qid) if (mq_receive(qid, (char*) &msg, sizeof msg, NULL) == -1) { } else 114 | #define recive_async(qid) for (;mq_receive(qid, (char*) &msg, sizeof msg, NULL) != -1;) 115 | 116 | #endif -------------------------------------------------------------------------------- /cw03/zad2/util.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "matrix.c" 9 | #undef min 10 | #undef max 11 | 12 | int opt_min = 0; 13 | int opt_max = 0; 14 | int opt_count = 1; 15 | char* opt_generate = NULL; 16 | 17 | #define opt_generate_i 0 18 | #define opt_min_i 1 19 | #define opt_max_i 2 20 | #define opt_count_i 3 21 | #define opt_test_i 4 22 | 23 | #define case(name, code) case opt_##name##_i: code; break 24 | 25 | char A_file_path[PATH_MAX], B_file_path[PATH_MAX], C_file_path[PATH_MAX]; 26 | 27 | const struct option options[] = { 28 | {"generate", required_argument, 0, 'g'}, 29 | {"min" , required_argument, 0, 'm'}, 30 | {"max" , required_argument, 0, 'M'}, 31 | {"count" , required_argument, 0, 'c'}, 32 | {"test" , required_argument, 0, 't'}, 33 | {0, 0, 0, 0} 34 | }; 35 | 36 | int test(char* list_file) { 37 | FILE* list = fopen(list_file, "r"); 38 | while(fscanf(list, "%s %s %s\n", A_file_path, B_file_path, C_file_path) == 3) { 39 | matrix* a = open_matrix(A_file_path); 40 | matrix* b = open_matrix(B_file_path); 41 | matrix* c = open_matrix(C_file_path); 42 | 43 | matrix* d = multiply(a, b); 44 | bool matching = true; 45 | for (int row = 0; row < c->rows; row++) 46 | for (int col = 0; col < c->cols; col++) 47 | if (c->values[get_index(c, row, col)] != d->values[get_index(d, row, col)]) { 48 | matching = false; 49 | goto non; 50 | } 51 | non: 52 | printf("%s x %s = %s %s\n", A_file_path, B_file_path, C_file_path, matching ? "true" : "false"); 53 | } 54 | return 0; 55 | } 56 | 57 | int rand_range(int min, int max) { 58 | return rand() % (max - min) + min; 59 | } 60 | 61 | void generate_file(char* path, uint rows, uint cols) { 62 | matrix* m = create_matrix(rows, cols); 63 | int fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0644); 64 | for (int row = 0; row < rows; row++) 65 | for (int col = 0; col < cols; col++) 66 | m->values[get_index(m, row, col)] = rand_range(-100, 100); 67 | 68 | dump_to_file(fd, 0, cols, 0, m); 69 | close(fd); 70 | } 71 | 72 | int generate(char* list_file) { 73 | FILE* file = fopen(list_file, "w+"); 74 | char path[30]; 75 | for (uint i = 0; i < opt_count; i++) { 76 | uint Arows = rand_range(opt_min, opt_max), Acols = rand_range(opt_min, opt_max); 77 | sprintf(path, "data/A%u.txt", i); 78 | generate_file(path, Arows, Acols); 79 | fprintf(file, "%s ", path); 80 | 81 | uint Brows = Acols, Bcols = rand_range(opt_min, opt_max); 82 | sprintf(path, "data/B%u.txt", i); 83 | generate_file(path, Brows, Bcols); 84 | fprintf(file, "%s ", path); 85 | 86 | fprintf(file, "data/C%u.txt\n", i); 87 | } 88 | 89 | return 0; 90 | } 91 | 92 | int main(int argc, char** argv) { 93 | int option, l; 94 | while((option = getopt_long_only(argc, argv, "", options, &l)) >= 0) { 95 | switch (l) { 96 | case(generate, exit(generate(optarg))); 97 | case(min, opt_min = atoi(optarg)); 98 | case(max, opt_max = atoi(optarg)); 99 | case(test, exit(test(optarg))); 100 | case(count, opt_count = atoi(optarg)); 101 | } 102 | } 103 | 104 | return 0; 105 | } -------------------------------------------------------------------------------- /cw03/zad3/util.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "matrix.c" 9 | #undef min 10 | #undef max 11 | 12 | int opt_min = 0; 13 | int opt_max = 0; 14 | int opt_count = 1; 15 | char* opt_generate = NULL; 16 | 17 | #define opt_generate_i 0 18 | #define opt_min_i 1 19 | #define opt_max_i 2 20 | #define opt_count_i 3 21 | #define opt_test_i 4 22 | 23 | #define case(name, code) case opt_##name##_i: code; break 24 | 25 | char A_file_path[PATH_MAX], B_file_path[PATH_MAX], C_file_path[PATH_MAX]; 26 | 27 | const struct option options[] = { 28 | {"generate", required_argument, 0, 'g'}, 29 | {"min" , required_argument, 0, 'm'}, 30 | {"max" , required_argument, 0, 'M'}, 31 | {"count" , required_argument, 0, 'c'}, 32 | {"test" , required_argument, 0, 't'}, 33 | {0, 0, 0, 0} 34 | }; 35 | 36 | int test(char* list_file) { 37 | FILE* list = fopen(list_file, "r"); 38 | while(fscanf(list, "%s %s %s\n", A_file_path, B_file_path, C_file_path) == 3) { 39 | matrix* a = open_matrix(A_file_path); 40 | matrix* b = open_matrix(B_file_path); 41 | matrix* c = open_matrix(C_file_path); 42 | 43 | matrix* d = multiply(a, b); 44 | bool matching = true; 45 | for (int row = 0; row < c->rows; row++) 46 | for (int col = 0; col < c->cols; col++) 47 | if (c->values[get_index(c, row, col)] != d->values[get_index(d, row, col)]) { 48 | matching = false; 49 | goto non; 50 | } 51 | non: 52 | printf("%s x %s = %s %s\n", A_file_path, B_file_path, C_file_path, matching ? "true" : "false"); 53 | } 54 | return 0; 55 | } 56 | 57 | int rand_range(int min, int max) { 58 | return rand() % (max - min) + min; 59 | } 60 | 61 | void generate_file(char* path, uint rows, uint cols) { 62 | matrix* m = create_matrix(rows, cols); 63 | int fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0644); 64 | for (int row = 0; row < rows; row++) 65 | for (int col = 0; col < cols; col++) 66 | m->values[get_index(m, row, col)] = rand_range(-100, 100); 67 | 68 | dump_to_file(fd, 0, cols, 0, m); 69 | close(fd); 70 | } 71 | 72 | int generate(char* list_file) { 73 | FILE* file = fopen(list_file, "w+"); 74 | char path[30]; 75 | for (uint i = 0; i < opt_count; i++) { 76 | uint Arows = rand_range(opt_min, opt_max), Acols = rand_range(opt_min, opt_max); 77 | sprintf(path, "data/A%u.txt", i); 78 | generate_file(path, Arows, Acols); 79 | fprintf(file, "%s ", path); 80 | 81 | uint Brows = Acols, Bcols = rand_range(opt_min, opt_max); 82 | sprintf(path, "data/B%u.txt", i); 83 | generate_file(path, Brows, Bcols); 84 | fprintf(file, "%s ", path); 85 | 86 | fprintf(file, "data/C%u.txt\n", i); 87 | } 88 | 89 | return 0; 90 | } 91 | 92 | int main(int argc, char** argv) { 93 | int option, l; 94 | while((option = getopt_long_only(argc, argv, "", options, &l)) >= 0) { 95 | switch (l) { 96 | case(generate, exit(generate(optarg))); 97 | case(min, opt_min = atoi(optarg)); 98 | case(max, opt_max = atoi(optarg)); 99 | case(test, exit(test(optarg))); 100 | case(count, opt_count = atoi(optarg)); 101 | } 102 | } 103 | 104 | return 0; 105 | } -------------------------------------------------------------------------------- /cw09/zad1/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define MAX_CLIENT_CREATION_OFFSET 3 9 | #define MAX_BARBER_ACTION_TIME 5 10 | #define MAX_CLIENT_RETRY_DELAY 2 11 | 12 | #define repeat(n) for (int i = 0, __size = n; i < __size; i++) 13 | #define loop for(;;) 14 | #define using(mutex) for (int __run = 1; __run && (pthread_mutex_lock(&mutex), 1) ; __run = (pthread_mutex_unlock(&mutex), 0)) 15 | #define find(init, cond) ({ int index = -1; for (init) if (cond) { index = i; break; } index; }) 16 | #define copy(arg) ({ typeof(arg)* copy = malloc(sizeof *copy); *copy = arg; copy; }) 17 | #define p_creat(thread_ptr, fn, arg) pthread_create(thread_ptr, NULL, (void* (*)(void*)) fn, copy(arg)) 18 | 19 | #define LOG1 "\033[47;30m" 20 | #define LOG2 "\033[100;97m" 21 | #define DEF "\033[0m" 22 | #define ENDL "\r\n" 23 | 24 | pthread_mutex_t chair_mutex = PTHREAD_MUTEX_INITIALIZER; 25 | pthread_cond_t barber_cond = PTHREAD_COND_INITIALIZER; 26 | 27 | int client_count, chair_count, free_chairs; 28 | id_t* chairs; 29 | bool barber_sleeping = false; 30 | 31 | void* barber(void* _) { 32 | repeat (client_count) { 33 | using(chair_mutex) { 34 | while (free_chairs == chair_count) { 35 | printf(LOG1" Golibroda "DEF" Idę spać"ENDL); 36 | barber_sleeping = true; 37 | pthread_cond_wait(&barber_cond, &chair_mutex); 38 | } 39 | barber_sleeping = false; 40 | int client_index = find(int i = 0; i < client_count; i++, chairs[i] != 0); 41 | 42 | free_chairs++; 43 | printf(LOG1" Golibroda "DEF" Czeka %d klientow, golę klienta %u"ENDL, chair_count - free_chairs, chairs[client_index]); 44 | chairs[client_index] = 0; 45 | } 46 | 47 | sleep(rand() % MAX_BARBER_ACTION_TIME + 1); 48 | } 49 | printf(LOG1" Golibroda "DEF" Koniec pracy"ENDL); 50 | return NULL; 51 | } 52 | 53 | void* client(id_t* id) { 54 | bool done = false; 55 | loop { 56 | using(chair_mutex) { 57 | if (free_chairs == 0) { 58 | printf(LOG1" Klient "LOG2" %u "DEF" Zajęte"ENDL, *id); 59 | continue; 60 | } 61 | 62 | int free_chair_index = find(int i = 0; i < chair_count; i++, chairs[i] == 0); 63 | chairs[free_chair_index] = *id; 64 | 65 | printf(LOG1" Klient "LOG2" %u "DEF" Poczekalnia, wolne miejsca %d"ENDL, *id, free_chairs); 66 | if (free_chairs == chair_count && barber_sleeping) { 67 | printf(LOG1" Klient "LOG2" %u "DEF" Budze golibrodę"ENDL, *id); 68 | pthread_cond_broadcast(&barber_cond); 69 | } 70 | free_chairs--; 71 | done = true; 72 | } 73 | 74 | if (done) return free(id), NULL; 75 | sleep(rand() % MAX_CLIENT_RETRY_DELAY + 1); 76 | } 77 | } 78 | 79 | int main(int argc, char** argv) { 80 | assert(argc == 3); 81 | 82 | client_count = atoi(argv[1]); 83 | assert(client_count > 0); 84 | 85 | free_chairs = chair_count = atoi(argv[2]); 86 | assert(chair_count > 0); 87 | 88 | srand(time(NULL)); 89 | 90 | chairs = calloc(chair_count, sizeof *chairs); 91 | 92 | pthread_t barber_thread, *client_thread = malloc(client_count * sizeof *client_thread); 93 | pthread_create(&barber_thread, NULL, barber, NULL); 94 | 95 | repeat (client_count) { 96 | p_creat(&client_thread[i], client, i + 1); 97 | sleep(rand() % MAX_CLIENT_CREATION_OFFSET + 1); 98 | } 99 | 100 | repeat (client_count) pthread_join(client_thread[i], NULL); 101 | pthread_join(barber_thread, NULL); 102 | } -------------------------------------------------------------------------------- /cw08/readme.md: -------------------------------------------------------------------------------- 1 | # Wątki - podstawy 2 | 3 | ## Zadanie 1. 4 | 5 | Napisz program współbieżnie wyliczający histogram dla obrazu o wymiarze nxm przy użyciu wątków, zakładając, że obraz jest macierzą reprezentującą obraz. Dla uproszczenia rozważamy jedynie obrazy w 256 odcieniach szarości. Każdy element macierzy jest więc liczbą całkowitą z zakresu 0 do 255. Program należy zaimplementować w różnych wariantach: 6 | 7 | **Wariant 1**: Podział zadania na podzadania odbywa się na zasadzie dekompozycji w dziedzinie problemu, gdzie dziedziną jest zbiór liczb - każdy wątek zlicza wystąpienia dla określonego zestawu liczb. Zbiór liczb dla wątku można przydzielić w dowolny sposób, ale taki, by każdy wątek dostał inne liczby i zadanie było podzielone równo na wszystkie wątki. (30%) 8 | 9 | **Wariant 2**: Podział dokonywany w dziedzinie problemu dotyczącego obrazu, a nie znaków. 10 | 11 | * Podział blokowy – k-ty wątek zlicza 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. (35%) 12 | * Podział cykliczny – k-ty wątek zlicza 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). (35%) 13 | 14 | Program przyjmuje następujące argumenty: 15 | 16 | 1. liczbę wątków, 17 | 2. sposób podziału obrazu pomiędzy wątki, t.j. jedną z trzech opcji: `sign / block / interleaved`, 18 | 3. nazwę pliku z wejściowym obrazem, 19 | 4. nazwę pliku wynikowego. 20 | 21 | Po wczytaniu danych (wejściowy obraz) wątek główny tworzy tyle nowych wątków, ile zażądano w argumencie wywołania. Utworzone wątki równolegle tworzą histogram obrazu. Każdy stworzony wątek odpowiada za wygenerowanie części histogramu obrazu. 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. 22 | 23 | Wątek główny czeka na zakończenie pracy przez wątki wykonujące podzadania. 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 zliczanie (wraz z identyfikatorem zakończonego wątku). Dodatkowo, po zakończeniu pracy przez wszystkie stworzone wątki, wątek główny zapisuje powstały histogram (w formie linii zawierających zliczany odcień oraz liczbę jego wystąpień) do pliku wynikowego i wypisuje na ekranie czas rzeczywisty spędzony na wykonaniu zadania (z dokładnością do mikrosekund). W czasie całkowitym należy uwzględnić narzut związany z utworzeniem i zakończeniem wątków (ale bez czasu operacji wejścia/wyjścia). 24 | 25 | Wykonaj pomiary czasu operacji dla obrazu o rozmiarze kilkaset na kilkaset pikseli. Eksperymenty wykonaj dla wszystkich trzech wariantów podziału obrazu pomiędzy wątki. Testy przeprowadź dla 1, 2, 4, i 8 wątków. Wyniki (czasy dla każdego wątku oraz całkowity czas wykonania zadania w zależności od wariantu) zamieść w pliku Times.txt i dołącz do archiwum z rozwiązaniem zadania. 26 | 27 | ## Format wejścia-wyjścia 28 | Program powinien odczytywać i zapisywać obrazy w formacie ASCII PGM (Portable Gray Map). Pliki w tym formacie mają nagłówek postaci: 29 | 30 | ``` 31 | P2 32 | W H 33 | M 34 | ... 35 | ``` 36 | 37 | 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. -------------------------------------------------------------------------------- /cw05/readme.md: -------------------------------------------------------------------------------- 1 | # Zadania - Zestaw 5 2 | # Potoki nazwane i nienazwane 3 | ## Zadanie 1 (50%) 4 | Napisz interpreter poleceń przechowywanych w pliku. Ścieżka do pliku to pierwszy argument wywołania programu. 5 | 6 | Polecenia w pliku przechowywane są w kolejnych liniach w postaci: 7 | 8 | prog1 arg1 ... argn1 | prog2 arg1 ... argn2 | ... | progN arg1 ... argnN 9 | 10 | - 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) 11 | - Można założyć ograniczenie górne na ilość obsługiwanych argumentów oraz ilość połączonych komend w pojedynczym poleceniu (co najmniej 3). 12 | - Po uruchomieniu ciągu programów składających się na pojedyncze polecenie (linijkę) interpreter powinien oczekiwać na zakończenie wszystkich tych programów. 13 | 14 | Program należy zaimplementować korzystając z funkcji pipe/fork/exec. 15 | 16 | ## Zadanie 2 (10%) 17 | Napisać program przyjmujący jeden argument - ścieżkę do pliku tekstowego zawierających kilka linii tekstu (dowolne znaki). 18 | Wykorzystując popen oraz komendę sort posortować linie podanego pliku tekstowego (posortowane linie mają być wypisane na ekran). 19 | ## Zadanie 3 (40%) 20 | W problemie producenta i konsumenta występują dwa rodzaje procesów, które dzielą wspólny bufor dla produkowanych i konsumowanych jednostek. Zadaniem producenta jest wytworzenie surowca, umieszczenie go w buforze i rozpoczęcie pracy od nowa. Konsument pobiera surowiec z bufora i wykorzystuje go. 21 | 22 | Przy pomocy potoków nazwanych zaimplementować problem Producenta i Konsumenta. Napisać dwa niezależne programy - Producent oraz Konsument, które będą komunikować się poprzez potok nazwany (kolejkę FIFO). Do potoku pisać będzie wiele procesów wykonujących program Producenta, a czytał będzie z niej jeden proces Konsumenta. Dla zademonstrowania, że nie doszło do utraty ani zwielokrotnienia towaru surowiec będzie pobierany z pliku przez Producenta i umieszczany w innym pliku przez Konsumenta. 23 | 24 | Producent: 25 | 26 | - przyjmuje trzy argumenty: ścieżka do potoku nazwanego, ścieżka do pliku tekstowego z dowolną zawartością, N - liczba znaków odczytywanych jednorazowo z pliku 27 | - otwiera potok nazwany 28 | - wielokrotnie (aż do odczytania całego pliku): 29 | - odczekuje losową ilość czasu (np. 1-2 sekund) 30 | - zapisuje do potoku nazwanego linię zawierającą swój PID oraz odczytany fragment pliku w następującej formie: #PID#(N odczytanych znaków) 31 | 32 | Konsument: 33 | 34 | - przyjmuje trzy argumenty: ścieżka do potoku nazwanego, ścieżka do pliku tekstowego (do którego będzie zapisywany odczytany tekst), N - liczba znaków odczytywanych jednorazowo z pliku 35 | - otwiera potok nazwany 36 | - wielokrotnie: 37 | - czyta kolejnych N znaków potoku nazwanego 38 | - umieszcza odczytane znaki w pliku tekstowym (różnym od plików, z których korzystają producenci) 39 | 40 | Pliki tekstowe powinny być krótkie (na 5-10 odczytów) i umożliwiać sprawdzenie poprawności działania (brak utraty, zwielokrotnienia surowca). W szczególności każdy Producent powinien otrzymać wygenerowany w dowolny sposób plik tekstowy z dowolną zawartością, ale w istotny sposób różniącą się od zawartości plików innych Producentów. Na przykład jeden producent może otrzymać plik zawierający tylko konkretną literę, inny tylko liczby itd. 41 | 42 | Sprawdzić, że potoki nazwane działają dla niezależnych procesów - utworzyć potok z linii komend, a następnie uruchomić Producenta i Konsumenta w różnych terminalach. Dodatkowo należy napisać program, który tworzy potok nazwany, a następnie uruchamia program Konsumenta i pięciu Producentów (z różnymi argumentami). -------------------------------------------------------------------------------- /cw02/zad1/sys.c: -------------------------------------------------------------------------------- 1 | #ifndef sys 2 | #define sys 3 | 4 | #include "util.c" 5 | 6 | static int check_word_size_sys(char *file) { 7 | int fd = open(file, O_RDONLY), size = -1; 8 | if (fd < 0) panic("Can not open file '%s': %s", file, strerror(errno)); 9 | 10 | for (char c = ' '; c && c != '\n' && c != '\r'; size++) 11 | read(fd, &c, 1); 12 | close(fd); 13 | return size; 14 | } 15 | 16 | void copy_sys(char *source, char *target, uint word_count) { 17 | int word_size = check_word_size_sys(source), size; 18 | uint bytes_to_copy = word_count * (word_size + new_line_size); 19 | 20 | int in = open(source, O_RDONLY); 21 | if (in < 0) panic("Can not open file '%s': %s", source, strerror(errno)); 22 | 23 | int out = open(target, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); 24 | if (out < 0) panic("Can not open file '%s': %s", target, strerror(errno)); 25 | 26 | while (bytes_to_copy > 0 && (size = read(in, buffer, min(buffer_size, bytes_to_copy)))) { 27 | bytes_to_copy -= size; 28 | write(out, buffer, size); 29 | } 30 | 31 | close(in); 32 | close(out); 33 | } 34 | 35 | static void swap_sys(int fd, int line1, int line2) { 36 | int step_size = word_size + new_line_size; 37 | char* buffer1 = malloc(sizeof(char) * word_size); 38 | char* buffer2 = malloc(sizeof(char) * word_size); 39 | 40 | if (lseek(fd, line1 * step_size, SEEK_SET) < 0) 41 | panic("Can not seek: %s", strerror(errno)); 42 | if (read(fd, buffer1, word_size) < 0) 43 | panic("Can not read: %s", strerror(errno)); 44 | 45 | if (lseek(fd, line2 * step_size, SEEK_SET) < 0) 46 | panic("Can not seek: %s", strerror(errno)); 47 | if (read(fd, buffer2, word_size) < 0) 48 | panic("Can not read: %s", strerror(errno)); 49 | 50 | if (lseek(fd, line1 * step_size, SEEK_SET) < 0) 51 | panic("Can not seek: %s", strerror(errno)); 52 | if (write(fd, buffer2, word_size) < 0) 53 | panic("Can not write: %s", strerror(errno)); 54 | 55 | if (lseek(fd, line2 * step_size, SEEK_SET) < 0) 56 | panic("Can not seek: %s", strerror(errno)); 57 | if (write(fd, buffer1, word_size) < 0) 58 | panic("Can not write: %s", strerror(errno)); 59 | 60 | free(buffer1); 61 | free(buffer2); 62 | } 63 | 64 | static int partition_sys(int fd, uint low, uint high) { 65 | uint step_size = word_size + new_line_size; 66 | 67 | char* pivot_buffer = malloc(sizeof(char) * word_size); 68 | char* buffer = malloc(sizeof(char) * word_size); 69 | 70 | if (lseek(fd, high * step_size, SEEK_SET) < 0) 71 | panic("Can not seek: %s", strerror(errno)); 72 | if (read(fd, pivot_buffer, word_size) < 0) 73 | panic("Can not read: %s", strerror(errno)); 74 | 75 | int i = low - 1; 76 | for (int j = low; j < high; j++) { 77 | if (lseek(fd, j * step_size, SEEK_SET) < 0) 78 | panic("Can not seek: %s", strerror(errno)); 79 | if (read(fd, buffer, word_size) < 0) 80 | panic("Can not read: %s", strerror(errno)); 81 | 82 | if (strncmp(buffer, pivot_buffer, word_size) < 0) 83 | swap_sys(fd, ++i, j); 84 | } 85 | swap_sys(fd, i + 1, high); 86 | 87 | free(pivot_buffer); 88 | free(buffer); 89 | return i + 1; 90 | } 91 | 92 | static void sort_sys_(int fd, int low, int high) { 93 | if (low >= high) return; 94 | int pivot = partition_sys(fd, low, high); 95 | sort_sys_(fd, low, pivot - 1); 96 | sort_sys_(fd, pivot + 1, high); 97 | } 98 | 99 | void sort_sys(char *file, int word_count_, int word_size_) { 100 | int fd = open(file, O_RDWR); 101 | if (fd < 0) panic("Can not open file '%s': %s", file, strerror(errno)); 102 | 103 | word_count = word_count_; 104 | word_size = word_size_; 105 | 106 | sort_sys_(fd, 0, word_count - 1); 107 | 108 | close(fd); 109 | } 110 | 111 | #endif -------------------------------------------------------------------------------- /cw02/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 oraz bibliotecznych funkcji wejścia/wyjścia. Program operował będzie na przechowywanej w pliku tablicy napisów (rekordów). Dla uproszczenia pojedynczy napis będzie miał stałą wielkość. Nazwa pliku, wielkość oraz liczba i długość napisó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 (w porządku leksykograficznym), używając sortowania szybkiego. Kluczem do sortowania niech będzie wartość pierwszego napisu / rekordu. Podczas sortowania w pamięci powinny być przechowywane jednocześnie najwyżej dwa rekordy (porównywanie 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 | 18 | ./program generate dane 100 512 powinno losowo generować 100 rekordów o długości 512 bajtów (znaków) 19 | do pliku dane, 20 | 21 | ./program sort dane 100 512 sys powinien sortować rekordy w pliku dane przy użyciu funkcji systemowych, 22 | zakładając że zawiera on 100 rekordów wielkości 512 bajtów 23 | 24 | ./program copy plik1 plik2 100 512 lib powinno skopiować 100 rekordów pliku 1 do pliku 2 za pomocą funkcji 25 | bibliotecznych z wykorzystaniem bufora 512 bajtów 26 | 27 | * (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. 28 | 29 | ## Zadanie 2. Operacje na strukturze katalogów (45%) 30 | 31 | Napisz prosty odpowiednik programu find — program powinien implementować następujące opcje: '-mtime', '-atime' oraz '-maxdepth'. W przypadku dwóch pierwszych, podobnie jak w przypadku find, argumentem może być: liczba (bezwzględna), liczba poprzedzonej znakiem '+' lub liczba poprzedzona znakiem '-'. Program ma wypisać na standardowe wyjście następujące informacje o znalezionych plikach: 32 | 33 | * ścieżka bezwzględna pliku, 34 | * liczbę dowiązań 35 | * 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) 36 | * rozmiar w bajtach, 37 | * datę ostatniego dostępu, 38 | * datę ostatniej modyfikacji. 39 | 40 | Ś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. 41 | 42 | Program należy zaimplementować w dwóch wariantach: 43 | 44 | 1. Korzystając z funkcji opendir(), readdir() oraz funkcji z rodziny stat (25%) 45 | 2. Korzystając z funkcji nftw() (20%) 46 | 47 | W ramach testowania funkcji utwórz w badanej strukturze katalogów jakieś dowiązania symboliczne, zwykłe pliki i katalogi. -------------------------------------------------------------------------------- /cw02/zad1/lib.c: -------------------------------------------------------------------------------- 1 | #ifndef std 2 | #define std 3 | 4 | #include "util.c" 5 | 6 | static int check_word_size_c(char* file) { 7 | FILE* f = fopen(file, "r"); 8 | if (!f) panic("Can not open file '%s': %s", file, strerror(errno)); 9 | 10 | int size = -1; 11 | for (char c = ' '; c && c != '\n' && c != '\r'; size++) 12 | fread(&c, sizeof(char), 1, f); 13 | fclose(f); 14 | return size; 15 | } 16 | 17 | void copy_lib(char *source, char *target, uint word_count) { 18 | int word_size = check_word_size_c(source), size; 19 | uint bytes_to_copy = word_count * (word_size + new_line_size); 20 | 21 | FILE* in = fopen(source, "r"); 22 | if (!in) panic("Can not open file '%s': %s", source, strerror(errno)); 23 | 24 | FILE* out = fopen(target, "w"); 25 | if (!out) panic("Can not open file '%s': %s", target, strerror(errno)); 26 | 27 | while(bytes_to_copy > 0 && (size = fread(buffer, sizeof(char), min(buffer_size, bytes_to_copy), in))) { 28 | bytes_to_copy -= size; 29 | fwrite(buffer, sizeof(char), size, out); 30 | } 31 | 32 | fclose(in); 33 | fclose(out); 34 | } 35 | 36 | static void swap_lib(FILE* file, int line1, int line2) { 37 | int step_size = word_size + new_line_size; 38 | char* buffer1 = malloc(sizeof(char) * word_size); 39 | char* buffer2 = malloc(sizeof(char) * word_size); 40 | 41 | if (fseek(file, line1 * step_size, SEEK_SET) < 0) 42 | panic("Can not seek: %s", strerror(errno)); 43 | if (fread(buffer1, sizeof(char), word_size, file) < 0) 44 | panic("Can not read: %s", strerror(errno)); 45 | 46 | if (fseek(file, line2 * step_size, SEEK_SET) < 0) 47 | panic("Can not seek: %s", strerror(errno)); 48 | if (fread(buffer2, sizeof(char), word_size, file) < 0) 49 | panic("Can not read: %s", strerror(errno)); 50 | 51 | if (fseek(file, line1 * step_size, SEEK_SET) < 0) 52 | panic("Can not seek: %s", strerror(errno)); 53 | if (fwrite(buffer2, sizeof(char), word_size, file) < 0) 54 | panic("Can not write: %s", strerror(errno)); 55 | 56 | if (fseek(file, line2 * step_size, SEEK_SET) < 0) 57 | panic("Can not seek: %s", strerror(errno)); 58 | if (fwrite(buffer1, sizeof(char), word_size, file) < 0) 59 | panic("Can not write: %s", strerror(errno)); 60 | 61 | free(buffer1); 62 | free(buffer2); 63 | } 64 | 65 | static int partition_lib(FILE* file, uint low, uint high) { 66 | uint step_size = word_size + new_line_size; 67 | 68 | char* pivot_buffer = malloc(sizeof(char) * word_size); 69 | char* buffer = malloc(sizeof(char) * word_size); 70 | 71 | if (fseek(file, high * step_size, SEEK_SET) < 0) 72 | panic("Can not seek: %s", strerror(errno)); 73 | if (fread(pivot_buffer, sizeof(char), word_size, file) < 0) 74 | panic("Can not read: %s", strerror(errno)); 75 | 76 | int i = low - 1; 77 | for (int j = low; j < high; j++) { 78 | if (fseek(file, j * step_size, SEEK_SET) < 0) 79 | panic("Can not seek: %s", strerror(errno)); 80 | if (fread(buffer, sizeof(char), word_size, file) < 0) 81 | panic("Can not read: %s", strerror(errno)); 82 | 83 | if (strncmp(buffer, pivot_buffer, word_size) < 0) 84 | swap_lib(file, ++i, j); 85 | } 86 | swap_lib(file, i + 1, high); 87 | 88 | free(pivot_buffer); 89 | free(buffer); 90 | return i + 1; 91 | } 92 | 93 | static void sort_lib_(FILE* file, int low, int high) { 94 | if (low >= high) return; 95 | int pivot = partition_lib(file, low, high); 96 | sort_lib_(file, low, pivot - 1); 97 | sort_lib_(file, pivot + 1, high); 98 | } 99 | 100 | void sort_lib(char *file, int word_count_, int word_size_) { 101 | FILE* f = fopen(file, "r+"); 102 | if (!f) panic("Can not open file '%s': %s", file, strerror(errno)); 103 | 104 | word_count = word_count_; 105 | word_size = word_size_; 106 | 107 | sort_lib_(f, 0, word_count - 1); 108 | 109 | fclose(f); 110 | } 111 | 112 | #endif -------------------------------------------------------------------------------- /cw08/zad1/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "image.c" 6 | #include "macros.h" 7 | 8 | 9 | typedef struct thread_start_info { 10 | image* img; 11 | int start, step, stop; 12 | } thread_start_info; 13 | 14 | typedef struct thread_ret_value { 15 | int time; 16 | unsigned int* fragment; 17 | } thread_ret_value; 18 | 19 | unsigned int hist[SHADES]; 20 | 21 | enum thread_fn { sign, block, interleaved }; 22 | enum thread_fn parse(char* arg) { 23 | #define parse(x) if (strcmp(arg, #x) == 0) return x; 24 | parse(sign) 25 | parse(block) 26 | parse(interleaved) 27 | #undef parse 28 | return -1; 29 | } 30 | 31 | thread_ret_value* scan_for_values(thread_start_info* info) { 32 | measure_time { 33 | shade** data = info->img->data, value; 34 | int width = info->img->width, height = info->img->height; 35 | int min = info->start, max = info->stop; 36 | 37 | for (int x = 0; x < width; ++x) { 38 | shade* col = data[x]; 39 | for (int y = 0; y < height; ++y) { 40 | value = col[y]; 41 | if (min <= value && value < max) 42 | ++hist[value]; 43 | } 44 | } 45 | } 46 | 47 | thread_ret_value* ret = malloc(sizeof *ret); 48 | ret->time = time; 49 | ret->fragment = NULL; 50 | return ret; 51 | } 52 | 53 | thread_ret_value* scan_by_cols(thread_start_info* info) { 54 | unsigned int* count; 55 | measure_time { 56 | shade** data = info->img->data; 57 | count = calloc(SHADES, sizeof *count); 58 | int height = info->img->height; 59 | int stop = info->stop, step = info->step; 60 | 61 | for (int x = info->start; x < stop; x += step) { 62 | shade* col = data[x]; 63 | for (int y = 0; y < height; y++) 64 | ++count[col[y]]; 65 | } 66 | } 67 | 68 | thread_ret_value* ret = malloc(sizeof *ret); 69 | ret->fragment = count; 70 | ret->time = time; 71 | return ret; 72 | } 73 | 74 | 75 | int main(int argc, char** argv) { 76 | int thread_count = atoi(argv[1]); 77 | assert(thread_count > 0); 78 | 79 | image* img = load_image(argv[3]); 80 | assert(img != NULL); 81 | 82 | FILE* file_out = fopen(argv[4], "w+"); 83 | assert(file_out != NULL); 84 | 85 | enum thread_fn fn = parse(argv[2]); 86 | 87 | int problem_size = fn == sign ? SHADES : img->width; 88 | int chunk = ceil_div(problem_size, thread_count); 89 | 90 | pthread_t *threads = malloc(thread_count * sizeof *threads); 91 | 92 | measure_time { 93 | if (fn == sign) { 94 | repeat (thread_count) { 95 | thread_start_info info = { img, chunk * i, 1, chunk * (i + 1) }; 96 | p_creat(&threads[i], scan_for_values, info); 97 | } 98 | repeat (thread_count) { 99 | thread_ret_value* ret; 100 | p_join(threads[i], &ret); 101 | printf("thread(%lu) took(%d microseconds)\n", threads[i], ret->time); 102 | free(ret); 103 | } 104 | } else { 105 | if (fn == block) { 106 | repeat (thread_count) { 107 | thread_start_info info = { img, chunk * i, 1, min(chunk * (i + 1), problem_size) }; 108 | p_creat(&threads[i], scan_by_cols, info); 109 | } 110 | } else if (fn == interleaved) { 111 | repeat (thread_count) { 112 | thread_start_info info = { img, i, thread_count, img->width }; 113 | p_creat(&threads[i], scan_by_cols, info); 114 | } 115 | } 116 | 117 | repeat (thread_count) { 118 | thread_ret_value* ret; 119 | p_join(threads[i], &ret); 120 | repeat (SHADES) hist[i] += ret->fragment[i]; 121 | printf("thread(%lu) took(%d microseconds)\n", threads[i], ret->time); 122 | free(ret->fragment); 123 | free(ret); 124 | } 125 | } 126 | } 127 | 128 | repeat (SHADES) fprintf(file_out, "%d %u\n", i, hist[i]); 129 | printf("total time(%d microseconds)\n", time); 130 | fclose(file_out); 131 | return 0; 132 | } -------------------------------------------------------------------------------- /cw01/zad1/lib.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | typedef struct node { 4 | struct node* next; 5 | char* value; 6 | } node; 7 | 8 | // node** tail, char* value 9 | #define push_back(tail, val) \ 10 | *tail = calloc(sizeof(struct node), 1); \ 11 | (*tail)->value = val; \ 12 | tail = &(*tail)->next; 13 | 14 | static block* create_block(int size) { 15 | block* b = calloc(sizeof(block), 1); 16 | b->size = size; 17 | b->operations = calloc(sizeof(char*), size); 18 | return b; 19 | } 20 | 21 | block* compare_files(char* file1, char* file2) { 22 | // initializing variables for diff call 23 | static const char pattern[] = "diff %s %s > /tmp/diffs"; 24 | 25 | int size = sizeof(pattern) + strlen(file1) + strlen(file2); 26 | use(char, out, size, { 27 | sprintf(out, pattern, file1, file2); 28 | system(out); 29 | }); 30 | 31 | // reading file 32 | FILE *f = fopen("/tmp/diffs", "r"); 33 | 34 | if (f == NULL) return NULL; 35 | 36 | fseek(f, 0, SEEK_END); 37 | long fsize = ftell(f); 38 | fseek(f, 0, SEEK_SET); 39 | 40 | node* operation_list = NULL; 41 | node** tail = &operation_list; 42 | int operation_count = 0; 43 | 44 | use_malloc(char, content, fsize + 1, { 45 | fread(content, 1, fsize, f); 46 | content[fsize] = 0; 47 | fclose(f); 48 | 49 | for (int i = 0, operation_start, operation_end; content[i];) { 50 | operation_start = i; 51 | do { 52 | while (content[i] != '\n' && content[i]) i++; 53 | if (content[i]) i++; 54 | } while (content[i] && (content[i] == '<' || content[i] == '-' || content[i] == '>' || content[i] == '\\')); 55 | operation_end = i; 56 | 57 | int operation_len = operation_end - operation_start + 1; 58 | char* operation = calloc(sizeof(char), operation_len + 1); 59 | 60 | for (int i = operation_start, j = 0; i < operation_end; ++i, ++j) 61 | operation[j] = content[i]; 62 | 63 | push_back(tail, operation); 64 | operation_count++; 65 | } 66 | 67 | }); 68 | 69 | block* b = create_block(operation_count); 70 | b->files[0] = file1; 71 | b->files[1] = file2; 72 | 73 | struct node* iter = operation_list, *tmp; 74 | for (int i = 0; i < operation_count; i++) { 75 | b->operations[i] = iter->value; 76 | tmp = iter; 77 | iter = iter->next; 78 | free(tmp); 79 | } 80 | 81 | return b; 82 | } 83 | 84 | table* create_table(int size) { 85 | table* t = calloc(sizeof(table), 1); 86 | t->values = calloc(sizeof(block*), size); 87 | t->size = size; 88 | return t; 89 | } 90 | 91 | void remove_block(table* table, int block_index) { 92 | if (table->values[block_index] == NULL) return; 93 | free(table->values[block_index]); 94 | table->values[block_index] = NULL; 95 | } 96 | 97 | void remove_operation(table* table, int block_index, int operation_index) { 98 | block* block = table->values[block_index]; 99 | if (block == NULL) return; 100 | if (block->operations[operation_index] == NULL) return; 101 | free(block->operations[operation_index]); 102 | block->operations[operation_index] = 0; 103 | } 104 | 105 | void compare_file_sequence(table* table, char** sequence) { 106 | static char* files[2]; 107 | 108 | int size = table->size; 109 | for (int i = 0; i < size; i++) { 110 | if (table->values[i]) free(table->values[i]); 111 | files[0] = strtok(sequence[i], ":"); 112 | files[1] = strtok(NULL, ""); 113 | table->values[i] = compare_files(files[0], files[1]); 114 | } 115 | } 116 | 117 | int operation_count(table* table, int block_index) { 118 | if (table == NULL || table->values == NULL) return -1; 119 | block* block = table->values[block_index]; 120 | int count = 0; 121 | for (int i = 0; i < block->size; i++) 122 | if (block->operations[i]) count++; 123 | return count; 124 | } 125 | 126 | int blocks_count(table* table) { 127 | if (table == NULL || table->values == NULL) return -1; 128 | int count = 0; 129 | for (int i = 0; i < table->size; i++) 130 | if (table->values[i]) count++; 131 | return count; 132 | } 133 | -------------------------------------------------------------------------------- /cw01/zad3a/lib.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | typedef struct node { 4 | struct node* next; 5 | char* value; 6 | } node; 7 | 8 | // node** tail, char* value 9 | #define push_back(tail, val) \ 10 | *tail = calloc(sizeof(struct node), 1); \ 11 | (*tail)->value = val; \ 12 | tail = &(*tail)->next; 13 | 14 | static block* create_block(int size) { 15 | block* b = calloc(sizeof(block), 1); 16 | b->size = size; 17 | b->operations = calloc(sizeof(char*), size); 18 | return b; 19 | } 20 | 21 | block* compare_files(char* file1, char* file2) { 22 | // initializing variables for diff call 23 | static const char pattern[] = "diff %s %s > /tmp/diffs"; 24 | 25 | int size = sizeof(pattern) + strlen(file1) + strlen(file2); 26 | use(char, out, size, { 27 | sprintf(out, pattern, file1, file2); 28 | system(out); 29 | }); 30 | 31 | // reading file 32 | FILE *f = fopen("/tmp/diffs", "r"); 33 | 34 | if (f == NULL) return NULL; 35 | 36 | fseek(f, 0, SEEK_END); 37 | long fsize = ftell(f); 38 | fseek(f, 0, SEEK_SET); 39 | 40 | node* operation_list = NULL; 41 | node** tail = &operation_list; 42 | int operation_count = 0; 43 | 44 | use_malloc(char, content, fsize + 1, { 45 | fread(content, 1, fsize, f); 46 | content[fsize] = 0; 47 | fclose(f); 48 | 49 | for (int i = 0, operation_start, operation_end; content[i];) { 50 | operation_start = i; 51 | do { 52 | while (content[i] != '\n' && content[i]) i++; 53 | if (content[i]) i++; 54 | } while (content[i] && (content[i] == '<' || content[i] == '-' || content[i] == '>' || content[i] == '\\')); 55 | operation_end = i; 56 | 57 | int operation_len = operation_end - operation_start + 1; 58 | char* operation = calloc(sizeof(char), operation_len + 1); 59 | 60 | for (int i = operation_start, j = 0; i < operation_end; ++i, ++j) 61 | operation[j] = content[i]; 62 | 63 | push_back(tail, operation); 64 | operation_count++; 65 | } 66 | 67 | }); 68 | 69 | block* b = create_block(operation_count); 70 | b->files[0] = file1; 71 | b->files[1] = file2; 72 | 73 | struct node* iter = operation_list, *tmp; 74 | for (int i = 0; i < operation_count; i++) { 75 | b->operations[i] = iter->value; 76 | tmp = iter; 77 | iter = iter->next; 78 | free(tmp); 79 | } 80 | 81 | return b; 82 | } 83 | 84 | table* create_table(int size) { 85 | table* t = calloc(sizeof(table), 1); 86 | t->values = calloc(sizeof(block*), size); 87 | t->size = size; 88 | return t; 89 | } 90 | 91 | void remove_block(table* table, int block_index) { 92 | if (table->values[block_index] == NULL) return; 93 | free(table->values[block_index]); 94 | table->values[block_index] = NULL; 95 | } 96 | 97 | void remove_operation(table* table, int block_index, int operation_index) { 98 | block* block = table->values[block_index]; 99 | if (block == NULL) return; 100 | if (block->operations[operation_index] == NULL) return; 101 | free(block->operations[operation_index]); 102 | block->operations[operation_index] = 0; 103 | } 104 | 105 | void compare_file_sequence(table* table, char** sequence) { 106 | static char* files[2]; 107 | 108 | int size = table->size; 109 | for (int i = 0; i < size; i++) { 110 | if (table->values[i]) free(table->values[i]); 111 | files[0] = strtok(sequence[i], ":"); 112 | files[1] = strtok(NULL, ""); 113 | table->values[i] = compare_files(files[0], files[1]); 114 | } 115 | } 116 | 117 | int operation_count(table* table, int block_index) { 118 | if (table == NULL || table->values == NULL) return -1; 119 | block* block = table->values[block_index]; 120 | int count = 0; 121 | for (int i = 0; i < block->size; i++) 122 | if (block->operations[i]) count++; 123 | return count; 124 | } 125 | 126 | int blocks_count(table* table) { 127 | if (table == NULL || table->values == NULL) return -1; 128 | int count = 0; 129 | for (int i = 0; i < table->size; i++) 130 | if (table->values[i]) count++; 131 | return count; 132 | } 133 | -------------------------------------------------------------------------------- /cw01/zad3b/lib.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | typedef struct node { 4 | struct node* next; 5 | char* value; 6 | } node; 7 | 8 | // node** tail, char* value 9 | #define push_back(tail, val) \ 10 | *tail = calloc(sizeof(struct node), 1); \ 11 | (*tail)->value = val; \ 12 | tail = &(*tail)->next; 13 | 14 | static block* create_block(int size) { 15 | block* b = calloc(sizeof(block), 1); 16 | b->size = size; 17 | b->operations = calloc(sizeof(char*), size); 18 | return b; 19 | } 20 | 21 | block* compare_files(char* file1, char* file2) { 22 | // initializing variables for diff call 23 | static const char pattern[] = "diff %s %s > /tmp/diffs"; 24 | 25 | int size = sizeof(pattern) + strlen(file1) + strlen(file2); 26 | use(char, out, size, { 27 | sprintf(out, pattern, file1, file2); 28 | system(out); 29 | }); 30 | 31 | // reading file 32 | FILE *f = fopen("/tmp/diffs", "r"); 33 | 34 | if (f == NULL) return NULL; 35 | 36 | fseek(f, 0, SEEK_END); 37 | long fsize = ftell(f); 38 | fseek(f, 0, SEEK_SET); 39 | 40 | node* operation_list = NULL; 41 | node** tail = &operation_list; 42 | int operation_count = 0; 43 | 44 | use_malloc(char, content, fsize + 1, { 45 | fread(content, 1, fsize, f); 46 | content[fsize] = 0; 47 | fclose(f); 48 | 49 | for (int i = 0, operation_start, operation_end; content[i];) { 50 | operation_start = i; 51 | do { 52 | while (content[i] != '\n' && content[i]) i++; 53 | if (content[i]) i++; 54 | } while (content[i] && (content[i] == '<' || content[i] == '-' || content[i] == '>' || content[i] == '\\')); 55 | operation_end = i; 56 | 57 | int operation_len = operation_end - operation_start + 1; 58 | char* operation = calloc(sizeof(char), operation_len + 1); 59 | 60 | for (int i = operation_start, j = 0; i < operation_end; ++i, ++j) 61 | operation[j] = content[i]; 62 | 63 | push_back(tail, operation); 64 | operation_count++; 65 | } 66 | 67 | }); 68 | 69 | block* b = create_block(operation_count); 70 | b->files[0] = file1; 71 | b->files[1] = file2; 72 | 73 | struct node* iter = operation_list, *tmp; 74 | for (int i = 0; i < operation_count; i++) { 75 | b->operations[i] = iter->value; 76 | tmp = iter; 77 | iter = iter->next; 78 | free(tmp); 79 | } 80 | 81 | return b; 82 | } 83 | 84 | table* create_table(int size) { 85 | table* t = calloc(sizeof(table), 1); 86 | t->values = calloc(sizeof(block*), size); 87 | t->size = size; 88 | return t; 89 | } 90 | 91 | void remove_block(table* table, int block_index) { 92 | if (table->values[block_index] == NULL) return; 93 | free(table->values[block_index]); 94 | table->values[block_index] = NULL; 95 | } 96 | 97 | void remove_operation(table* table, int block_index, int operation_index) { 98 | block* block = table->values[block_index]; 99 | if (block == NULL) return; 100 | if (block->operations[operation_index] == NULL) return; 101 | free(block->operations[operation_index]); 102 | block->operations[operation_index] = 0; 103 | } 104 | 105 | void compare_file_sequence(table* table, char** sequence) { 106 | static char* files[2]; 107 | 108 | int size = table->size; 109 | for (int i = 0; i < size; i++) { 110 | if (table->values[i]) free(table->values[i]); 111 | files[0] = strtok(sequence[i], ":"); 112 | files[1] = strtok(NULL, ""); 113 | table->values[i] = compare_files(files[0], files[1]); 114 | } 115 | } 116 | 117 | int operation_count(table* table, int block_index) { 118 | if (table == NULL || table->values == NULL) return -1; 119 | block* block = table->values[block_index]; 120 | int count = 0; 121 | for (int i = 0; i < block->size; i++) 122 | if (block->operations[i]) count++; 123 | return count; 124 | } 125 | 126 | int blocks_count(table* table) { 127 | if (table == NULL || table->values == NULL) return -1; 128 | int count = 0; 129 | for (int i = 0; i < table->size; i++) 130 | if (table->values[i]) count++; 131 | return count; 132 | } 133 | -------------------------------------------------------------------------------- /cw01/zad2/lib.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | typedef struct node { 4 | struct node* next; 5 | char* value; 6 | } node; 7 | 8 | // node** tail, char* value 9 | #define push_back(tail, val) \ 10 | *tail = calloc(sizeof(struct node), 1); \ 11 | (*tail)->value = val; \ 12 | tail = &(*tail)->next; 13 | 14 | static block* create_block(int size) { 15 | block* b = calloc(sizeof(block), 1); 16 | b->size = size; 17 | b->operations = calloc(sizeof(char*), size); 18 | return b; 19 | } 20 | 21 | block* compare_files(char* file1, char* file2) { 22 | // initializing variables for diff call 23 | static const char pattern[] = "diff %s %s > /tmp/diffs"; 24 | 25 | int size = sizeof(pattern) + strlen(file1) + strlen(file2); 26 | use(char, out, size, { 27 | sprintf(out, pattern, file1, file2); 28 | system(out); 29 | }); 30 | 31 | // reading file 32 | FILE *f = fopen("/tmp/diffs", "r"); 33 | 34 | if (f == NULL) return NULL; 35 | 36 | fseek(f, 0, SEEK_END); 37 | long fsize = ftell(f); 38 | fseek(f, 0, SEEK_SET); 39 | 40 | node* operation_list = NULL; 41 | node** tail = &operation_list; 42 | int operation_count = 0; 43 | 44 | use_malloc(char*, content, fsize + 1, { 45 | fread(content, 1, fsize, f); 46 | content[fsize] = 0; 47 | fclose(f); 48 | 49 | for (int i = 0, operation_start, operation_end; content[i];) { 50 | operation_start = i; 51 | do { 52 | while (content[i] != '\n' && content[i]) i++; 53 | if (content[i]) i++; 54 | } while (content[i] && (content[i] == '<' || content[i] == '-' || content[i] == '>' || content[i] == '\\')); 55 | operation_end = i; 56 | 57 | int operation_len = operation_end - operation_start + 1; 58 | char* operation = calloc(sizeof(char), operation_len + 1); 59 | 60 | for (int i = operation_start, j = 0; i < operation_end; ++i, ++j) 61 | operation[j] = content[i]; 62 | 63 | push_back(tail, operation); 64 | operation_count++; 65 | } 66 | 67 | }); 68 | 69 | block* b = create_block(operation_count); 70 | b->files[0] = file1; 71 | b->files[1] = file2; 72 | 73 | struct node* iter = operation_list, *tmp; 74 | for (int i = 0; i < operation_count; i++) { 75 | b->operations[i] = iter->value; 76 | tmp = iter; 77 | iter = iter->next; 78 | free(tmp); 79 | } 80 | 81 | return b; 82 | } 83 | 84 | table* create_table(int size) { 85 | table* t = calloc(sizeof(table), 1); 86 | t->values = calloc(sizeof(block*), size); 87 | t->size = size; 88 | return t; 89 | } 90 | 91 | void remove_block(table* table, int block_index) { 92 | if (table->values[block_index] == NULL) return; 93 | free(table->values[block_index]); 94 | table->values[block_index] = NULL; 95 | } 96 | 97 | void remove_operation(table* table, int block_index, int operation_index) { 98 | block* block = table->values[block_index]; 99 | if (block == NULL) return; 100 | if (block->operations[operation_index] == NULL) return; 101 | free(block->operations[operation_index]); 102 | block->operations[operation_index] = 0; 103 | } 104 | 105 | void compare_file_sequence(table* table, char** sequence) { 106 | static char* files[2]; 107 | 108 | int size = table->size; 109 | for (int i = 0; i < size; i++) { 110 | if (table->values[i]) free(table->values[i]); 111 | files[0] = strtok(sequence[i], ":"); 112 | files[1] = strtok(NULL, ""); 113 | table->values[i] = compare_files(files[0], files[1]); 114 | } 115 | } 116 | 117 | int operation_count(table* table, int block_index) { 118 | if (table == NULL || table->values == NULL) return -1; 119 | block* block = table->values[block_index]; 120 | int count = 0; 121 | for (int i = 0; i < block->size; i++) 122 | if (block->operations[i]) count++; 123 | return count; 124 | } 125 | 126 | int blocks_count(table* table) { 127 | if (table == NULL || table->values == NULL) return -1; 128 | int count = 0; 129 | for (int i = 0; i < table->size; i++) 130 | if (table->values[i]) count++; 131 | return count; 132 | } 133 | -------------------------------------------------------------------------------- /cw03/readme.md: -------------------------------------------------------------------------------- 1 | # Tworzenie procesów. Środowisko procesu, sterowanie procesami. 2 | ## Zadanie 1. Drzewo procesów (15%) 3 | 4 | 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. 5 | ## Zadanie 2. Równoległe mnożenie macierzy (50%) 6 | 7 | Napisz program macierz do równoległego mnożenia macierzy — zawartość każdej z macierzy (wejściowej lub wynikowej) znajduje się w osobnych plikach. Argumenty operacji mnożenia są treścią pliku lista, będącego pierwszym argumentem wywołania programu. Plik lista zawiera, w pojedynczej linii: 8 | 9 | * Nazwę pliku z pierwszą macierzą wejściową. 10 | * Nazwę pliku z drugą macierzą wejściową. 11 | * Nazwę pliku z macierzą wyjściową. 12 | 13 | Na samym początku program (Manager Process) tworzy podaną (w drugim argumencie programu) liczbę procesów potomnych (Worker Process). 14 | 15 | ![Struktura danych](https://i.postimg.cc/4xrTznNG/The-manager-worker-model.png) 16 | 17 | Dla każdego wpisu z pliku lista proces potomny mnoży odpowiednie wiersze macierzy A przez odpowiednie kolumny macierzy B, a wynik zapisuje w odpowiednie miejsce macierzy C — każdy z procesów potomnych korzysta z całej macierzy A, a w przypadku macierzy B, tylko z określonych jej kolumn — patrz rysunek: ![mnozenie.png](https://i.postimg.cc/kgSHPsqr/mnozenie.png) 18 | 19 | Przykładowo, dla dwóch procesów potomnych, pierwszy z nich mnoży odpowiednie wiersze macierzy A przez kolumny macierzy B oznaczone kolorem zielonym; drugi proces potomny, mnoży odpowiednie wiersze macierzy A przez kolumny macierzy B oznaczone kolorem niebieskim. 20 | Czas działania procesu potomnego nie może przekroczyć podanej liczby sekund — trzeci argument programu. 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 mnożeń — wymnożenie fragmentu macierzy A przez fragment macierzy B traktujemy jako jedno mnożenie. Proces, który zakończył mnożenie fragmentów, nie kończy działania — może być użyty do kolejnej operacji mnożenia. Program macierzysty pobiera statusy procesów potomnych, wypisuje raport: "Proces PID wykonał n mnożeń macierzy" i kończy swoje działanie. UWAGA! Nie używamy sygnałów, które są tematem następnych zajęć. Ponadto zakładamy, że jedynym dostępnym sposobem komunikacji procesów jest, w tym momencie, komunikacja poprzez plik — właściwe sposoby komunikacji procesów poznamy na dalszych ćwiczeniach. 21 | 22 | Tworzenie pliku wynikowego może się odbywać na dwa sposoby — czwarty argument programu: 23 | 24 | 1. Procesy potomne zapisują wynik mnożenia w odpowiednie miejsce **wspólnego** pliku wynikowego — pamiętaj o odpowiednim użyciu blokady FLOCK. 25 | 2. Procesy potomne zapisują wynik mnożenia do **odrębnych** plików; osobny proces wywołuje jedną z funkcji rodziny `exec*()` w celu wykonania komendy `paste` — połączenie zawartości plików. 26 | 27 | 28 | Napisz pomocniczy program, który: 29 | 30 | * Tworzy określoną liczbę plików z treścią macierzy. Rozmiar tworzonych macierzy, dla odrębnych par macierzy, jest losowy ∈ [Min, Max], gdzie: Min, Max są argumentami programu, przy czym należy zadbać, aby (dla danej pary) liczba kolumn macierzy A była równa liczbie wierszy macierzy B. 31 | * Umożliwia sprawdzenie poprawności otrzymanych wyników mnożenia — implementacja własna lub przy wykorzystaniu dowolnej biblioteki do wykonywania testów jednostkowych 32 | 33 | ## Zadanie 3. Zasoby procesów (35%) 34 | 35 | Zmodyfikuj program z Zadania 2 tak, aby każdy proces (mnożący) 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 dwa ostatnie argumenty wywołania programu macierz. 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 macierz. 36 | 37 | Zaimplementuj w macierz 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. -------------------------------------------------------------------------------- /cw03/zad2/matrix.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define min(a, b) a > b ? b : a 13 | #define max(a, b) a > b ? a : b 14 | 15 | #define panic(str, args...) {\ 16 | fprintf(stderr, "%s:%i ", __func__, __LINE__);\ 17 | fprintf(stderr, str, args);\ 18 | fprintf(stderr, ".\n");\ 19 | exit(1);\ 20 | } 21 | 22 | typedef int number; // if changed remember to change dprint format 23 | typedef unsigned int uint; 24 | #define number_size 12 25 | 26 | typedef struct matrix { 27 | int fd; 28 | uint rows, cols; 29 | number* values; 30 | } matrix; 31 | 32 | static int get_index(matrix* m, uint row, uint col) { 33 | return m->cols * row + col; 34 | } 35 | 36 | matrix* create_matrix(uint rows, uint cols) { 37 | matrix* m = malloc(sizeof(matrix)); 38 | m->rows = rows; 39 | m->cols = cols; 40 | m->values = calloc(rows * cols, sizeof(number)); 41 | return m; 42 | } 43 | 44 | void dump_to_fragment_file(char* root_path, uint cols, uint id, matrix* m) { 45 | char* fragment_path = calloc(strlen(root_path) + 14, sizeof(char)); 46 | sprintf(fragment_path, "%s-%u", root_path, id); 47 | FILE* file = fopen(fragment_path, "w+"); 48 | for (int row = 0; row < m->rows; row++) { 49 | for (int col = 0; col < m->cols; col++) 50 | fprintf(file, "%11i\t", m->values[get_index(m, row, col)]); 51 | fseek(file, -1 * sizeof(char), SEEK_CUR); 52 | fwrite("\n", sizeof(char), 1, file); 53 | } 54 | fclose(file); 55 | } 56 | 57 | void dump_to_file(int fd, uint min_col, uint cols, uint id, matrix* m) { 58 | flock(fd, LOCK_EX); 59 | for (int row = 0; row < m->rows; row++) { 60 | for (int col = 0; col < m->cols; col++) { 61 | lseek(fd, (row * cols + col + min_col) * number_size * sizeof(char), SEEK_SET); 62 | dprintf(fd, (col + min_col + 1 == cols) ? "%11i\n" : "%11i\t", m->values[get_index(m, row, col)]); 63 | } 64 | } 65 | 66 | if (id == 0) { 67 | lseek(fd, m->rows * cols * number_size * sizeof(char), SEEK_SET); 68 | dprintf(fd, "%11u\t%11u\n", m->rows, cols); 69 | ftruncate(fd, lseek(fd, 0, SEEK_CUR)); 70 | } 71 | 72 | flock(fd, LOCK_UN); 73 | } 74 | 75 | matrix* open_partial(int fd, uint min_col, uint max_col, uint rows, uint cols) { 76 | matrix* m = create_matrix(rows, max_col - min_col + 1); 77 | 78 | int row_size = number_size * cols * sizeof(char); 79 | int row_data_size = m->cols * number_size * sizeof(char); 80 | char* row_data = malloc(row_data_size); 81 | 82 | for (int row = 0; row < m->rows; row++) { 83 | lseek(fd, row_size * row + min_col * number_size * sizeof(char), SEEK_SET); 84 | read(fd, row_data, row_data_size); 85 | for (int i = number_size - 1; i <= row_data_size; i += number_size) 86 | row_data[i] = 0; 87 | char* tmp_row_ptr = row_data; 88 | for (int col = 0; col < m->cols; col++) { 89 | m->values[get_index(m, row, col)] = atoi(tmp_row_ptr); 90 | tmp_row_ptr += number_size; 91 | } 92 | } 93 | 94 | free(row_data); 95 | m->fd = fd; 96 | return m; 97 | } 98 | 99 | void read_size(int fd, uint* rows, uint* cols) { // flock file first 100 | static char raw[number_size]; 101 | lseek(fd, -2 * number_size * sizeof(char), SEEK_END); 102 | read(fd, raw, number_size * sizeof(char)); 103 | raw[number_size - 1] = 0; 104 | 105 | if (rows) *rows = atoi(raw); 106 | read(fd, raw, (number_size - 1) * sizeof(char)); 107 | if (cols) *cols = atoi(raw); 108 | } 109 | 110 | matrix* open_matrix(char* file) { 111 | int fd = open(file, O_RDONLY, 777); 112 | 113 | flock(fd, LOCK_EX); 114 | uint rows, cols; 115 | read_size(fd, &rows, &cols); 116 | matrix* m = open_partial(fd, 0, cols - 1, rows, cols); 117 | flock(fd, LOCK_UN); 118 | return m; 119 | } 120 | 121 | void print_matrix(matrix* m) { 122 | number value; 123 | for (uint row = 0; row < m->rows; row++) { 124 | for (uint col = 0; col < m->cols; col++) { 125 | value = m->values[get_index(m, row, col)]; 126 | printf("%i ", value); 127 | } 128 | printf("\n"); 129 | } 130 | } 131 | 132 | void free_matrix(matrix* m) { 133 | close(m->fd); 134 | free(m->values); 135 | free(m); 136 | } 137 | 138 | matrix* multiply(matrix* A, matrix* B) { // matrix B should be loaded using load_partial 139 | matrix* C = create_matrix(A->rows, B->cols); 140 | int inner = B->rows, sum, i; 141 | for (int row = 0; row < A->rows; row++) { 142 | for (int col = 0; col < B->cols; col++) { 143 | for (sum = i = 0; i < inner; i++) 144 | sum += A->values[get_index(A, row, i)] * B->values[get_index(B, i, col)]; 145 | C->values[get_index(C, row, col)] = sum; 146 | } 147 | } 148 | return C; 149 | } -------------------------------------------------------------------------------- /cw03/zad3/matrix.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define min(a, b) a > b ? b : a 13 | #define max(a, b) a > b ? a : b 14 | 15 | #define panic(str, args...) {\ 16 | fprintf(stderr, "%s:%i ", __func__, __LINE__);\ 17 | fprintf(stderr, str, args);\ 18 | fprintf(stderr, ".\n");\ 19 | exit(1);\ 20 | } 21 | 22 | typedef int number; // if changed remember to change dprint format 23 | typedef unsigned int uint; 24 | #define number_size 12 25 | 26 | typedef struct matrix { 27 | int fd; 28 | uint rows, cols; 29 | number* values; 30 | } matrix; 31 | 32 | static int get_index(matrix* m, uint row, uint col) { 33 | return m->cols * row + col; 34 | } 35 | 36 | matrix* create_matrix(uint rows, uint cols) { 37 | matrix* m = malloc(sizeof(matrix)); 38 | m->rows = rows; 39 | m->cols = cols; 40 | m->values = calloc(rows * cols, sizeof(number)); 41 | return m; 42 | } 43 | 44 | void dump_to_fragment_file(char* root_path, uint cols, uint id, matrix* m) { 45 | char* fragment_path = calloc(strlen(root_path) + 14, sizeof(char)); 46 | sprintf(fragment_path, "%s-%u", root_path, id); 47 | FILE* file = fopen(fragment_path, "w+"); 48 | for (int row = 0; row < m->rows; row++) { 49 | for (int col = 0; col < m->cols; col++) 50 | fprintf(file, "%11i\t", m->values[get_index(m, row, col)]); 51 | fseek(file, -1 * sizeof(char), SEEK_CUR); 52 | fwrite("\n", sizeof(char), 1, file); 53 | } 54 | fclose(file); 55 | } 56 | 57 | void dump_to_file(int fd, uint min_col, uint cols, uint id, matrix* m) { 58 | flock(fd, LOCK_EX); 59 | for (int row = 0; row < m->rows; row++) { 60 | for (int col = 0; col < m->cols; col++) { 61 | lseek(fd, (row * cols + col + min_col) * number_size * sizeof(char), SEEK_SET); 62 | dprintf(fd, (col + min_col + 1 == cols) ? "%11i\n" : "%11i\t", m->values[get_index(m, row, col)]); 63 | } 64 | } 65 | 66 | if (id == 0) { 67 | lseek(fd, m->rows * cols * number_size * sizeof(char), SEEK_SET); 68 | dprintf(fd, "%11u\t%11u\n", m->rows, cols); 69 | ftruncate(fd, lseek(fd, 0, SEEK_CUR)); 70 | } 71 | 72 | flock(fd, LOCK_UN); 73 | } 74 | 75 | matrix* open_partial(int fd, uint min_col, uint max_col, uint rows, uint cols) { 76 | matrix* m = create_matrix(rows, max_col - min_col + 1); 77 | 78 | int row_size = number_size * cols * sizeof(char); 79 | int row_data_size = m->cols * number_size * sizeof(char); 80 | char* row_data = malloc(row_data_size); 81 | 82 | for (int row = 0; row < m->rows; row++) { 83 | lseek(fd, row_size * row + min_col * number_size * sizeof(char), SEEK_SET); 84 | read(fd, row_data, row_data_size); 85 | for (int i = number_size - 1; i <= row_data_size; i += number_size) 86 | row_data[i] = 0; 87 | char* tmp_row_ptr = row_data; 88 | for (int col = 0; col < m->cols; col++) { 89 | m->values[get_index(m, row, col)] = atoi(tmp_row_ptr); 90 | tmp_row_ptr += number_size; 91 | } 92 | } 93 | 94 | free(row_data); 95 | m->fd = fd; 96 | return m; 97 | } 98 | 99 | void read_size(int fd, uint* rows, uint* cols) { // flock file first 100 | static char raw[number_size]; 101 | lseek(fd, -2 * number_size * sizeof(char), SEEK_END); 102 | read(fd, raw, number_size * sizeof(char)); 103 | raw[number_size - 1] = 0; 104 | 105 | if (rows) *rows = atoi(raw); 106 | read(fd, raw, (number_size - 1) * sizeof(char)); 107 | if (cols) *cols = atoi(raw); 108 | } 109 | 110 | matrix* open_matrix(char* file) { 111 | int fd = open(file, O_RDONLY, 777); 112 | 113 | flock(fd, LOCK_EX); 114 | uint rows, cols; 115 | read_size(fd, &rows, &cols); 116 | matrix* m = open_partial(fd, 0, cols - 1, rows, cols); 117 | flock(fd, LOCK_UN); 118 | return m; 119 | } 120 | 121 | void print_matrix(matrix* m) { 122 | number value; 123 | for (uint row = 0; row < m->rows; row++) { 124 | for (uint col = 0; col < m->cols; col++) { 125 | value = m->values[get_index(m, row, col)]; 126 | printf("%i ", value); 127 | } 128 | printf("\n"); 129 | } 130 | } 131 | 132 | void free_matrix(matrix* m) { 133 | close(m->fd); 134 | free(m->values); 135 | free(m); 136 | } 137 | 138 | matrix* multiply(matrix* A, matrix* B) { // matrix B should be loaded using load_partial 139 | matrix* C = create_matrix(A->rows, B->cols); 140 | int inner = B->rows, sum, i; 141 | for (int row = 0; row < A->rows; row++) { 142 | for (int col = 0; col < B->cols; col++) { 143 | for (sum = i = 0; i < inner; i++) 144 | sum += A->values[get_index(A, row, i)] * B->values[get_index(B, i, col)]; 145 | C->values[get_index(C, row, col)] = sum; 146 | } 147 | } 148 | return C; 149 | } -------------------------------------------------------------------------------- /cw06/readme.md: -------------------------------------------------------------------------------- 1 | # Zadania - Zestaw 6 2 | # IPC - kolejki komunikatów 3 | ### Przydatne funkcje: 4 | 5 | System V: 6 | 7 | ``` 8 | - msgget, msgctl, msgsnd, msgrcv, ftok 9 | ``` 10 | 11 | POSIX: 12 | 13 | ``` 14 | - mq_open, mq_send, mq_receive, mq_getattr, mq_setattr, mq_close, mq_unlink, mq_notify 15 | ``` 16 | 17 | # Zadanie 1. Prosty chat - System V (50%) 18 | Napisz prosty program typu klient-serwer, w którym komunikacja zrealizowana jest za pomocą kolejek komunikatów. 19 | 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. 20 | 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 może wysłać zlecenie do serwera(zlecenia są czytane ze standardowego wyjścia w postaci typ_komunikatu). 21 | Serwer ma umożliwiać łączenie klientów w pary - klienci przechodząc do trybu chatu będą mogli wysyłać sobie bezpośrednio wiadomości bez udziału serwera. 22 | 23 | 24 | ## Rodzaje zleceń 25 | - LIST: 26 | Zlecenie wypisania listy wszystkich aktywnych klientów wraz z informacja czy są dostępni do połączenia. 27 | - CONNECT id_klienta: 28 | Zlecenie połączenia się z konkretnym klientem. Zleceniodawca wysyła do serwera id_klienta z listy aktywnych klientów. Serwer wysyła mu klucz kolejki klienta z którym chce się połączyć. Następnie serwer wysyła klucz kolejki zleceniodawcy do wybranego klienta. Obaj klienci przechodzą w tryb chatu - wysyłają sobie wiadomości bezpośrednio(bez udziału serwera). Serwer oznacza ich jako niedostępnych do połączenia dla innych klientów. (Należy umożliwić zerwanie połączenia - co skutkuje wysłaniem DISCONNECT do serwera). 29 | - DISCONNECT: 30 | Zlecenie ustawienia klienta jako dostępnego do połączenia. 31 | - STOP: 32 | 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. 33 | 34 | Zlecenia powinny być obsługiwane zgodnie z priorytetami, najwyższy priorytet ma STOP, potem DISCONNECT oraz LIST i reszta. Można tego dokonać poprzez sterowanie parametrem MTYPE w funkcji msgsnd. 35 | 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 jest ograniczona pewną stałą (jej definicja powinna znaleźć się w pliku nagłówkowym). 36 | 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). 37 | Serwer może wysłać do klientów komunikaty: 38 | - inicjujący pracę klienta w trybie chatu (kolejka klientów) 39 | - wysyłający odpowiedzi do klientów (kolejki klientów) 40 | - 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) 41 | 42 | 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. 43 | 44 | ## Zadanie 2. Prosty chat - POSIX (50%) 45 | 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ł. -------------------------------------------------------------------------------- /cw04/readme.md: -------------------------------------------------------------------------------- 1 | # Zadania - zestaw 4 2 | Rodzaje sygnałów: SIGINT, SIGQUIT, SIGKILL, SIGTSTP, SIGSTOP, SIGTERM, SIGSEGV, SIGHUP, SIGALARM, SIGCHLD, SIGUSR1, SIGUSR2 3 | Sygnały czasu rzeczywistego: SIGRTMIN, SIGRTMIN+n, SIGRTMAX 4 | Przydatne polecenia Unix: kill, ps 5 | Przydatne funkcje systemowe: kill, raise, sigqueue, signal, sigaction, sigemptyset, sigfillset, sigaddset, sigdelset, sigismember, sigprocmask, sigpending, pause, sigsuspend 6 | ## Zadanie 1 (10%) 7 | Napisz program wypisujący w pętli nieskończonej zawartość bieżącego katalogu. 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. 8 | 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). 9 | ## Zadanie 2 (30%) 10 | Napisz program demonstrujący, czy ustawienia dyspozycji dla sygnałów są dziedziczone po wykonaniu funkcji fork oraz exec. 11 | W szczególności eksperymenty proszę wykonać dla sygnału SIGUSR1 w następujący sposób: 12 | - Dziedziczenie ustawień sygnałów po wykonaniu funkcji fork. Proszę napisać program, który w zależności od wartości argumentu z linii poleceń, może on przyjmować wartości ignore, handler, mask lub pending, odpowiednio w procesie przodka ustawia ignorowanie, instaluje handler obsługujący sygnał wypisujący komunikat o jego otrzymaniu, maskuje ten sygnał oraz sprawdza (przy zamaskowaniu tego sygnału) czy wiszący/oczekujący sygnał jest widoczny w procesie, a następnie przy pomocy funkcji raise wysyła sygnał do samego siebie oraz wykonuje odpowiednie dla danej opcji działania, po czym tworzy potomka funkcją fork i ponownie przy pomocy funkcji raise potomek wysyła sygnał do samego siebie (z wyjątkiem opcji pending, gdzie testowane jest sprawdzenie, czy sygnał czekający w przodku jest widoczny w potomku). 13 | - Dziedziczenie ustawień sygnałów po wykonaniu funkcji exec. W podobny sposób sprawdź jaki wpływ na ustawienia sygnałów ma wywołanie funkcji exec. Rozpatrz opcje: ignore, mask i pending. 14 | - Przygotuj plik raport2.txt w którym nastąpi podsumowanie z wnioskami z wykonanych powyższych eksperymentów 15 | ## Zadanie 3 (15%) 16 | Przetestuj działanie flagi SA_SIGINFO w funkcji sigation. Zainstaluj w ten sposób procedurę obsługi sygnału (handler) dla odpowiednio dobranych sygnałów stosując składnie procedury handlera z trzema argumentami. Wypisz i skomentuj (przygotowując odpowiednie scenariusze) trzy różne informacje (pomijając numer sygnału oraz identyfikator PID procesu wysyłającego) dostarczane w strukturze siginfo_t przekazywanej jako drugi argument funkcji handlera. 17 | 18 | ## Zadanie 4 (45%) 19 | 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. 20 | 21 | 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 siginfo_t 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. 22 | 23 | UWAGA! W żaden sposób nie opóźniamy wysyłania sygnałów, wszelkie "gubienie" sygnałów jest zjawiskiem naturalnym. 24 | 25 | a) Wysyłanie sygnałów w obu programach należy wykonać w następujących trybach: (30%) 26 | 27 | - KILL - za pomocą funkcji kill 28 | - 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. 29 | - 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? 30 | 31 | 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%) -------------------------------------------------------------------------------- /cw02/zad2/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #ifdef use_nftw 10 | #include 11 | #endif 12 | 13 | typedef unsigned int uint; 14 | 15 | #define config(setting, value) {\ 16 | config_##setting = value;\ 17 | config_use_##setting = true;\ 18 | } 19 | 20 | static uint config_max_depth = 1; 21 | static time_t config_atime; 22 | static time_t config_mtime; 23 | static bool config_use_atime = false; 24 | static bool config_use_mtime = false; 25 | static bool config_use_max_depth = false; 26 | static char config_mtime_mode; 27 | static char config_atime_mode; 28 | 29 | static time_t launch_time; 30 | 31 | char* file_type_name(const struct stat* s) { 32 | uint mode = s->st_mode; 33 | if (S_ISDIR(mode)) return "dir"; 34 | if (S_ISREG(mode)) return "file"; 35 | if (S_ISLNK(mode)) return "link"; 36 | if (S_ISCHR(mode)) return "char"; 37 | if (S_ISBLK(mode)) return "block"; 38 | if (S_ISFIFO(mode)) return "fifo"; 39 | if (S_ISSOCK(mode)) return "socket"; 40 | return "undefined"; 41 | } 42 | 43 | void print_file(const char* path, const struct stat* s) { 44 | static const char* time_format = "%Y-%m-%d %H:%M:%S"; 45 | static char m_time_str[20], a_time_str[20]; 46 | struct tm m_time, a_time; 47 | 48 | localtime_r(&s->st_mtime, &m_time); 49 | localtime_r(&s->st_atime, &a_time); 50 | 51 | strftime(m_time_str, 20, time_format, &m_time); 52 | strftime(a_time_str, 20, time_format, &a_time); 53 | 54 | printf("%s\t%lu\t%s\t%ld\t%s\t%s\n", 55 | path, s->st_nlink, 56 | file_type_name(s), s->st_size, 57 | a_time_str, m_time_str 58 | ); 59 | } 60 | 61 | bool match_file(const char* path, const struct stat* s) { 62 | if (config_use_mtime) { 63 | if (config_mtime_mode == '+' && difftime(s->st_mtime, config_mtime) > 0) return false; 64 | if (config_mtime_mode == '-' && difftime(s->st_mtime, config_mtime) < 0) return false; 65 | } 66 | if (config_use_atime) { 67 | if (config_atime_mode == '+' && difftime(s->st_atime, config_atime) > 0) return false; 68 | if (config_atime_mode == '-' && difftime(s->st_atime, config_atime) < 0) return false; 69 | } 70 | return true; 71 | } 72 | 73 | #ifndef use_nftw 74 | char* join_path(char* path1, char* path2) { 75 | char* path = malloc(sizeof(char) * (strlen(path1) + strlen(path2)) + 2); 76 | sprintf(path, "%s/%s", path1, path2); 77 | return path; 78 | } 79 | 80 | static void scan_dir(char* path, int depth) { 81 | if (!path || (config_use_max_depth && depth >= config_max_depth)) return; 82 | DIR* dir = opendir(path); 83 | if (!dir) return; // can not read 84 | 85 | struct dirent* d; 86 | struct stat s; 87 | while ((d = readdir(dir))) { 88 | if (strcmp(d->d_name, "..") == 0) continue; 89 | if (strcmp(d->d_name, ".") == 0) continue; 90 | 91 | char* dir = join_path(path, d->d_name); 92 | if (lstat(dir, &s) < 0) continue; // can not read 93 | if (S_ISDIR(s.st_mode)) scan_dir(dir, depth + 1); 94 | 95 | if (match_file(dir, &s)) print_file(dir, &s); 96 | free(dir); 97 | } 98 | closedir(dir); 99 | } 100 | #endif 101 | 102 | #ifdef use_nftw 103 | int filter(const char* path, const struct stat* s, int type, struct FTW* f) { 104 | if (config_use_max_depth && type == FTW_D && f->level > config_max_depth) return 1; 105 | if (!match_file(path, s)) return 1; 106 | print_file(path, s); 107 | return 0; 108 | } 109 | #endif 110 | 111 | void find(char* path) { 112 | #ifndef use_nftw 113 | struct stat s; 114 | if (lstat(path, &s) >= 0 && match_file(path, &s)) 115 | print_file(path, &s); 116 | scan_dir(path, 0); 117 | #endif 118 | #ifdef use_nftw 119 | nftw(path, filter, 0, 0); 120 | #endif 121 | } 122 | 123 | #define opt_atime_i 0 124 | #define opt_mtime_i 1 125 | #define opt_maxdepth_i 2 126 | 127 | #define case(name, code) case opt_##name##_i: code; break 128 | 129 | const struct option options[] = { 130 | {"atime", required_argument, 0, 'a'}, 131 | {"mtime", required_argument, 0, 'm'}, 132 | {"maxdepth", required_argument, 0, 0 }, 133 | {0, 0, 0, 0} 134 | }; 135 | 136 | int main(int argc, char** argv) { 137 | char* search_path = argc > 1 ? argv[1] : "."; 138 | 139 | time(&launch_time); 140 | struct tm* timeinfo; 141 | for (int option; getopt_long_only(argc, argv, "", options, &option) >= 0;) { 142 | switch (option) { 143 | case(atime, { 144 | int arg = atoi(optarg); 145 | timeinfo = localtime(&launch_time); 146 | timeinfo->tm_mday -= abs(arg); 147 | if (arg > 0) timeinfo->tm_mday -= 1; 148 | config_atime_mode = arg >= 0 ? '+' : '-'; 149 | 150 | config(atime, mktime(timeinfo)); 151 | }); 152 | case(mtime, { 153 | int arg = atoi(optarg); 154 | timeinfo = localtime(&launch_time); 155 | timeinfo->tm_mday -= abs(arg); 156 | if (arg > 0) timeinfo->tm_mday -= 1; 157 | config_mtime_mode = arg >= 0 ? '+' : '-'; 158 | 159 | config(mtime, mktime(timeinfo)); 160 | }); 161 | case(maxdepth, config(max_depth, atoi(optarg)) ); 162 | } 163 | } 164 | find(search_path); 165 | return 0; 166 | } -------------------------------------------------------------------------------- /cw01/readme.md: -------------------------------------------------------------------------------- 1 | # Zarządzanie pamięcią, biblioteki, pomiar czasu 2 | 3 | ## Zadanie 1. Alokacja tablicy ze wskaźnikami na bloki pamięci zawierające tablicę wskaźników (25%) 4 | 5 | Zaprojektuj i przygotuj zestaw funkcji (bibliotekę) do zarządzania tablicą bloków, w których to blokach pamięci zapisywane są rezultaty operacji porównywania plików wiersz po wierszu (poleceniem ```diff```) sekwencji par plików — sekwencja ich nazw jest parametrem funkcji. 6 | 7 | Biblioteka powinna umożliwiać: 8 | 9 | * Utworzenie tablicy wskaźników (tablicy głównej) — w tej tablicy będą przechowywane wskaźniki na bloki operacji edycyjnych — pierwszy element tablicy głównej zawiera wykaz operacji edycyjnych dla pierwszej pary plików, drugi element dla drugiej pary, itd. Pojedynczy blok operacji edycyjnych (element wskazywany z tablicy głównej), to tablica wskaźników na poszczególne operacje edycyjne 10 | * Definiowanie sekwencji par plików 11 | * Przeprowadzenie porównania (dla każdego elementu sekwencji) oraz zapisanie wyniku porównania do pliku tymczasowego 12 | * Utworzenie, na podstawie zawartość pliku tymczasowego, bloku operacji edycyjnych — tablicy wskaźników na operacje edycyjne, ustawienie w tablicy głównej (wskaźników) wskazania na ten blok; na końcu, funkcja powinna zwrócić indeks elementu tablicy (głównej), który zawiera wskazanie na utworzony blok — dla pokazanego (niżej) przykładu powinna więc zwrócić 0 13 | * Zwrócenie informacji o ilości operacji w danym bloku operacji edycyjnych — dla przykładu, pokazanego poniżej, zwracaną wartością powinno być 3 14 | * Usunięcie, z pamięci, bloku (operacji edycyjnych) o zadanym indeksie 15 | * Usunięcie, z pamięci, określonej operacji dla podanego bloku operacji edycyjnych 16 | 17 | **Przykład** — załóżmy, że sekwencja nazw plików zawiera tylko jedną parę ('a.txt', 'b.txt'). 18 | 19 | Zawartość pliku a.txt: 20 | 21 | aaa 22 | bbb ccc 23 | ddd 24 | eee 25 | hhh iii 26 | 27 | Zawartość pliku b.txt: 28 | 29 | jjj kkk 30 | aaa 31 | fff ccc 32 | eee 33 | bbb ggg 34 | 35 | Wynik wykonania ```diff a.txt b.txt```: 36 | 37 | 0a1 38 | > jjj kkk 39 | 2,3c3 40 | < bbb ccc 41 | < ddd 42 | --- 43 | > fff ccc 44 | 5c5 45 | < hhh iii 46 | --- 47 | > bbb ggg 48 | 49 | W tym przypadku tablica główna powinna zawierać tylko jeden wskaźnik na blok operacji edycyjnych (bo mamy tylko jedną parę plików). Blok operacji edycyjnych powinien być trzyelementową tablicą wskaźników na napisy z treścią operacji edycyjnych. 50 | 51 | ![Struktura danych](https://i.postimg.cc/ZK16VCCC/foo.jpg "Struktura danych") 52 | 53 | Tablice / bloki powinny być alokowane przy pomocy funkcji calloc() (alokacja dynamiczna). 54 | 55 | 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ą. 56 | 57 | ## Zadanie 2. Program korzystający z biblioteki (25%) 58 | 59 | Napisz program testujący działanie funkcji z biblioteki z zadania 1. 60 | 61 | Jako argumenty przekaż liczbę elementów tablicy głównej (liczbę par plików) oraz listę zadań do wykonania. Zadania mogą stanowić zadania porównania wszystkich par w sekwencji lub zadania usunięcia bloku o podanym indeksie bądź usunięcia operacji o podanym indeksie. 62 | 63 | Operacje mogą być specyfikowane w linii poleceń na przykład jak poniżej: 64 | 65 | * create_table rozmiar — stworzenie tablicy o rozmiarze "rozmiar" 66 | * compare_pairs file1A.txt:file1B.txt file2A.txt:file2B.txt … — porównanie para plików: file1A.txt z file1B.txt, file2A.txt z file2B.txt, itd 67 | * remove_block index- usuń z tablicy bloków o indeksie index 68 | * remove_operation block_index operation_index — usuń z bloku o indeksie block_index operację o indeksie operation_index 69 | 70 | Program powinien stworzyć tablice bloków o zadanej liczbie elementów 71 | 72 | W programie zmierz, wypisz na konsolę i zapisz do pliku z raportem czasy realizacji podstawowych operacji: 73 | 74 | * Przeprowadzenie porównania par plików — różna ilość elementów w sekwencji par (mała (np. 1-5), średnia oraz duża ilość par) oraz różny stopień podobieństwa plików w parze (pliki bardzo podobne do siebie, pliki w średnim stopniu niepodobne do siebie, pliki w znacznym stopniu niepodobne do siebie) 75 | * Zapisanie, w pamięci, bloków o różnych rozmiarach (odpowiadających rozmiarom różnych przeprowadzonych porównań) 76 | * Usunięcie zaalokowanych bloków o różnych rozmiarach (odpowiadających rozmiarom różnych przeprowadzonych porównań) 77 | * Na przemian kilkakrotne dodanie i usunięcie zadanej liczby bloków 78 | 79 | 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. 80 | ## Zadanie 3. Testy i pomiary (50%) 81 | 82 | 1. (25%) Przygotuj plik Makefile, zawierający polecenie uruchamiania testów oraz polecenia kompilacji programu z zad 2 na trzy sposoby: 83 | * Z wykorzystaniem bibliotek statycznych, 84 | * Z wykorzystaniem bibliotek dzielonych (dynamiczne, ładowane przy uruchomieniu programu), 85 | * Z wykorzystaniem bibliotek ładowanych dynamicznie (dynamiczne, ładowane przez program). 86 | 87 | Wyniki pomiarów zbierz w pliku results3a.txt. Otrzymane wyniki krótko skomentuj. 88 | 2. (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 różnych poziomów optymalizacji. 89 | Wyniki pomiarów dodaj do pliku results3b.txt. Otrzymane wyniki krótko skomentuj. 90 | 91 | Wygenerowane pliki z raportami załącz jako element rozwiązania. 92 | 93 | **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)```. -------------------------------------------------------------------------------- /cw10/zad1/client.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "message.h" 3 | 4 | int connect_unix(char* path) { 5 | struct sockaddr_un addr; 6 | memset(&addr, 0, sizeof(addr)); 7 | addr.sun_family = AF_UNIX; 8 | strncpy(addr.sun_path, path, sizeof addr.sun_path); 9 | 10 | int sock = safe (socket(AF_UNIX, SOCK_STREAM, 0)); 11 | safe (connect(sock, (struct sockaddr*) &addr, sizeof addr)); 12 | 13 | return sock; 14 | } 15 | 16 | int connect_web(char* ipv4, int port) { 17 | struct sockaddr_in addr; 18 | memset(&addr, 0, sizeof(addr)); 19 | addr.sin_family = AF_INET; 20 | addr.sin_port = htons(port); 21 | if (inet_pton(AF_INET, ipv4, &addr.sin_addr) <= 0) { 22 | print("Invalid address\n"); 23 | exit(0); 24 | } 25 | 26 | int sock = safe (socket(AF_INET, SOCK_STREAM, 0)); 27 | safe (connect(sock, (struct sockaddr*) &addr, sizeof addr)); 28 | 29 | return sock; 30 | } 31 | 32 | struct state { 33 | int score[2]; 34 | char* nicknames[2]; 35 | char* symbols[2]; 36 | char symbol; 37 | struct game_state game; 38 | } state; 39 | 40 | static const char board[] = 41 | "\033[0;0H\033[J\033[90m\n" 42 | " 1 │ 2 │ 3 you\033[0m (%s) %s\n\033[90m" 43 | " ───┼───┼─── \033[0m (%s) %s\n\033[90m" 44 | " 4 │ 5 │ 6 \n" 45 | " ───┼───┼───\n" 46 | " 7 │ 8 │ 9 \n\n\033[0m"; 47 | void draw_initial_state() { 48 | dprintf(STDOUT_FILENO, board, 49 | state.symbols[0], state.nicknames[0], 50 | state.symbols[1], state.nicknames[1]); 51 | } 52 | 53 | void cell(int x, int y, char* text) { 54 | dprintf(STDOUT_FILENO, "\033[s\033[%d;%dH%s\033[u", y * 2 + 2, x * 4 + 4, text); 55 | } 56 | 57 | void render_footer() { 58 | if (state.game.move != state.symbol) 59 | print("\033[8;0H\033[J\r [ ] \033[33mWait for your move.\r\033[0m\r\033[2C"); 60 | else print("\033[8;0H\033[J\r [ ]\033[J\r\033[2C"); 61 | } 62 | 63 | void render_update() { 64 | static char tmp[12]; 65 | for (int x = 0; x < 3; x++) 66 | for (int y = 0; y < 3; y++) { 67 | int c = x + y * 3; 68 | if (state.game.board[c] == '-') { 69 | sprintf(tmp, "\033[90m%d\033[0m", c + 1); 70 | cell(x, y, tmp); 71 | } 72 | else cell(x, y, state.symbols[state.game.board[x + y * 3] == state.symbol ? 0 : 1]); 73 | } 74 | render_footer(); 75 | } 76 | 77 | int sock; 78 | void on_SIGINT(int _) { 79 | message msg = { .type = msg_disconnect }; 80 | write(sock, &msg, sizeof msg); 81 | exit(0); 82 | } 83 | 84 | int main(int argc, char** argv) { 85 | if (strcmp(argv[2], "web") == 0 && argc == 5) sock = connect_web(argv[3], atoi(argv[4])); 86 | else if (strcmp(argv[2], "unix") == 0 && argc == 4) sock = connect_unix(argv[3]); 87 | else { 88 | print("Usage [nick] [web|unix] [ip port|path]\n"); 89 | exit(0); 90 | } 91 | 92 | signal(SIGINT, on_SIGINT); 93 | char* nickname = state.nicknames[0] = argv[1]; 94 | write(sock, nickname, strlen(nickname)); 95 | 96 | int epoll_fd = safe (epoll_create1(0)); 97 | 98 | struct epoll_event stdin_event = { 99 | .events = EPOLLIN | EPOLLPRI, 100 | .data = { .fd = STDIN_FILENO } 101 | }; 102 | epoll_ctl(epoll_fd, EPOLL_CTL_ADD, STDIN_FILENO, &stdin_event); 103 | 104 | struct epoll_event socket_event = { 105 | .events = EPOLLIN | EPOLLPRI | EPOLLHUP, 106 | .data = { .fd = sock } 107 | }; 108 | epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock, &socket_event); 109 | 110 | int c; 111 | struct epoll_event events[2]; 112 | loop { 113 | int nread = safe (epoll_wait(epoll_fd, events, 2, 1)); 114 | repeat(nread) { 115 | if (events[i].data.fd == STDIN_FILENO) { 116 | if (scanf("%d", &c) != 1) { 117 | char x; 118 | while ((x = getchar()) != EOF && x != '\n'); // skip invalid input 119 | render_footer(); 120 | continue; 121 | } 122 | render_footer(); 123 | if (c < 1 || c > 9) continue; 124 | c -= 1; 125 | int x = c % 3, y = c / 3; 126 | 127 | if (state.game.board[c] == '-') { 128 | cell(x, y, state.symbols[0]); 129 | message msg = { .type = msg_move }; 130 | msg.payload.move = c; 131 | write(sock, &msg, sizeof msg); 132 | } 133 | } else { 134 | message msg; 135 | read(sock, &msg, sizeof msg); 136 | if (msg.type == msg_wait) { 137 | print("Waiting for an opponent\n"); 138 | } else if (msg.type == msg_play) { 139 | state.nicknames[1] = msg.payload.play.nickname; 140 | state.symbols[1] = msg.payload.play.symbol == 'o' ? "\033[36mx\033[0m" : "\033[32mo\033[0m"; 141 | state.symbol = msg.payload.play.symbol; 142 | state.symbols[0] = msg.payload.play.symbol == 'o' ? "\033[32mo\033[0m" : "\033[36mx\033[0m"; 143 | state.score[0] = state.score[1] = 0; 144 | draw_initial_state(); 145 | } else if (msg.type == msg_username_taken) { 146 | print("This username is already taken\n"); 147 | close(sock); 148 | exit(0); 149 | } else if (msg.type == msg_server_full) { 150 | print("Server is full\n"); 151 | close(sock); 152 | exit(0); 153 | } else if (events[i].events & EPOLLHUP) { 154 | print("\033[8;0H\033[J\r Disconnected X_x\n\n"); 155 | exit(0); 156 | } else if (msg.type == msg_ping) 157 | write(sock, &msg, sizeof msg); 158 | else if (msg.type == msg_state) { 159 | memcpy(&state.game, &msg.payload.state, sizeof state.game); 160 | render_update(); 161 | } else if (msg.type == msg_win) { 162 | if (msg.payload.win == state.symbol) print("\033[8;0H\033[J\r You won ^.^\33[J\n\n"); 163 | else if (msg.payload.win == '-') print("\033[8;0H\033[J\r It's a draw O_o\33[J\n\n"); 164 | else print("\033[8;0H\033[J\r You lost T_T\n\n"); 165 | close(sock); 166 | exit(0); 167 | } 168 | } 169 | } 170 | } 171 | } -------------------------------------------------------------------------------- /cw10/zad2/client.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "message.h" 3 | #include 4 | 5 | int connect_unix(char* path, char* user) { 6 | struct sockaddr_un addr, bind_addr; 7 | memset(&addr, 0, sizeof(addr)); 8 | bind_addr.sun_family = AF_UNIX; 9 | addr.sun_family = AF_UNIX; 10 | snprintf(bind_addr.sun_path, sizeof bind_addr.sun_path, "/tmp/%s%ld", user, time(NULL)); 11 | strncpy(addr.sun_path, path, sizeof addr.sun_path); 12 | 13 | int sock = safe (socket(AF_UNIX, SOCK_DGRAM, 0)); 14 | safe (bind(sock, (void*) &bind_addr, sizeof addr)); 15 | safe (connect(sock, (struct sockaddr*) &addr, sizeof addr)); 16 | 17 | return sock; 18 | } 19 | 20 | int connect_web(char* ipv4, int port) { 21 | struct sockaddr_in addr; 22 | memset(&addr, 0, sizeof(addr)); 23 | addr.sin_family = AF_INET; 24 | addr.sin_port = htons(port); 25 | if (inet_pton(AF_INET, ipv4, &addr.sin_addr) <= 0) { 26 | print("Invalid address\n"); 27 | exit(0); 28 | } 29 | 30 | int sock = safe (socket(AF_INET, SOCK_DGRAM, 0)); 31 | safe (connect(sock, (struct sockaddr*) &addr, sizeof addr)); 32 | 33 | return sock; 34 | } 35 | 36 | struct state { 37 | int score[2]; 38 | char* nicknames[2]; 39 | char* symbols[2]; 40 | char symbol; 41 | struct game_state game; 42 | } state; 43 | 44 | static const char board[] = 45 | "\033[0;0H\033[J\033[90m\n" 46 | " 1 │ 2 │ 3 you\033[0m (%s) %s\n\033[90m" 47 | " ───┼───┼─── \033[0m (%s) %s\n\033[90m" 48 | " 4 │ 5 │ 6 \n" 49 | " ───┼───┼───\n" 50 | " 7 │ 8 │ 9 \n\n\033[0m"; 51 | void draw_initial_state() { 52 | dprintf(STDOUT_FILENO, board, 53 | state.symbols[0], state.nicknames[0], 54 | state.symbols[1], state.nicknames[1]); 55 | } 56 | 57 | void cell(int x, int y, char* text) { 58 | dprintf(STDOUT_FILENO, "\033[s\033[%d;%dH%s\033[u", y * 2 + 2, x * 4 + 4, text); 59 | } 60 | 61 | void render_footer() { 62 | if (state.game.move != state.symbol) 63 | print("\033[8;0H\033[J\r [ ] \033[33mWait for your move.\r\033[0m\r\033[2C"); 64 | else print("\033[8;0H\033[J\r [ ]\033[J\r\033[2C"); 65 | } 66 | 67 | void render_update() { 68 | static char tmp[12]; 69 | for (int x = 0; x < 3; x++) 70 | for (int y = 0; y < 3; y++) { 71 | int c = x + y * 3; 72 | if (state.game.board[c] == '-') { 73 | sprintf(tmp, "\033[90m%d\033[0m", c + 1); 74 | cell(x, y, tmp); 75 | } 76 | else cell(x, y, state.symbols[state.game.board[x + y * 3] == state.symbol ? 0 : 1]); 77 | } 78 | render_footer(); 79 | } 80 | 81 | int sock; 82 | void on_SIGINT(int _) { 83 | message msg = {.type = msg_disconnect}; 84 | send(sock, &msg, sizeof msg, 0); 85 | exit(0); 86 | } 87 | 88 | int main(int argc, char** argv) { 89 | char* nickname; 90 | if (argc > 2) nickname = state.nicknames[0] = argv[1]; 91 | if (argc == 5 && strcmp(argv[2], "web") == 0) sock = connect_web(argv[3], atoi(argv[4])); 92 | else if (argc == 4 && strcmp(argv[2], "unix") == 0) sock = connect_unix(argv[3], nickname); 93 | else { 94 | print("Usage [nick] [web|unix] [ip port|path]\n"); 95 | exit(0); 96 | } 97 | 98 | signal(SIGINT, on_SIGINT); 99 | 100 | message msg = { .type = msg_connect }; 101 | strncpy(msg.payload.nickname, nickname, sizeof msg.payload.nickname); 102 | send(sock, &msg, sizeof msg, 0); 103 | 104 | int epoll_fd = safe (epoll_create1(0)); 105 | 106 | struct epoll_event stdin_event = { 107 | .events = EPOLLIN | EPOLLPRI, 108 | .data = { .fd = STDIN_FILENO } 109 | }; 110 | epoll_ctl(epoll_fd, EPOLL_CTL_ADD, STDIN_FILENO, &stdin_event); 111 | 112 | struct epoll_event socket_event = { 113 | .events = EPOLLIN | EPOLLPRI | EPOLLHUP, 114 | .data = { .fd = sock } 115 | }; 116 | epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock, &socket_event); 117 | 118 | int c; 119 | struct epoll_event events[2]; 120 | loop { 121 | int nread = safe (epoll_wait(epoll_fd, events, 2, 1)); 122 | repeat(nread) { 123 | if (events[i].data.fd == STDIN_FILENO) { 124 | if (scanf("%d", &c) != 1) { 125 | char x; 126 | while ((x = getchar()) != EOF && x != '\n'); // skip invalid input 127 | render_footer(); 128 | continue; 129 | } 130 | render_footer(); 131 | if (c < 1 || c > 9) continue; 132 | c -= 1; 133 | int x = c % 3, y = c / 3; 134 | 135 | if (state.game.board[c] == '-') { 136 | cell(x, y, state.symbols[0]); 137 | message msg = { .type = msg_move }; 138 | msg.payload.move = c; 139 | sendto(sock, &msg, sizeof msg, 0, NULL, sizeof(struct sockaddr_in)); 140 | } 141 | } else { 142 | message msg; 143 | recvfrom(sock, &msg, sizeof msg, 0, NULL, NULL); 144 | if (msg.type == msg_wait) { 145 | print("Waiting for an opponent\n"); 146 | } else if (msg.type == msg_play) { 147 | state.nicknames[1] = msg.payload.play.nickname; 148 | state.symbols[1] = msg.payload.play.symbol == 'o' ? "\033[36mx\033[0m" : "\033[32mo\033[0m"; 149 | state.symbol = msg.payload.play.symbol; 150 | state.symbols[0] = msg.payload.play.symbol == 'o' ? "\033[32mo\033[0m" : "\033[36mx\033[0m"; 151 | state.score[0] = state.score[1] = 0; 152 | draw_initial_state(); 153 | } else if (msg.type == msg_username_taken) { 154 | print("This username is already taken\n"); 155 | close(sock); 156 | exit(0); 157 | } else if (msg.type == msg_disconnect) { 158 | exit(0); 159 | } else if (msg.type == msg_server_full) { 160 | print("Server is full\n"); 161 | close(sock); 162 | exit(0); 163 | } else if (events[i].events & EPOLLHUP) { 164 | print("\033[8;0H\033[J\r Disconnected X_x\n\n"); 165 | exit(0); 166 | } else if (msg.type == msg_ping) 167 | write(sock, &msg, sizeof msg); 168 | else if (msg.type == msg_state) { 169 | memcpy(&state.game, &msg.payload.state, sizeof state.game); 170 | render_update(); 171 | } else if (msg.type == msg_win) { 172 | if (msg.payload.win == state.symbol) print("\033[8;0H\033[J\r You won ^.^\33[J\n\n"); 173 | else if (msg.payload.win == '-') print("\033[8;0H\033[J\r It's a draw O_o\33[J\n\n"); 174 | else print("\033[8;0H\033[J\r You lost T_T\n\n"); 175 | exit(0); 176 | } 177 | } 178 | } 179 | } 180 | } -------------------------------------------------------------------------------- /cw10/zad2/server.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "message.h" 3 | #include 4 | 5 | #define MAX_CONN 16 6 | #define PING_INTERVAL 20 7 | 8 | pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 9 | 10 | int epoll_fd; 11 | 12 | union addr { 13 | struct sockaddr_un uni; 14 | struct sockaddr_in web; 15 | }; 16 | typedef struct sockaddr* sa; 17 | 18 | struct client { 19 | union addr addr; 20 | int sock, addrlen; 21 | enum client_state { empty = 0, waiting, playing } state; 22 | struct client* peer; 23 | char nickname[16]; 24 | char symbol; 25 | struct game_state* game_state; 26 | bool responding; 27 | } clients[MAX_CONN], *waiting_client = NULL; 28 | typedef struct client client; 29 | 30 | void delete_client(client* client) { 31 | printf("Deleting %s\n", client->nickname); 32 | if (client == waiting_client) waiting_client = NULL; 33 | if (client->peer) { 34 | client->peer->peer = NULL; 35 | client->peer->game_state = NULL; 36 | delete_client(client->peer); 37 | free(client->game_state); 38 | client->peer = NULL; 39 | client->game_state = NULL; 40 | } 41 | message msg = { .type = msg_disconnect }; 42 | sendto(client->sock, &msg, sizeof msg, 0, (sa) &client->addr, client->addrlen); 43 | memset(&client->addr, 0, sizeof client->addr); 44 | client->state = empty; 45 | client->sock = 0; 46 | client->nickname[0] = 0; 47 | } 48 | 49 | void send_gamestate(client* client) { 50 | message msg = { .type = msg_state }; 51 | memcpy(&msg.payload.state, client->game_state, sizeof (struct game_state)); 52 | sendto(client->sock, &msg, sizeof msg, 0, (sa) &client->addr, client->addrlen); 53 | } 54 | 55 | int cell_coord(int x, int y) { 56 | return x + y * 3; 57 | } 58 | 59 | bool check_game(client* client) { 60 | static int win[8][3] = { 61 | {0, 1, 2}, {3, 4, 5}, {6, 7, 8}, {0, 3, 6}, 62 | {1, 4, 7}, {2, 5, 8}, {0, 4, 8}, {2, 4, 6} 63 | }; 64 | char* board = client->game_state->board; 65 | char c = client->symbol; 66 | for (int i = 0; i < 8; i++) { 67 | if (board[win[i][0]] == c && 68 | board[win[i][1]] == c && 69 | board[win[i][2]] == c) 70 | return true; 71 | } 72 | return false; 73 | } 74 | 75 | bool check_draw(client* client) { 76 | for (int i = 0; i < 9; i++) 77 | if (client->game_state->board[i] == '-') 78 | return false; 79 | return true; 80 | } 81 | 82 | void join_clients(client* client1, client* client2) { 83 | client1->state = client2->state = playing; 84 | client1->peer = client2; 85 | client2->peer = client1; 86 | 87 | client1->game_state = client2->game_state = calloc(1, sizeof client1->game_state); 88 | memset(client1->game_state->board, '-', 9); 89 | 90 | message msg = { .type = msg_play }; 91 | strncpy(msg.payload.play.nickname, client2->nickname, sizeof client2->nickname); 92 | client1->symbol = msg.payload.play.symbol = 'x'; 93 | sendto(client1->sock, &msg, sizeof msg, 0, (sa) &client1->addr, client1->addrlen); 94 | 95 | strncpy(msg.payload.play.nickname, client1->nickname, sizeof client1->nickname); 96 | client2->symbol = msg.payload.play.symbol = 'o'; 97 | sendto(client2->sock, &msg, sizeof msg, 0, (sa) &client2->addr, client2->addrlen); 98 | 99 | client1->game_state->move = client1->symbol; 100 | send_gamestate(client1); 101 | send_gamestate(client2); 102 | } 103 | 104 | void on_client_message(client* client, message* msg) { 105 | if (msg->type == msg_ping) { 106 | pthread_mutex_lock(&mutex); 107 | printf("pong %s\n", client->nickname); 108 | client->responding = true; 109 | pthread_mutex_unlock(&mutex); 110 | } 111 | else if (msg->type == msg_disconnect) { 112 | pthread_mutex_lock(&mutex); 113 | delete_client(client); 114 | pthread_mutex_unlock(&mutex); 115 | } else if (msg->type == msg_move) { 116 | int move = msg->payload.move; 117 | if (msg->type != msg_move) return; 118 | if (client->game_state->move == client->symbol 119 | && client->game_state->board[move] == '-' 120 | && 0 <= move && move <= 8) { 121 | client->game_state->board[move] = client->symbol; 122 | client->game_state->move = client->peer->symbol; 123 | 124 | printf("%s moved\n", client->nickname); 125 | send_gamestate(client); 126 | send_gamestate(client->peer); 127 | if (check_game(client)) { 128 | msg->type = msg_win; 129 | msg->payload.win = client->symbol; 130 | } 131 | else if (check_draw(client)) { 132 | msg->type = msg_win; 133 | msg->payload.win = '-'; 134 | } 135 | if (msg->type == msg_win) { 136 | printf("Game between %s and %s finised\n", client->nickname, client->peer->nickname); 137 | client->peer->peer = NULL; 138 | sendto(client->peer->sock, msg, sizeof msg, 0, (sa) &client->peer->addr, client->peer->addrlen); 139 | sendto(client->sock, msg, sizeof msg, 0, (sa) &client->addr, client->addrlen); 140 | delete_client(client); 141 | } 142 | } 143 | else send_gamestate(client); 144 | } 145 | } 146 | 147 | void init_socket(int socket, void* addr, int addr_size) { 148 | safe (bind(socket, (struct sockaddr*) addr, addr_size)); 149 | struct epoll_event event = { 150 | .events = EPOLLIN | EPOLLPRI, 151 | .data = { .fd = socket } 152 | }; 153 | epoll_ctl(epoll_fd, EPOLL_CTL_ADD, socket, &event); 154 | } 155 | 156 | void new_client(union addr* addr, socklen_t addrlen, int sock, char* nickname) { 157 | pthread_mutex_lock(&mutex); 158 | int empty_index = -1; 159 | for (int i = 0; i < MAX_CONN; i++) { 160 | if (clients[i].state == empty) empty_index = i; 161 | else if (strncmp(nickname, clients[i].nickname, sizeof clients->nickname) == 0) { 162 | pthread_mutex_unlock(&mutex); 163 | message msg = {.type = msg_username_taken }; 164 | printf("Nickname %s already taken\n", nickname); 165 | sendto(sock, &msg, sizeof msg, 0, (sa) addr, addrlen); 166 | return; 167 | } 168 | } 169 | if (empty_index == -1) { 170 | pthread_mutex_unlock(&mutex); 171 | printf("Server is full\n"); 172 | message msg = { .type = msg_server_full }; 173 | sendto(sock, &msg, sizeof msg, 0, (sa) addr, addrlen); 174 | return; 175 | } 176 | printf("New client %s\n", nickname); 177 | client* client = &clients[empty_index]; 178 | memcpy(&client->addr, addr, addrlen); 179 | client->addrlen = addrlen; 180 | client->state = waiting; 181 | client->responding = true; 182 | client->sock = sock; 183 | 184 | memset(client->nickname, 0, sizeof client->nickname); 185 | strncpy(client->nickname, nickname, sizeof client->nickname - 1); 186 | if (waiting_client) { 187 | printf("Connecting %s with %s\n", client->nickname, waiting_client->nickname); 188 | if (rand() % 2 == 0) join_clients(client, waiting_client); 189 | else join_clients(waiting_client, client); 190 | waiting_client = NULL; 191 | } else { 192 | printf("%s is waiting\n", client->nickname); 193 | message msg = { .type = msg_wait }; 194 | sendto(client->sock, &msg, sizeof msg, 0, (sa) &client->addr, client->addrlen); 195 | waiting_client = client; 196 | } 197 | 198 | pthread_mutex_unlock(&mutex); 199 | } 200 | 201 | void* ping(void* _) { 202 | const static message msg = { .type = msg_ping }; 203 | loop { 204 | sleep(PING_INTERVAL); 205 | pthread_mutex_lock(&mutex); 206 | printf("Pinging clients\n"); 207 | for (int i = 0; i < MAX_CONN; i++) { 208 | if (clients[i].state != empty) { 209 | if (clients[i].responding) { 210 | clients[i].responding = false; 211 | sendto(clients[i].sock, &msg, sizeof msg, 0, (sa) &clients[i].addr, clients[i].addrlen); 212 | } 213 | else delete_client(&clients[i]); 214 | } 215 | } 216 | pthread_mutex_unlock(&mutex); 217 | } 218 | return NULL; 219 | } 220 | 221 | int main(int argc, char** argv) { 222 | if (argc != 3) { 223 | print("Usage [port] [path]\n"); 224 | exit(0); 225 | } 226 | int port = atoi(argv[1]); 227 | char* socket_path = argv[2]; 228 | 229 | epoll_fd = safe (epoll_create1(0)); 230 | 231 | struct sockaddr_un local_addr = { .sun_family = AF_UNIX }; 232 | strncpy(local_addr.sun_path, socket_path, sizeof local_addr.sun_path); 233 | 234 | struct sockaddr_in web_addr = { 235 | .sin_family = AF_INET, .sin_port = htons(port), 236 | .sin_addr = { .s_addr = htonl(INADDR_ANY) }, 237 | }; 238 | 239 | unlink(socket_path); 240 | int local_sock = safe (socket(AF_UNIX, SOCK_DGRAM, 0)); 241 | init_socket(local_sock, &local_addr, sizeof local_addr); 242 | 243 | int web_sock = safe (socket(AF_INET, SOCK_DGRAM, 0)); 244 | init_socket(web_sock, &web_addr, sizeof web_addr); 245 | 246 | pthread_t ping_thread; 247 | pthread_create(&ping_thread, NULL, ping, NULL); 248 | 249 | struct epoll_event events[10]; 250 | loop { 251 | int nread = safe (epoll_wait(epoll_fd, events, 10, -1)); 252 | repeat (nread) { 253 | int sock = events[i].data.fd; 254 | message msg; 255 | union addr addr; 256 | socklen_t addrlen = sizeof addr; 257 | recvfrom(sock, &msg, sizeof msg, 0, (sa) &addr, &addrlen); 258 | if (msg.type == msg_connect) { 259 | new_client(&addr, addrlen, sock, msg.payload.nickname); 260 | } else { 261 | int i = find(int i = 0; i < MAX_CONN; i++, memcmp(&clients[i].addr, &addr, addrlen) == 0); 262 | on_client_message(&clients[i], &msg); 263 | } 264 | } 265 | } 266 | } --------------------------------------------------------------------------------