├── 2019-2020 ├── 10-exec │ ├── 3.sh │ ├── 5.py │ ├── 8.x │ ├── 7.c │ ├── 4.c │ ├── 9.c │ ├── 2.c │ ├── 1.c │ └── 6.c ├── 07-make │ ├── r.h │ ├── r.c │ ├── m.c │ ├── Makefile │ └── r2.c ├── 01-args │ └── 1-args.c ├── 02-syscalls │ ├── 4-cat.c │ ├── 1-int-overflow.c │ ├── 2-hello-world.s │ └── 3-cat.S ├── 06-mmap │ ├── 1-count-digits.c │ ├── 4-anon-mmap.c │ ├── 3-generate.c │ └── 2-count-digits-mmap.c ├── 12-signal │ ├── 03-sigaction.c │ ├── 01-bsd-signal-handling.c │ ├── 07-wait-for-signal-usleep.c │ ├── 04-async-signal-safe.c │ ├── 05-wait-for-signal-busy.c │ ├── 06-wait-for-signal-pause.c │ └── 02-sysv-signal-handling.c ├── 08-dlopen │ ├── r.h │ ├── Makefile │ ├── r.c │ ├── m.c │ └── r2.c ├── 03-file-syscalls │ ├── 4-umask.c │ ├── 1-open-read.c │ ├── 2-open-append.c │ └── 3-lseek-negative.c ├── 11-pipe │ ├── 1-pipesize.c │ ├── 3-runpipe2.c │ ├── 2-runpipe.c │ └── 4-pingpong.c ├── shestimer │ ├── t.c │ └── t_2.c ├── 04-stat-time │ ├── 2-mktime.c │ └── 1-stat.c ├── 13-signal-safe │ ├── 01-ping-pong-basic.c │ ├── 02-ping-pong-siginfo.c │ ├── 06-ping-pong-signalfd.c │ ├── 04-ping-pong-sigsuspend.c │ ├── 03-ping-pong-sigprocmask.c │ └── 05-ping-pong-async-safe.c ├── 05-opendir │ ├── 1-snprintf.c │ └── 2-asprintf.c ├── 09-fork │ └── 1-fork-wait.c └── 14-ipc │ ├── 01-ping-pong.c │ └── 02-philosophers.c ├── 2017-2018 ├── sem14 │ ├── .gitignore │ ├── Makefile │ ├── bitmap.c │ ├── client.c │ └── server.c ├── sem11 │ ├── fill.sh │ ├── ex03-pipe-buf.c │ ├── ex01-pipesize.c │ ├── ex04-pipeline.c │ ├── ex05-pipeline-2.c │ ├── ex02-pipesize-auto.c │ └── ex06-ping-pong.c ├── sem04 │ ├── fs-1.pdf │ └── fs-2.pdf ├── sem02 │ ├── sem02.pdf │ └── example.c ├── sem06 │ ├── 19-mmap.pdf │ ├── 20-memmng.pdf │ ├── ex08-myso.c │ ├── ex01-stdio.c │ ├── ex08-useso.c │ ├── ex09-useself.c │ ├── ex07-mmap6.c │ ├── ex02-mmap1.c │ ├── ex06-mmap5.c │ ├── ex03-mmap2.c │ ├── ex05-mmap4.c │ └── ex04-mmap3.c ├── sem08 │ ├── 02threads.pdf │ ├── ex03-create-10.c │ ├── ex02-data-race.c │ ├── ex04-create-with-cast.c │ ├── ex01-create.c │ ├── ex07-race-cond.c │ ├── ex06-thread-unsafe.c │ └── ex05-stress.c ├── sem12 │ ├── signal-1.pdf │ ├── signal-2.pdf │ ├── sem-signals.pdf │ ├── ex01-sig1.c │ ├── ex05-pingpong1.c │ ├── ex02-sig2.c │ ├── ex03-sig3.c │ ├── ex06-pingpong2.c │ └── ex04-sig4.c ├── sem07 │ ├── 06-pointers.pdf │ ├── ex01-wchar.c │ ├── ex04-rand-oop │ │ ├── randint.h │ │ ├── prng.c │ │ ├── randuse.c │ │ └── trng.c │ ├── ex03-rand2.c │ └── ex02-rand1.c ├── sem10 │ ├── ex08-shellscript.sh │ ├── ex10-myinter.xx │ ├── ex07-shebang.py │ ├── ex09-inter.c │ ├── ex01-waitstatus.c │ ├── ex03-arbitrary-argv0.c │ ├── ex04-shell-use.c │ ├── ex02-waitpid.c │ ├── ex05-execve.c │ └── ex06-redir.c ├── sem03 │ ├── hello-syscalls-c.c │ ├── stdio-unlocked.c │ ├── syscalls-are-slow.c │ ├── stdio-buffered.c │ ├── read-from-stdin.c │ ├── lseek-example.c │ ├── hello-syscalls-libc.S │ ├── open-example.c │ ├── hello-syscalls.S │ ├── redirect-example.c │ └── README.md ├── sem09 │ ├── ex01-avalanche.c │ ├── ex02-buffering.c │ ├── ex06-forkbomb.c │ ├── ex03-_exit.c │ ├── ex07-oom.c │ ├── ex04-fork-exec.c │ └── ex05-syscall.c ├── sem05 │ ├── ex02-readdir.c │ ├── ex01-printmax.c │ ├── ex03-scandir-bad-1.c │ ├── ex06-scandir-2.c │ ├── ex04-scandir-bad-2.c │ ├── ex05-scandir-1.c │ ├── ex10-time.c │ ├── ex07-traverse-bad-1.c │ ├── ex08-traverse-bad-2.c │ └── ex09-traverse-1.c ├── sem13 │ ├── ex01-sem1.c │ ├── ex06-msg.c │ ├── ex03-sem3.c │ ├── ex04-sem4.c │ ├── ex05-sem5.c │ └── ex02-sem2.c └── sem15 │ └── epoll-server.c ├── old ├── 203 │ └── pipe │ │ ├── .gitignore │ │ ├── Makefile │ │ ├── pipe1.c │ │ ├── pipe3.c │ │ └── pipe2.c ├── Unix-Знакомство.pdf ├── Каталоги. Время.pdf ├── oop │ └── random │ │ ├── lib.c │ │ └── main.c ├── fork-exec │ ├── test.c │ ├── exec.c │ ├── proc.h │ └── proc.c └── philosophers │ └── philosophers.c ├── images ├── settings.png ├── webhook_ping_ok.png ├── add_deploy_key_btn.png ├── deploy_keys_form.png ├── github_add_webhook.png ├── menu_deploy_keys.png ├── ejudge_integration_2.png ├── ejudge_properties_1.png ├── github_webhooks_menu.png ├── ejudge_new_integration.png └── github_add_webhook_form.png ├── 2020-2021 ├── sem04 │ ├── fs-1.pdf │ ├── fs-2.pdf │ └── README.md ├── sem07 │ ├── sem07.pdf │ └── README.md ├── sem08 │ ├── sem08.pdf │ └── README.md ├── sem09 │ ├── slides.pdf │ ├── reading.pdf │ └── README.md ├── sem11 │ ├── slides.pdf │ └── README.md ├── sem06 │ ├── 19-mmap.pdf │ └── 20-memmng.pdf └── sem10 │ └── README.md ├── 2021-2022 ├── sem04 │ ├── fs-1.pdf │ ├── fs-2.pdf │ └── README.md ├── sem06 │ ├── 19-mmap.pdf │ └── 20-memmng.pdf └── sem01 │ ├── 1.c │ ├── 5.c │ └── 6.c ├── 2018-2019 ├── sem02 │ ├── 05-_exit.c │ ├── 01-sys1.c │ ├── 02-sys2.S │ ├── 06-copy1.c │ ├── 03-sys3.S │ ├── 04-sys4.c │ ├── 07-copy2.c │ └── 08-copy3.c └── sem07 │ ├── Makefile │ └── 01-count-digits.c ├── 2023-2024 └── format.yaml └── GithubIntegration.md /2019-2020/10-exec/3.sh: -------------------------------------------------------------------------------- 1 | echo 'hello' 2 | -------------------------------------------------------------------------------- /2017-2018/sem14/.gitignore: -------------------------------------------------------------------------------- 1 | client 2 | server 3 | -------------------------------------------------------------------------------- /old/203/pipe/.gitignore: -------------------------------------------------------------------------------- 1 | pipe1 2 | pipe2 3 | pipe3 4 | -------------------------------------------------------------------------------- /2017-2018/sem11/fill.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cat /usr/share/dict/words 4 | -------------------------------------------------------------------------------- /images/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/images/settings.png -------------------------------------------------------------------------------- /2019-2020/10-exec/5.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python3 2 | 3 | print(int(input()) + int(input())) 4 | -------------------------------------------------------------------------------- /2017-2018/sem04/fs-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/2017-2018/sem04/fs-1.pdf -------------------------------------------------------------------------------- /2017-2018/sem04/fs-2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/2017-2018/sem04/fs-2.pdf -------------------------------------------------------------------------------- /2020-2021/sem04/fs-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/2020-2021/sem04/fs-1.pdf -------------------------------------------------------------------------------- /2020-2021/sem04/fs-2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/2020-2021/sem04/fs-2.pdf -------------------------------------------------------------------------------- /2021-2022/sem04/fs-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/2021-2022/sem04/fs-1.pdf -------------------------------------------------------------------------------- /2021-2022/sem04/fs-2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/2021-2022/sem04/fs-2.pdf -------------------------------------------------------------------------------- /old/Unix-Знакомство.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/old/Unix-Знакомство.pdf -------------------------------------------------------------------------------- /old/Каталоги. Время.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/old/Каталоги. Время.pdf -------------------------------------------------------------------------------- /2017-2018/sem02/sem02.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/2017-2018/sem02/sem02.pdf -------------------------------------------------------------------------------- /2020-2021/sem07/sem07.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/2020-2021/sem07/sem07.pdf -------------------------------------------------------------------------------- /2020-2021/sem08/sem08.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/2020-2021/sem08/sem08.pdf -------------------------------------------------------------------------------- /2020-2021/sem09/slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/2020-2021/sem09/slides.pdf -------------------------------------------------------------------------------- /2020-2021/sem11/slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/2020-2021/sem11/slides.pdf -------------------------------------------------------------------------------- /images/webhook_ping_ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/images/webhook_ping_ok.png -------------------------------------------------------------------------------- /2017-2018/sem06/19-mmap.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/2017-2018/sem06/19-mmap.pdf -------------------------------------------------------------------------------- /2017-2018/sem06/20-memmng.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/2017-2018/sem06/20-memmng.pdf -------------------------------------------------------------------------------- /2017-2018/sem08/02threads.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/2017-2018/sem08/02threads.pdf -------------------------------------------------------------------------------- /2017-2018/sem12/signal-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/2017-2018/sem12/signal-1.pdf -------------------------------------------------------------------------------- /2017-2018/sem12/signal-2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/2017-2018/sem12/signal-2.pdf -------------------------------------------------------------------------------- /2020-2021/sem06/19-mmap.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/2020-2021/sem06/19-mmap.pdf -------------------------------------------------------------------------------- /2020-2021/sem06/20-memmng.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/2020-2021/sem06/20-memmng.pdf -------------------------------------------------------------------------------- /2020-2021/sem09/reading.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/2020-2021/sem09/reading.pdf -------------------------------------------------------------------------------- /2021-2022/sem06/19-mmap.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/2021-2022/sem06/19-mmap.pdf -------------------------------------------------------------------------------- /2021-2022/sem06/20-memmng.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/2021-2022/sem06/20-memmng.pdf -------------------------------------------------------------------------------- /images/add_deploy_key_btn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/images/add_deploy_key_btn.png -------------------------------------------------------------------------------- /images/deploy_keys_form.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/images/deploy_keys_form.png -------------------------------------------------------------------------------- /images/github_add_webhook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/images/github_add_webhook.png -------------------------------------------------------------------------------- /images/menu_deploy_keys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/images/menu_deploy_keys.png -------------------------------------------------------------------------------- /2017-2018/sem07/06-pointers.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/2017-2018/sem07/06-pointers.pdf -------------------------------------------------------------------------------- /2017-2018/sem12/sem-signals.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/2017-2018/sem12/sem-signals.pdf -------------------------------------------------------------------------------- /images/ejudge_integration_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/images/ejudge_integration_2.png -------------------------------------------------------------------------------- /images/ejudge_properties_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/images/ejudge_properties_1.png -------------------------------------------------------------------------------- /images/github_webhooks_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/images/github_webhooks_menu.png -------------------------------------------------------------------------------- /2017-2018/sem10/ex08-shellscript.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # скрипт для интерпретатора bash 4 | 5 | echo "Hello" 6 | -------------------------------------------------------------------------------- /2019-2020/10-exec/8.x: -------------------------------------------------------------------------------- 1 | #! /mnt/old-vm/home/cher/cmc-os/2019-2020/sem11/2/7 a b 2 | 3 | sdf 4 | sdf 5 | sdf 6 | 7 | -------------------------------------------------------------------------------- /images/ejudge_new_integration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/images/ejudge_new_integration.png -------------------------------------------------------------------------------- /images/github_add_webhook_form.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackav/cmc-os/HEAD/images/github_add_webhook_form.png -------------------------------------------------------------------------------- /2018-2019/sem02/05-_exit.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | printf("abc\n"); 6 | _exit(1); 7 | } 8 | -------------------------------------------------------------------------------- /2020-2021/sem11/README.md: -------------------------------------------------------------------------------- 1 | # Сигналы 2 | 3 | [Запись занятия](https://youtu.be/We0Im0lWAYQ) 4 | 5 | [Слайды](slides.pdf) 6 | -------------------------------------------------------------------------------- /2019-2020/07-make/r.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum { VAR = 100 }; 4 | extern int rand_init(); 5 | extern int rand_n(int max_value); 6 | -------------------------------------------------------------------------------- /2017-2018/sem10/ex10-myinter.xx: -------------------------------------------------------------------------------- 1 | #! /home/cher/cmc-os/2017-2018/sem10/ex09-inter -z 2 | 3 | # мой собственный интерпретатор 4 | 5 | aaa 6 | -------------------------------------------------------------------------------- /2020-2021/sem09/README.md: -------------------------------------------------------------------------------- 1 | # Каналы 2 | 3 | [Запись занятия](https://youtu.be/ZAJoH4iQn0M) 4 | 5 | [Слайды](slides.pdf) 6 | 7 | [Текст](reading.pdf) -------------------------------------------------------------------------------- /2020-2021/sem07/README.md: -------------------------------------------------------------------------------- 1 | # Процессы (fork, wait, exit) 2 | 3 | [Запись занятия](https://www.youtube.com/watch?v=-Vmeobgh96k) 4 | 5 | [Слайды](sem07.pdf) -------------------------------------------------------------------------------- /2020-2021/sem08/README.md: -------------------------------------------------------------------------------- 1 | # Процессы (fork, wait, exit) 2 | 3 | [Запись занятия](https://www.youtube.com/watch?v=xkKRu5bU3uI) 4 | 5 | [Слайды](sem08.pdf) -------------------------------------------------------------------------------- /2017-2018/sem06/ex08-myso.c: -------------------------------------------------------------------------------- 1 | /* 2 | gcc -Wall -O2 -fPIC -DPIC -shared ex08-myso.c -omyso.so 3 | */ 4 | 5 | int myfunc(int x) 6 | { 7 | return x + 1; 8 | } 9 | -------------------------------------------------------------------------------- /2017-2018/sem03/hello-syscalls-c.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | const char str[] = "Hello\n"; 4 | int main() 5 | { 6 | write(1, str, sizeof(str) - 1); 7 | _exit(4); 8 | } 9 | -------------------------------------------------------------------------------- /2021-2022/sem01/1.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | for (int i = 0; i < argc; ++i) { 6 | printf("%d: %s\n", i, argv[i]); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /2017-2018/sem11/ex03-pipe-buf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // выводим значение константы PIPE_BUF 5 | int main() 6 | { 7 | printf("%d\n", (int)PIPE_BUF); 8 | } 9 | -------------------------------------------------------------------------------- /2019-2020/10-exec/7.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | for (int i = 0; i < argc; ++i) { 6 | printf("[%d]: %s\n", i, argv[i]); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /2017-2018/sem10/ex07-shebang.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python3 -E 2 | 3 | # в этом скрипте на питоне используется специальный комментарий #! 4 | # для указания пути к интерпретатору 5 | 6 | print(1 + 2 + 3); 7 | -------------------------------------------------------------------------------- /2018-2019/sem02/01-sys1.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | static const char msg[] = "Hello!\n"; 6 | 7 | write(1, msg, sizeof(msg) - 1); 8 | _exit(0); 9 | } 10 | -------------------------------------------------------------------------------- /2019-2020/01-args/1-args.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | printf("%d\n", argc); 6 | for (int i = 0; i < argc; ++i) { 7 | printf("%s\n", argv[i]); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /2019-2020/02-syscalls/4-cat.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | while (1) { 6 | char c; 7 | ssize_t z = read(0, &c, sizeof(c)); 8 | if (z <= 0) break; 9 | write(1, &c, sizeof(c)); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /old/oop/random/lib.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef struct Random Random; 4 | 5 | int next42(Random *r) { 6 | return 42; 7 | } 8 | 9 | Random *destroy42(Random *r) { 10 | free(r); 11 | return NULL; 12 | } 13 | -------------------------------------------------------------------------------- /2019-2020/02-syscalls/1-int-overflow.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | int a, b; 6 | scanf("%d%d", &a, &b); 7 | int c; 8 | _Bool res = __builtin_add_overflow(a, b, &c); 9 | printf("%d %d\n", res, c); 10 | } 11 | 12 | -------------------------------------------------------------------------------- /2017-2018/sem09/ex01-avalanche.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // сколько будет процессов выполнять pause()? 5 | int main() 6 | { 7 | fork(); 8 | fork(); 9 | printf("%d\n", getpid()); 10 | pause(); 11 | } 12 | -------------------------------------------------------------------------------- /2018-2019/sem02/02-sys2.S: -------------------------------------------------------------------------------- 1 | .text 2 | .global main 3 | main: 4 | push $strend-str 5 | push $str 6 | push $1 7 | call write 8 | push $0 9 | call _exit 10 | str: 11 | .ascii "Hello\n" 12 | strend: 13 | -------------------------------------------------------------------------------- /old/203/pipe/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -Wall -Werror -std=gnu11 -O2 -g 3 | TARGETS = pipe1 pipe2 pipe3 4 | 5 | all : $(TARGETS) 6 | 7 | 8 | pipe1 : pipe1.c 9 | pipe2 : pipe2.c 10 | pipe3 : pipe3.c 11 | 12 | clean : 13 | -rm -f $(TARGETS) 14 | -------------------------------------------------------------------------------- /2017-2018/sem14/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -Wall -O2 -Werror -std=gnu11 3 | 4 | TARGETS = client server 5 | 6 | all : $(TARGETS) 7 | 8 | client : client.c 9 | 10 | server : server.c 11 | 12 | .PHONY : clean 13 | 14 | clean : 15 | -rm -f $(TARGETS) 16 | -------------------------------------------------------------------------------- /2018-2019/sem07/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -O2 -Wall -Werror -std=gnu11 -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE 3 | 4 | TARGETS = 01-count-digits 5 | 6 | all : $(TARGETS) 7 | 8 | 01-count-digits : 01-count-digits.c 9 | 10 | clean : 11 | -rm -f $(TARGETS) 12 | -------------------------------------------------------------------------------- /2021-2022/sem01/5.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[], char *envp[]) 4 | { 5 | for (int i = 0; i < argc; ++i) { 6 | printf("%d: %s\n", i, argv[i]); 7 | } 8 | for (int i = 0; envp[i]; ++i) { 9 | printf("%s\n", envp[i]); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /2017-2018/sem14/bitmap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | enum { N = 1024 }; 5 | 6 | uint8_t bits[N]; 7 | 8 | // получить бит с индексом i в битовом массиве bits 9 | int get_bit(unsigned i) 10 | { 11 | return (bits[i >> 3] >> (i & 7)) & 1; 12 | } 13 | -------------------------------------------------------------------------------- /2019-2020/02-syscalls/2-hello-world.s: -------------------------------------------------------------------------------- 1 | .att_syntax noprefix 2 | .global _start 3 | _start: 4 | mov $4, eax 5 | mov $1, ebx 6 | mov $str, ecx 7 | mov $estr-str, edx 8 | int $0x80 9 | 10 | mov $1, eax 11 | mov $42, ebx 12 | int $0x80 13 | str: .asciz "Hello\n" 14 | estr: 15 | -------------------------------------------------------------------------------- /2017-2018/sem09/ex02-buffering.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // буферизация стандартных потоков 5 | int main() 6 | { 7 | printf("Hello"); fflush(stdout); 8 | //fprintf(stderr, "Hello"); 9 | //setbuf(stdout, NULL); 10 | printf("Hello"); 11 | fork(); 12 | } 13 | -------------------------------------------------------------------------------- /2019-2020/07-make/r.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "r.h" 6 | 7 | int rand_init() 8 | { 9 | srand(time(NULL)); 10 | return 0; 11 | } 12 | 13 | int rand_n(int n) 14 | { 15 | assert(n > 0); 16 | return (int)((rand() / (RAND_MAX + 1.0)) * n); 17 | } 18 | -------------------------------------------------------------------------------- /2017-2018/sem10/ex09-inter.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // программа печатает аргументы командной строки 4 | // она будет использоваться в качестве "интерпретатора" 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | pause(); 9 | for (int i = 0; i < argc; ++i) { 10 | printf("<%s>\n", argv[i]); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /2017-2018/sem07/ex01-wchar.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /* 6 | используем Wide Char API для обработки текста 7 | */ 8 | int main(void) 9 | { 10 | wchar_t c; 11 | setlocale(LC_ALL, ""); 12 | while ((c = getwc(stdin)) != EOF) { 13 | wprintf(L"%Lc\n", (int) c); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /2018-2019/sem02/06-copy1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | char c; 8 | int r; 9 | while (1) { 10 | r = read(STDIN_FILENO, &c, sizeof(c)); 11 | if (r != sizeof(c)) break; 12 | r = write(STDOUT_FILENO, &c, sizeof(c)); 13 | if (r != 1) abort(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /2017-2018/sem03/stdio-unlocked.c: -------------------------------------------------------------------------------- 1 | /* 2 | * За счет использования функций чтения-записи, не предназначенных для 3 | * использования в многопоточных программах можно еще ускорить ввод-вывод. 4 | */ 5 | 6 | #include 7 | 8 | int main() 9 | { 10 | int c; 11 | while ((c = getchar_unlocked()) != EOF) { 12 | putchar_unlocked(c); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /2018-2019/sem02/03-sys3.S: -------------------------------------------------------------------------------- 1 | #include 2 | .text 3 | .global _start 4 | _start: 5 | mov $__NR_write, %eax 6 | mov $1, %ebx 7 | mov $str, %ecx 8 | mov $strend-str, %edx 9 | int $0x80 10 | mov $__NR_exit, %eax 11 | mov $0, %ebx 12 | int $0x80 13 | str: 14 | .ascii "Hello\n" 15 | strend: 16 | -------------------------------------------------------------------------------- /2019-2020/06-mmap/1-count-digits.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | int c; 6 | long long count[10] = {}; 7 | while ((c = getchar_unlocked()) != EOF) { 8 | if (c >= '0' && c <= '9') { 9 | ++count[c - '0']; 10 | } 11 | } 12 | for (int i = 0; i < 10; ++i) { 13 | printf("%lld\n", count[i]); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /2019-2020/07-make/m.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "r.h" 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | int max_rand = strtol(argv[1], NULL, 10); 9 | int count = strtol(argv[2], NULL, 10); 10 | 11 | rand_init(); 12 | 13 | for (int i = 0; i < count; ++i) { 14 | printf("%d\n", rand_n(max_rand)); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /2018-2019/sem02/04-sys4.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void _start() 4 | { 5 | const static char msg[] = "Hello\n"; 6 | 7 | asm volatile("mov %0, %%eax; mov %1, %%ebx; mov %2, %%ecx; mov %3, %%edx; int $0x80" : : "g"(__NR_write), "g"(1), "g"(msg), "g"(sizeof(msg) - 1)); 8 | asm volatile("mov %0, %%eax; mov %1, %%ebx; int $0x80" :: "g"(__NR_exit), "g"(1)); 9 | } 10 | -------------------------------------------------------------------------------- /2017-2018/sem03/syscalls-are-slow.c: -------------------------------------------------------------------------------- 1 | /* 2 | * в этом примере стандартный поток ввода побайтово копируется 3 | * на стандартный поток вывода с помощью системных вызовов 4 | * Время работы можно замерить с помощью команды time 5 | */ 6 | 7 | #include 8 | 9 | int main() 10 | { 11 | char c; 12 | while (read(0, &c, 1) == 1) { 13 | write(1, &c, 1); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /2021-2022/sem01/6.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | if (argv[1]) { 7 | const char *s = getenv(argv[1]); 8 | if (s) { 9 | printf("%s\n", s); 10 | } else { 11 | fprintf(stderr, "%s: variable '%s' is undefined\n", argv[0], argv[1]); 12 | return 1; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /2020-2021/sem10/README.md: -------------------------------------------------------------------------------- 1 | # Каналы (продолжение) 2 | 3 | [Запись занятия](https://youtu.be/imZXO8UCJ0g) 4 | 5 | ## Содержание занятия 6 | * Решение задачи ping-pong 7 | * Связь файловых дескрипторов и FILE (fdopen, fileno) 8 | * Передача текстовых данных в канал 9 | * Именованные каналы (FIFO) 10 | * Правильное создание временных файлов (случайное имя во временном каталоге) 11 | * Устройство `/dev/urandom` -------------------------------------------------------------------------------- /2017-2018/sem07/ex04-rand-oop/randint.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct RandomState; 4 | 5 | struct RandomOps 6 | { 7 | void (*destroy)(struct RandomState *); 8 | double (*next)(struct RandomState *); 9 | }; 10 | 11 | struct RandomState 12 | { 13 | const struct RandomOps *ops; 14 | }; 15 | 16 | //struct RandomState *init_prng_gen(const char *); 17 | //struct RandomState *init_trng_gen(const char *); 18 | -------------------------------------------------------------------------------- /2017-2018/sem09/ex06-forkbomb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // неограниченное создание процессов - fork bomb 7 | // запускайте с осторожностью! 8 | int main() 9 | { 10 | while (1) { 11 | int pid = fork(); 12 | if (pid < 0) { 13 | fprintf(stderr, "error: %s\n", strerror(errno)); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /2019-2020/02-syscalls/3-cat.S: -------------------------------------------------------------------------------- 1 | .text 2 | .global _start 3 | 4 | _start: 5 | sub $4, %esp 6 | 7 | again: 8 | mov $3, %eax 9 | mov $0, %ebx 10 | mov %esp, %ecx 11 | mov $1, %edx 12 | int $0x80 13 | 14 | test %eax, %eax 15 | jle done 16 | 17 | mov $4, %eax 18 | mov $0, %ebx 19 | mov %esp, %ecx 20 | mov $1, %edx 21 | int $0x80 22 | jmp again 23 | 24 | done: 25 | mov $1, %eax 26 | mov $42, %ebx 27 | int $0x80 28 | -------------------------------------------------------------------------------- /2017-2018/sem03/stdio-buffered.c: -------------------------------------------------------------------------------- 1 | /* 2 | * В этом примере стандартный поток ввода побайтово копируется 3 | * на стандартный поток вывода. Используются функции побайтового ввода-вывода из libc. 4 | * За счет буферизации потоков в libc (по умолчанию) ввод-вывод существенно быстрее. 5 | */ 6 | 7 | #include 8 | 9 | int main() 10 | { 11 | int c; 12 | while ((c = getchar()) != EOF) { 13 | putchar(c); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /2019-2020/07-make/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -g -Wall -Werror -std=gnu11 -fsanitize=undefined 3 | LDFLAGS = -fsanitize=undefined -g 4 | 5 | TARGETS = m 6 | CFILES = m.c r2.c 7 | HFILES = $(wildcard *.h) 8 | OFILES = $(CFILES:.c=.o) 9 | 10 | all : $(TARGETS) 11 | 12 | m : $(OFILES) 13 | 14 | include deps.make 15 | 16 | deps.make : $(CFILES) $(HFILES) 17 | $(CC) -MM $(CFILES) > deps.make 18 | 19 | clean : 20 | -rm -f $(TARGETS) *.o deps.make 21 | -------------------------------------------------------------------------------- /2019-2020/07-make/r2.c: -------------------------------------------------------------------------------- 1 | #include "r.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static int rand_fd = -1; 9 | 10 | int rand_init() 11 | { 12 | rand_fd = open("/dev/urandom", O_RDONLY); 13 | if (rand_fd < 0) return -1; 14 | return 0; 15 | } 16 | 17 | int rand_n(int n) 18 | { 19 | unsigned val; 20 | read(rand_fd, &val, sizeof(val)); 21 | return val % n; 22 | } 23 | -------------------------------------------------------------------------------- /2017-2018/sem03/read-from-stdin.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Буферизированное чтение со стандартного потока ввода. 3 | * В считанном буфере отсутствует байт '\0' терминатор строки, 4 | * об этом нужно заботиться самим. 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | int main() 11 | { 12 | char buf[32]; 13 | ssize_t rs; 14 | while ((rs = read(0, buf, sizeof(buf))) > 0) { 15 | printf("%d %.*s\n", (int) rs, (int) rs, buf); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /2017-2018/sem06/ex01-stdio.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* 5 | * эта программа подсчитывает число цифровых символов в файле 6 | */ 7 | int main(int argc, char *argv[]) 8 | { 9 | FILE *f = fopen(argv[1], "r"); 10 | int c; 11 | int count = 0; 12 | while ((c = getc_unlocked(f)) != EOF) { 13 | if (c >= '0' && c <= '9') ++count; 14 | //if (isdigit(c)) ++count; 15 | } 16 | printf("%d\n", count); 17 | } 18 | -------------------------------------------------------------------------------- /2017-2018/sem03/lseek-example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() 8 | { 9 | off_t res = lseek(1, 20, SEEK_END); 10 | if (res < 0) { 11 | fprintf(stderr, "error: %s\n", strerror(errno)); 12 | exit(1); 13 | } 14 | char c = '?'; 15 | int r = write(1, &c, 1); 16 | printf("%d\n", r); 17 | putchar(c); 18 | putchar('\n'); 19 | } 20 | -------------------------------------------------------------------------------- /2017-2018/sem03/hello-syscalls-libc.S: -------------------------------------------------------------------------------- 1 | .text 2 | /* поскольку используется стандартная библиотека Си, то точка входа - main */ 3 | .global main 4 | main: 5 | push $estr - str - 1 6 | push $str 7 | push $1 8 | call write 9 | add $12, %esp 10 | push $2 11 | call _exit // системный вызов exit в libc вызывается функцией _exit 12 | 13 | str: .asciz "Hello\n" 14 | estr: 15 | -------------------------------------------------------------------------------- /2019-2020/12-signal/03-sigaction.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void hand_int(int s) 7 | { 8 | printf("SIGINT\n"); 9 | } 10 | 11 | int main() 12 | { 13 | sigaction(SIGINT, &(struct sigaction) { .sa_handler = hand_int, .sa_flags = SA_RESTART }, NULL); 14 | 15 | int a, b; 16 | while (scanf("%d%d", &a, &b) == 2) { 17 | int c = a / b; 18 | printf("%d\n", c); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /2017-2018/sem12/ex01-sig1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* 5 | Игнорируем сигналы SIGINT и SIGFPE. 6 | При выполнении деления на 0 сигнал SIGFPE будет обработан по умолчанию. 7 | При посылке SIGFPE из другого процесса он будет проигнорирован. 8 | */ 9 | int main() 10 | { 11 | int a, b; 12 | signal(SIGINT, SIG_IGN); 13 | signal(SIGFPE, SIG_IGN); 14 | while (scanf("%d%d", &a, &b) == 2) { 15 | printf("%d\n", a / b); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /2019-2020/10-exec/4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int sys(const char *cmd) 8 | { 9 | pid_t pid = fork(); 10 | if (pid < 0) { 11 | } else if (!pid) { 12 | execl("/bin/sh", "sh", "-c", cmd, NULL); 13 | _exit(1); 14 | } 15 | 16 | wait(0); 17 | } 18 | 19 | int main(int argc, char *argv[]) 20 | { 21 | sys(argv[1]); 22 | sys(argv[2]); 23 | } 24 | -------------------------------------------------------------------------------- /2017-2018/sem03/open-example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | int old = umask(0); 14 | int fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0666); 15 | if (fd < 0) { 16 | fprintf(stderr, "error: %s\n", strerror(errno)); 17 | exit(1); 18 | } 19 | close(fd); 20 | } 21 | -------------------------------------------------------------------------------- /2017-2018/sem09/ex03-_exit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void myexitfunc() 7 | { 8 | fprintf(stderr, "atexit\n"); 9 | } 10 | 11 | // системный вызов _exit() немедленно завершает процесс 12 | // без сохранения буферов вывода на устройство 13 | // и вызовов функций, зарегистрированных в atexit 14 | int main() 15 | { 16 | atexit(myexitfunc); 17 | printf("Hello\n"); 18 | fork(); 19 | _exit(1); 20 | //raise(SIGABRT); 21 | } 22 | -------------------------------------------------------------------------------- /2017-2018/sem09/ex07-oom.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | enum { SZ = 1 * 1024 * 1024 * 1024U + 512 * 1024 * 1024U }; 7 | 8 | // из-за Copy-on-Write и Memory Overcommit 9 | // возникает ситуация Out-of-Memory и ядро ОС 10 | // завершает процессы, отправляя им SIGKILL 11 | int main() 12 | { 13 | unsigned char *ptr = malloc(SZ); 14 | fork(); 15 | fork(); 16 | memset(ptr, 1, SZ); 17 | printf("%d %d\n", ptr[SZ - 1], getpid()); 18 | } 19 | -------------------------------------------------------------------------------- /2019-2020/10-exec/9.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | uid_t uid = getuid(); 10 | uid_t euid = geteuid(); 11 | 12 | printf("%d %d\n", uid, euid); 13 | 14 | FILE *f = fopen(argv[1], "r"); 15 | if (f) { 16 | int c; 17 | while ((c = getc(f)) != EOF) putchar(c); 18 | } else { 19 | fprintf(stderr, "error: %s\n", strerror(errno)); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /2017-2018/sem06/ex08-useso.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /* 6 | Программа подгружает динамичесий модуль и вызывает из него функцию 7 | */ 8 | 9 | int main() 10 | { 11 | void *handle = dlopen("./myso.so", RTLD_LAZY); 12 | if (!handle) abort(); 13 | 14 | void *func = dlsym(handle, "myfunc"); 15 | if (!func) abort(); 16 | 17 | int x; 18 | while (scanf("%d", &x) == 1) { 19 | int y = ((int (*)(int)) func)(x); 20 | printf("%d\n", y); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /2019-2020/12-signal/01-bsd-signal-handling.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void hand_int(int s) 7 | { 8 | printf("SIGINT\n"); 9 | } 10 | 11 | void hand_fpe(int s) 12 | { 13 | printf("SIGFPE\n"); 14 | } 15 | 16 | int main() 17 | { 18 | signal(SIGINT, hand_int); 19 | signal(SIGFPE, hand_fpe); 20 | 21 | int a, b, r; 22 | while ((r = scanf("%d%d", &a, &b)) == 2) { 23 | int c = a / b; 24 | printf("%d\n", c); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /2019-2020/08-dlopen/r.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define INTERFACE_VERSION 1 4 | 5 | struct RandomContext; 6 | 7 | struct RandomOperations 8 | { 9 | void (*init)(struct RandomContext *); 10 | void (*destroy)(struct RandomContext *); 11 | int (*rand_n)(struct RandomContext *, int n); 12 | }; 13 | 14 | struct RandomContext 15 | { 16 | const struct RandomOperations *ops; 17 | }; 18 | 19 | struct RandomContext *create_stdlib_random(); 20 | struct RandomContext *create_urandom_random(); 21 | 22 | #define CREATE_FUNC_NAME(name,v) create_##name##_random_v##v 23 | -------------------------------------------------------------------------------- /2017-2018/sem07/ex03-rand2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | //int fd = open("/dev/random", O_RDONLY, 0); 10 | // системный генератор случайных чисел 11 | int fd = open("/dev/urandom", O_RDONLY, 0); 12 | for (int i = 0; i < 10; ++i) { 13 | unsigned val; 14 | read(fd, &val, sizeof(val)); 15 | double x = val / (UINT_MAX + 1.); 16 | printf("%u %.10g\n", val, x); 17 | } 18 | close(fd); 19 | } 20 | -------------------------------------------------------------------------------- /2019-2020/10-exec/2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | pid_t pid = fork(); 10 | if (pid < 0) { 11 | } else if (!pid) { 12 | if (chdir(argv[1]) < 0) { 13 | fprintf(stderr, "cannot chdir to '%s'\n", argv[1]); 14 | _exit(1); 15 | } 16 | execlp(argv[2], argv[2], NULL); 17 | fprintf(stderr, "exec of '%s' failed\n", argv[2]); 18 | _exit(1); 19 | } 20 | 21 | wait(0); 22 | } 23 | -------------------------------------------------------------------------------- /2019-2020/03-file-syscalls/4-umask.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main(int argc, char *argv[]) 10 | { 11 | int oldmask = umask(0177); 12 | (void) oldmask; 13 | int fd = open(argv[1], O_WRONLY | O_APPEND | O_CREAT, 0777); 14 | if (fd < 0) { 15 | fprintf(stderr, "%s: %s\n", argv[1], strerror(errno)); 16 | return 1; 17 | } 18 | 19 | dup2(fd, 1); close(fd); 20 | 21 | int c; 22 | while ((c = getchar()) != EOF) 23 | putchar(c); 24 | } 25 | -------------------------------------------------------------------------------- /2017-2018/sem11/ex01-pipesize.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | // определение размера буфера канала 9 | int main() 10 | { 11 | int fd[2]; 12 | 13 | pipe(fd); 14 | int sz = 0; 15 | char c = 'a'; 16 | while (1) { 17 | printf("%d\n", sz); 18 | ssize_t r = write(fd[1], &c, sizeof(c)); 19 | if (r < 0) { 20 | fprintf(stderr, "Error: %s\n", strerror(errno)); 21 | exit(1); 22 | } 23 | ++sz; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /2019-2020/12-signal/07-wait-for-signal-usleep.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | volatile sig_atomic_t int_flag = 0; 8 | 9 | void hand_int(int s) 10 | { 11 | int_flag = 1; 12 | sleep(5); 13 | } 14 | 15 | int main() 16 | { 17 | sigaction(SIGINT, &(struct sigaction) { .sa_handler = hand_int, .sa_flags = SA_RESTART }, NULL); 18 | 19 | while (1) { 20 | while (!int_flag) { 21 | usleep(10); 22 | } 23 | int_flag = 0; 24 | printf("SIGINT\n"); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /2019-2020/12-signal/04-async-signal-safe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void hand_int(int s) 8 | { 9 | static const char buf[] = "SIGINT\n"; 10 | int e = errno; 11 | write(1, buf, sizeof(buf) - 1); 12 | errno = e; 13 | } 14 | 15 | int main() 16 | { 17 | sigaction(SIGINT, &(struct sigaction) { .sa_handler = hand_int, .sa_flags = SA_RESTART }, NULL); 18 | 19 | int a, b; 20 | while (scanf("%d%d", &a, &b) == 2) { 21 | int c = a / b; 22 | printf("%d\n", c); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /2017-2018/sem05/ex02-readdir.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | /* 8 | * эта программа выводит содержимое каталога в виде последовательности пар Inode:Name 9 | */ 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | DIR *d = opendir(argv[1]); 14 | if (!d) { 15 | fprintf(stderr, "error: %s\n", strerror(errno)); 16 | exit(1); 17 | } 18 | struct dirent *dd; 19 | while ((dd = readdir(d))) { 20 | printf("%lu %s\n", dd->d_ino, dd->d_name); 21 | } 22 | closedir(d); 23 | } 24 | -------------------------------------------------------------------------------- /2019-2020/03-file-syscalls/1-open-read.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main(int argc, char *argv[]) 11 | { 12 | int fd = open(argv[1], O_RDONLY, 0); 13 | if (fd < 0) { 14 | fprintf(stderr, "%s: %s\n", argv[1], strerror(errno)); 15 | exit(1); 16 | } 17 | dup2(fd, STDIN_FILENO); 18 | close(fd); 19 | 20 | int c; 21 | while ((c = getchar()) != EOF) { 22 | putchar(c); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /2019-2020/12-signal/05-wait-for-signal-busy.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | volatile sig_atomic_t int_flag = 0; 8 | 9 | void hand_int(int s) 10 | { 11 | int_flag = 1; 12 | } 13 | 14 | int main() 15 | { 16 | sigaction(SIGINT, &(struct sigaction) { .sa_handler = hand_int, .sa_flags = SA_RESTART }, NULL); 17 | 18 | while (1) { 19 | // BUSY WAIT 20 | // недопустим в программах, это ошибка! 21 | while (!int_flag) {} 22 | int_flag = 0; 23 | printf("SIGINT\n"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /2019-2020/12-signal/06-wait-for-signal-pause.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | volatile sig_atomic_t int_flag = 0; 8 | 9 | void hand_int(int s) 10 | { 11 | int_flag = 1; 12 | } 13 | 14 | int main() 15 | { 16 | sigaction(SIGINT, &(struct sigaction) { .sa_handler = hand_int, .sa_flags = SA_RESTART }, NULL); 17 | 18 | while (1) { 19 | while (!int_flag) { 20 | // race condition!!! 21 | pause(); 22 | } 23 | int_flag = 0; 24 | printf("SIGINT\n"); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /old/fork-exec/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char **argv) { 6 | int fd = creat("out", 0666); 7 | int pid = fork(); 8 | 9 | if (pid == 0) { 10 | int new_fd = dup2(fd, 1); 11 | execlp("ls", "abacaba", argv[1], NULL); 12 | perror("q"); 13 | } else { 14 | int status, p; 15 | p = wait(&status); 16 | printf("%d %d %d", status, WIFEXITED(status), WEXITSTATUS(status)); 17 | if (WIFEXITED(status) && WEXITSTATUS(status) == 0) 18 | printf("%d %d %d\n", pid, p, status); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /2019-2020/11-pipe/1-pipesize.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() 8 | { 9 | char c; 10 | int z = 0; 11 | int fd[2]; 12 | pipe(fd); 13 | close(fd[0]); 14 | signal(SIGPIPE, SIG_IGN); 15 | while (1) { 16 | int r = write(fd[1], &c, sizeof(c)); 17 | if (r > 0) { 18 | ++z; 19 | printf("%d\n", z); 20 | } else if (!r) { 21 | printf("EOF\n"); 22 | } else { 23 | printf("%s\n", strerror(errno)); 24 | return 1; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /2019-2020/shestimer/t.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | struct Random { 7 | int fd; 8 | 9 | 10 | unsigned (*next)(struct Random*); 11 | }; 12 | 13 | unsigned next_r(struct Random* r) { 14 | unsigned x; 15 | read(r->fd, &x, sizeof(x)); 16 | return x; 17 | } 18 | 19 | int main(void) { 20 | srand(time(0)); 21 | const int maxt = 10; 22 | 23 | struct Random r; 24 | int fd = open("/dev/random", O_RDONLY); 25 | r.next = next_r; 26 | r.fd = fd; 27 | for (int i = 0; i < maxt; ++i) { 28 | printf("%u\n", r.next(&r) % 100); 29 | } 30 | close(fd); 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /2017-2018/sem08/ex03-create-10.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | enum { N = 10 }; 5 | 6 | void *thr_func(void *ptr) 7 | { 8 | // распечатать свой серийный номер 9 | printf("%d\n", *(int*) ptr); 10 | return NULL; 11 | } 12 | 13 | int main() 14 | { 15 | // массив идентификаторов нитей 16 | pthread_t ids[N]; 17 | // массив серийных номеров нитей 18 | int nums[N]; 19 | 20 | int i; 21 | for (i = 0; i < N; ++i) { 22 | nums[i] = i; 23 | pthread_create(&ids[i], NULL, thr_func, &nums[i]); 24 | } 25 | 26 | for (int i = 0; i < N; ++i) { 27 | pthread_join(ids[i], NULL); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /2019-2020/11-pipe/3-runpipe2.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char *argv[]) 9 | { 10 | int fd[2]; 11 | 12 | pipe2(fd, O_CLOEXEC); 13 | pid_t pid1 = fork(); 14 | if (!pid1) { 15 | dup2(fd[1], 1); 16 | execlp(argv[1], argv[1], NULL); 17 | _exit(1); 18 | } 19 | 20 | pid_t pid2 = fork(); 21 | if (!pid2) { 22 | dup2(fd[0], 0); 23 | execlp(argv[2], argv[2], NULL); 24 | _exit(1); 25 | } 26 | close(fd[1]); 27 | close(fd[0]); 28 | 29 | while (wait(NULL) > 0) {} 30 | } 31 | -------------------------------------------------------------------------------- /2017-2018/sem09/ex04-fork-exec.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | void myexitfunc() 11 | { 12 | fprintf(stderr, "atexit\n"); 13 | } 14 | 15 | int main(int argc, char *argv[]) 16 | { 17 | atexit(myexitfunc); 18 | printf("Hello"); 19 | int pid = fork(); 20 | if (!pid) { 21 | execlp(argv[1], argv[1], NULL); 22 | fprintf(stderr, "error: %s\n", strerror(errno)); 23 | _exit(1); // после exec нужно завершать процесс по _exit()! 24 | } 25 | 26 | wait(NULL); 27 | } 28 | -------------------------------------------------------------------------------- /2017-2018/sem08/ex02-data-race.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | enum { N = 10 }; 5 | 6 | void *thr_func(void *ptr) 7 | { 8 | printf("%d\n", *(int*) ptr); 9 | return NULL; 10 | } 11 | 12 | int main() 13 | { 14 | pthread_t ids[N]; 15 | 16 | int i; 17 | for (i = 0; i < N; ++i) { 18 | // передается адрес локальной переменной, 19 | // переменная модифицируется в main 20 | // и читается в thr_func 21 | // это Data Race - Undefined Behavior 22 | pthread_create(&ids[i], NULL, thr_func, &i); 23 | } 24 | 25 | for (int i = 0; i < N; ++i) { 26 | pthread_join(ids[i], NULL); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /old/203/pipe/pipe1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // argv[1] - cmd1 7 | // argv[2] - cmd2 8 | int main(int argc, char *argv[]) 9 | { 10 | int fds[2]; 11 | pipe(fds); 12 | if (!fork()) { 13 | dup2(fds[1], 1); 14 | close(fds[1]); 15 | close(fds[0]); 16 | execlp(argv[1], argv[1], NULL); 17 | _exit(1); 18 | } 19 | close(fds[1]); 20 | if (!fork()) { 21 | dup2(fds[0], 0); 22 | close(fds[0]); 23 | execlp(argv[2], argv[2], NULL); 24 | _exit(1); 25 | } 26 | close(fds[0]); 27 | wait(NULL); 28 | wait(NULL); 29 | } 30 | -------------------------------------------------------------------------------- /2017-2018/sem11/ex04-pipeline.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // конвейер на два процесса 7 | int main(int argc, char *argv[]) 8 | { 9 | int fds[2]; 10 | 11 | pipe(fds); 12 | if (!fork()) { 13 | dup2(fds[1], 1); 14 | close(fds[1]); 15 | close(fds[0]); 16 | execlp(argv[1], argv[1], NULL); 17 | _exit(1); 18 | } 19 | close(fds[1]); 20 | if (!fork()) { 21 | dup2(fds[0], 0); 22 | close(fds[0]); 23 | execlp(argv[2], argv[2], NULL); 24 | _exit(1); 25 | } 26 | close(fds[0]); 27 | wait(NULL); 28 | wait(NULL); 29 | } 30 | -------------------------------------------------------------------------------- /2017-2018/sem10/ex01-waitstatus.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | // получение статуса завершения процесса с помощью wait 8 | int main() 9 | { 10 | int pid = fork(); 11 | if (!pid) { 12 | raise(SIGSEGV); 13 | //_exit(500); 14 | } 15 | int pid2 = fork(); 16 | if (!pid2) { 17 | _exit(120); 18 | } 19 | 20 | int status; 21 | int p = wait(&status); 22 | printf("%d\n", p); 23 | if (WIFEXITED(status)) { 24 | printf("%d\n", WEXITSTATUS(status)); 25 | } else if (WIFSIGNALED(status)) { 26 | printf("%d\n", WTERMSIG(status)); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /2019-2020/03-file-syscalls/2-open-append.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main(int argc, char *argv[]) 11 | { 12 | int old_mask = umask(0); 13 | 14 | printf("%o\n", old_mask); 15 | int fd = open(argv[1], O_WRONLY | O_CREAT | O_APPEND, 0666); 16 | if (fd < 0) { 17 | fprintf(stderr, "%s: %s\n", argv[1], strerror(errno)); 18 | exit(1); 19 | } 20 | dup2(fd, STDOUT_FILENO); 21 | close(fd); 22 | 23 | int c; 24 | while ((c = getchar()) != EOF) { 25 | putchar(c); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /2017-2018/sem08/ex04-create-with-cast.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | enum { N = 10 }; 5 | 6 | void *thr_func(void *ptr) 7 | { 8 | // в значении указателя передаем серийный номер нити 9 | // intptr_t - целый тип размера, равного размеру указателя 10 | // иначе на 64-битных платформах будет ошибка компиляции 11 | printf("%d\n", (int) (intptr_t) ptr); 12 | return NULL; 13 | } 14 | 15 | int main() 16 | { 17 | pthread_t ids[N]; 18 | 19 | int i; 20 | for (i = 0; i < N; ++i) { 21 | pthread_create(&ids[i], NULL, thr_func, (void*) (intptr_t) i); 22 | } 23 | 24 | for (int i = 0; i < N; ++i) { 25 | pthread_join(ids[i], NULL); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /2019-2020/11-pipe/2-runpipe.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | int fd[2]; 10 | 11 | pipe(fd); 12 | pid_t pid1 = fork(); 13 | if (!pid1) { 14 | dup2(fd[1], 1); 15 | close(fd[1]); 16 | close(fd[0]); 17 | execlp(argv[1], argv[1], NULL); 18 | _exit(1); 19 | } 20 | 21 | close(fd[1]); 22 | pid_t pid2 = fork(); 23 | if (!pid2) { 24 | dup2(fd[0], 0); 25 | close(fd[0]); 26 | execlp(argv[2], argv[2], NULL); 27 | _exit(1); 28 | } 29 | close(fd[0]); 30 | 31 | while (wait(NULL) > 0) {} 32 | } 33 | -------------------------------------------------------------------------------- /2017-2018/sem03/hello-syscalls.S: -------------------------------------------------------------------------------- 1 | /* заголовочный файл с номерами системных вызовов */ 2 | #include 3 | .text 4 | .global _start 5 | _start: 6 | mov $__NR_write, %eax 7 | mov $1, %ebx // номер стандартного потока вывода - 1 8 | mov $str, %ecx // адрес выводимой строки 9 | mov $estr - str - 1, %edx // размер выводимой строки 10 | int $0x80 // системный вызов 11 | mov $__NR_exit, %eax 12 | mov $1, %ebx // код завершения программы - 1 13 | int $0x80 // системный вызов 14 | 15 | str: .asciz "Hello\n" 16 | estr: 17 | 18 | -------------------------------------------------------------------------------- /2017-2018/sem06/ex09-useself.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /* 6 | Для компиляции потребуется опция -rdynamic 7 | Программа ищет функцию по имени в самой себе. 8 | 9 | gcc -Wall -O2 ex09-useself.c -rdynamic -ouseself -ldl 10 | */ 11 | 12 | int myfunc(int x) 13 | { 14 | return x * 2; 15 | } 16 | 17 | int main() 18 | { 19 | void *handle = dlopen(NULL, RTLD_LAZY); 20 | if (!handle) abort(); 21 | 22 | void *func = dlsym(handle, "myfunc"); 23 | if (!func) abort(); 24 | 25 | int x; 26 | while (scanf("%d", &x) == 1) { 27 | int y = ((int (*)(int)) func)(x); 28 | printf("%d\n", y); 29 | } 30 | dlclose(handle); 31 | // dlerror 32 | } 33 | -------------------------------------------------------------------------------- /2017-2018/sem03/redirect-example.c: -------------------------------------------------------------------------------- 1 | /* 2 | * В этом примере стандартный поток вывода перенаправляется в файл за счет того, 3 | * что номер закрытого файлового дескриптора (1) повторно используется в open. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | int main(int argc, char *argv[]) 17 | { 18 | close(1); 19 | int old = umask(0); 20 | int fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0666); 21 | if (fd < 0) { 22 | fprintf(stderr, "error: %s\n", strerror(errno)); 23 | exit(1); 24 | } 25 | printf("Hello %d\n", fileno(stdout)); 26 | } 27 | -------------------------------------------------------------------------------- /2017-2018/sem08/ex01-create.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void *thr_func(void *ptr) 7 | { 8 | // печатаем свой идентификатор 9 | printf("%lu\n", pthread_self()); 10 | return NULL; 11 | } 12 | 13 | int main() 14 | { 15 | // переменные для хранения идентификаторов нитей 16 | pthread_t id1 = 0, id2 = 0; 17 | 18 | // создание нитей 19 | pthread_create(&id1, NULL, thr_func, NULL); 20 | pthread_create(&id2, NULL, thr_func, NULL); 21 | 22 | // завершаем "главную" нить, процесс завершится, 23 | // когда завершатся все запущенные нити 24 | pthread_exit(NULL); 25 | 26 | //pthread_join(id1, NULL); 27 | //pthread_join(id1, NULL); 28 | } 29 | -------------------------------------------------------------------------------- /2019-2020/10-exec/1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | extern char **environ; 8 | 9 | int main(int argc, char *argv[]) 10 | { 11 | pid_t pid = fork(); 12 | if (pid < 0) { 13 | } else if (!pid) { 14 | if (chdir(argv[1]) < 0) { 15 | fprintf(stderr, "cannot chdir to '%s'\n", argv[1]); 16 | _exit(1); 17 | } 18 | char *myenv[] = 19 | { 20 | "A=1", 21 | "B=2", 22 | NULL 23 | }; 24 | execve(argv[2], &argv[2], myenv); 25 | fprintf(stderr, "exec of '%s' failed\n", argv[2]); 26 | _exit(1); 27 | } 28 | 29 | wait(NULL); 30 | } 31 | -------------------------------------------------------------------------------- /2019-2020/10-exec/6.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | extern char **environ; 8 | 9 | int main(int argc, char *argv[]) 10 | { 11 | pid_t pid = fork(); 12 | if (pid < 0) { 13 | } else if (!pid) { 14 | if (chdir(argv[1]) < 0) { 15 | fprintf(stderr, "cannot chdir to '%s'\n", argv[1]); 16 | _exit(1); 17 | } 18 | char *myenv[] = 19 | { 20 | "A=1", 21 | "B=2", 22 | NULL 23 | }; 24 | execve(argv[2], &argv[3], NULL); 25 | fprintf(stderr, "exec of '%s' failed\n", argv[2]); 26 | _exit(1); 27 | } 28 | 29 | wait(NULL); 30 | } 31 | -------------------------------------------------------------------------------- /2017-2018/sem11/ex05-pipeline-2.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | // использование Linux-specific pipe2 и флага 10 | // принудительного закрытия файловых дескрипторов при exec 11 | int main(int argc, char *argv[]) 12 | { 13 | int fds[2]; 14 | 15 | pipe2(fds, O_CLOEXEC); 16 | if (!fork()) { 17 | dup2(fds[1], 1); 18 | execlp(argv[1], argv[1], NULL); 19 | _exit(1); 20 | } 21 | if (!fork()) { 22 | dup2(fds[0], 0); 23 | execlp(argv[2], argv[2], NULL); 24 | _exit(1); 25 | } 26 | close(fds[1]); 27 | close(fds[0]); 28 | wait(NULL); 29 | wait(NULL); 30 | } 31 | -------------------------------------------------------------------------------- /old/203/pipe/pipe3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void dowork(int id, int fd0, int fd1) 7 | { 8 | while (1) { 9 | int x; 10 | read(fd0, &x, sizeof(x)); 11 | printf("%d %d\n", id, x); 12 | fflush(stdout); 13 | ++x; 14 | write(fd1, &x, sizeof(x)); 15 | } 16 | } 17 | 18 | int main(void) 19 | { 20 | int fds4[2]; 21 | int fds7[2]; 22 | pipe(fds4); 23 | pipe(fds7); 24 | if (!fork()) { 25 | dowork(1, fds4[0], fds7[1]); 26 | } 27 | if (!fork()) { 28 | dowork(2, fds7[0], fds4[1]); 29 | } 30 | int x = 1; 31 | write(fds4[1], &x, sizeof(x)); 32 | wait(NULL); 33 | wait(NULL); 34 | } 35 | -------------------------------------------------------------------------------- /2017-2018/sem07/ex02-rand1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | unsigned seed = strtol(argv[1], NULL, 10); 8 | 9 | // time() может изменяться медленнее, чем требуется 10 | if (!seed) seed = time(NULL); 11 | 12 | for (int i = 0; i < 10; ++i) { 13 | int r = rand_r(&seed); 14 | // преобразуем в вещественное равномерно распределенное [0;1) 15 | double x = r / (RAND_MAX + 1.); 16 | // дискретное равномерное [0; 10) 17 | int a = x * 10; 18 | // дискретное равномерное [A; B) 19 | enum { A = -20, B = -10 }; 20 | int b = (int) (x * (B - A)) + A; 21 | printf("%d %.10g %d %d\n", r, x, a, b); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /2019-2020/12-signal/02-sysv-signal-handling.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void hand_int(int s) 7 | { 8 | signal(SIGINT, hand_int); 9 | printf("SIGINT\n"); 10 | } 11 | 12 | void hand_fpe(int s) 13 | { 14 | printf("SIGFPE\n"); 15 | } 16 | 17 | int main() 18 | { 19 | signal(SIGINT, hand_int); 20 | signal(SIGFPE, hand_fpe); 21 | //signal(SIGFPE, SIG_IGN); 22 | 23 | int a, b, r; 24 | restart: 25 | while ((r = scanf("%d%d", &a, &b)) == 2) { 26 | int c = a / b; 27 | printf("%d\n", c); 28 | } 29 | if (r == EOF && ferror(stdin)) { 30 | printf("error: %s\n", strerror(errno)); 31 | if (errno == EINTR) goto restart; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /2017-2018/sem07/ex04-rand-oop/prng.c: -------------------------------------------------------------------------------- 1 | #include "randint.h" 2 | #include 3 | 4 | struct PrngState 5 | { 6 | struct RandomState b; 7 | unsigned int seed; 8 | }; 9 | 10 | static void destroy(struct RandomState *rst) 11 | { 12 | free(rst); 13 | } 14 | 15 | static double next(struct RandomState *rst) 16 | { 17 | struct PrngState *pst = (struct PrngState *) rst; 18 | return rand_r(&pst->seed) / (RAND_MAX + 1.); 19 | } 20 | 21 | static const struct RandomOps ops = 22 | { 23 | destroy, 24 | next 25 | }; 26 | 27 | struct RandomState *init_prng_gen(const char *str) 28 | { 29 | struct PrngState *pst = calloc(1, sizeof(*pst)); 30 | pst->b.ops = &ops; 31 | pst->seed = strtoul(str, NULL, 10); 32 | return &pst->b; 33 | } 34 | 35 | -------------------------------------------------------------------------------- /2019-2020/03-file-syscalls/3-lseek-negative.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char *argv[]) 9 | { 10 | int fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0600); 11 | 12 | int count = strtol(argv[2], NULL, 10); 13 | long long val1 = strtoll(argv[3], NULL, 10); 14 | long long val2 = strtoll(argv[4], NULL, 10); 15 | 16 | lseek(fd, (count - 1) * sizeof(val1), SEEK_SET); 17 | for (; count; --count) { 18 | write(fd, &val1, sizeof(val1)); 19 | int64_t tmp = val1; 20 | val1 = val2; 21 | val2 += tmp; 22 | lseek(fd, -2LL * sizeof(val1), SEEK_CUR); 23 | } 24 | close(fd); 25 | } 26 | -------------------------------------------------------------------------------- /2017-2018/sem05/ex01-printmax.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* 5 | * Эта программа выводит значения констант PATH_MAX и NAME_MAX 6 | */ 7 | 8 | int main() 9 | { 10 | // константа PATH_MAX: размер буфера (то есть длина строки + 1) 11 | // максимальная поддерживаемая длина пути 12 | // если длина пути (относительного или абсолютного) больше, 13 | // системные вызовы возвращают ENAMETOOLONG 14 | // значение на Linux: 4096 (4KiB), то есть максимальная длина пути: 4095 15 | printf("PATH_MAX: %d\n", PATH_MAX); 16 | // константа NAME_MAX: максимальная длина компонента имени в пути 17 | // не поддерживаются имена в каталоге длиннее чем NAME_MAX байт 18 | // значение на Linux: 255 19 | printf("NAME_MAX: %d\n", NAME_MAX); 20 | } 21 | -------------------------------------------------------------------------------- /2019-2020/08-dlopen/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -g -Wall -Werror -std=gnu11 -m32 3 | LDFLAGS = -g -m32 4 | 5 | TARGETS = m rand_stdlib.so rand_urandom.so 6 | CFILES = m.c r.c r2.c 7 | HFILES = $(wildcard *.h) 8 | OFILES = $(CFILES:.c=.o) 9 | 10 | all : $(TARGETS) 11 | 12 | m : m.o 13 | $(CC) $(LDFLAGS) $^ -o$@ -ldl 14 | 15 | rand_stdlib.so : r.o 16 | $(CC) $(LDFLAGS) -shared -fPIC -DPIC $^ -o$@ 17 | 18 | rand_urandom.so : r2.o 19 | $(CC) $(LDFLAGS) -shared -fPIC -DPIC $^ -o$@ 20 | 21 | r.o : r.c 22 | $(CC) $(CFLAGS) -fPIC -DPIC -c r.c -o$@ 23 | 24 | r2.o : r2.c 25 | $(CC) $(CFLAGS) -fPIC -DPIC -c r2.c -o$@ 26 | 27 | include deps.make 28 | 29 | deps.make : $(CFILES) $(HFILES) 30 | $(CC) -MM $(CFILES) > deps.make 31 | 32 | clean : 33 | -rm -f $(TARGETS) *.o deps.make 34 | -------------------------------------------------------------------------------- /2018-2019/sem02/07-copy2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | enum { BUFSIZE = 4096 }; 8 | 9 | int main() 10 | { 11 | char buf[BUFSIZE]; 12 | ssize_t r, w; 13 | while (1) { 14 | r = read(STDIN_FILENO, &buf, sizeof(buf)); 15 | if (r < 0) { 16 | fprintf(stderr, "error: %s\n", strerror(errno)); 17 | exit(1); 18 | } 19 | if (!r) break; 20 | char *p = buf; 21 | while (r > 0) { 22 | w = write(STDOUT_FILENO, p, r); 23 | if (w < 0) { 24 | fprintf(stderr, "error: %s\n", strerror(errno)); 25 | exit(1); 26 | } 27 | r -= w; 28 | p += w; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /2017-2018/sem11/ex02-pipesize-auto.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | // определение размера буфера канала (автоматическое) 12 | int main() 13 | { 14 | int fd[2]; 15 | 16 | pipe2(fd, O_NONBLOCK); 17 | int sz = 0; 18 | char c = 'a'; 19 | while (1) { 20 | //printf("%d\n", sz); 21 | ssize_t r = write(fd[1], &c, sizeof(c)); 22 | if (r < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) { 23 | printf("%d\n", sz); 24 | break; 25 | } 26 | if (r < 0) { 27 | fprintf(stderr, "Error: %s\n", strerror(errno)); 28 | exit(1); 29 | } 30 | ++sz; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /2019-2020/04-stat-time/2-mktime.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | int year, mon, day, hour, min, sec; 7 | 8 | while (scanf("%d%d%d%d%d%d", &year, &mon, &day, &hour, &min, &sec) == 6) { 9 | struct tm lt; 10 | 11 | lt.tm_year = year - 1900; 12 | lt.tm_mon = mon - 1; 13 | lt.tm_mday = day; 14 | lt.tm_hour = hour; 15 | lt.tm_min = min; 16 | lt.tm_sec = sec; 17 | lt.tm_isdst = -1; 18 | 19 | time_t res = mktime(<); 20 | printf("%ld %d-%02d-%02d %02d:%02d:%02d %d %d %d\n", 21 | (long) res, 22 | lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday, 23 | lt.tm_hour, lt.tm_min, lt.tm_sec, 24 | lt.tm_yday, lt.tm_wday, lt.tm_isdst); 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /2017-2018/sem12/ex05-pingpong1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // классический пинг-понг между отцом и сыном с сигналами 7 | 8 | int pid; 9 | int fd[2]; 10 | 11 | void handler(int s) 12 | { 13 | int x; 14 | if (!pid) pid = getppid(); 15 | read(fd[0], &x, sizeof(x)); 16 | printf("%d %d %d\n", getpid(), x, pid); fflush(stdout); 17 | ++x; 18 | write(fd[1], &x, sizeof(x)); 19 | kill(pid, SIGUSR1); 20 | } 21 | 22 | int main() 23 | { 24 | pipe(fd); 25 | signal(SIGUSR1, handler); 26 | pid = fork(); 27 | if (!pid) { 28 | pid = getppid(); 29 | while (1) { pause(); } 30 | } else { 31 | int z = 1; 32 | write(fd[1], &z, sizeof(z)); 33 | kill(pid, SIGUSR1); 34 | while (1) { pause(); } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /2017-2018/sem09/ex05-syscall.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | void myexitfunc() 12 | { 13 | fprintf(stderr, "atexit\n"); 14 | } 15 | 16 | int main(int argc, char *argv[]) 17 | { 18 | atexit(myexitfunc); 19 | printf("Hello"); 20 | int pid; 21 | // результат системного вызова fork() сначала попадает в %eax 22 | // а только потом копируется в переменную pid, эта 23 | // последовательность неатомарна 24 | asm("int $0x80\n" : "=a" (pid) : "a"(__NR_fork)); 25 | if (!pid) { 26 | execlp(argv[1], argv[1], NULL); 27 | fprintf(stderr, "error: %s\n", strerror(errno)); 28 | _exit(1); 29 | } 30 | 31 | wait(NULL); 32 | } 33 | -------------------------------------------------------------------------------- /2017-2018/sem06/ex07-mmap6.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /* 12 | Приватное анонимное отображение - просто память, 13 | выделенная процессу 14 | */ 15 | 16 | int main(int argc, char *argv[]) 17 | { 18 | unsigned char *ptr = mmap(NULL, getpagesize() * 256, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 19 | if (ptr == MAP_FAILED) { 20 | fprintf(stderr, "mmap: %s\n", strerror(errno)); 21 | return 1; 22 | } 23 | int count = 0; 24 | int size = getpagesize() * 16; 25 | for (int i = 0; i < size; ++i) { 26 | if (ptr[i] >= '0' && ptr[i] <= '9') { 27 | ptr[i] = 'a'; 28 | ++count; 29 | } 30 | } 31 | printf("%d\n", count); 32 | } 33 | -------------------------------------------------------------------------------- /2019-2020/06-mmap/4-anon-mmap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | typedef unsigned long long ValueType; 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | char *path = argv[1]; 16 | int count = strtol(argv[2], NULL, 10); 17 | 18 | off_t fsize = (off_t) count * (off_t) sizeof(ValueType); 19 | 20 | ValueType *ptr = mmap(NULL, fsize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 21 | if (ptr == MAP_FAILED) { 22 | fprintf(stderr, "%s: %s\n", path, strerror(errno)); 23 | exit(1); 24 | } 25 | 26 | printf("%p\n", ptr); 27 | getchar(); 28 | 29 | for (int i = 1; i <= count; ++i) { 30 | ptr[count - i] = i; 31 | } 32 | 33 | munmap(ptr, fsize); 34 | } 35 | -------------------------------------------------------------------------------- /2017-2018/sem07/ex04-rand-oop/randuse.c: -------------------------------------------------------------------------------- 1 | #include "randint.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | typedef struct RandomState * (*init_func_t)(char const *); 8 | 9 | int main(int argc, char *argv[]) 10 | { 11 | struct RandomState *state = NULL; 12 | 13 | char fname[PATH_MAX]; 14 | snprintf(fname, sizeof(fname), "./rand_%s.so", argv[2]); 15 | void *handle = dlopen(fname, RTLD_LAZY); 16 | char sname[PATH_MAX]; 17 | snprintf(sname, sizeof(sname), "init_%s_gen", argv[2]); 18 | init_func_t sym = dlsym(handle, sname); 19 | 20 | //state = ((struct RandomState * (*)(char const *)) sym)(argv[1]); 21 | state = sym(argv[1]); 22 | for (int i = 0; i < 10; ++i) { 23 | double x = state->ops->next(state); 24 | printf("%.10g\n", x); 25 | } 26 | state->ops->destroy(state); 27 | dlclose(handle); 28 | } 29 | -------------------------------------------------------------------------------- /2017-2018/sem05/ex03-scandir-bad-1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | /* 11 | * В этом примере _неправильно_ обрабатывается содержимое каталога 12 | */ 13 | 14 | int main(int argc, char *argv[]) 15 | { 16 | DIR *d = opendir(argv[1]); 17 | if (!d) { 18 | fprintf(stderr, "error: %s\n", strerror(errno)); 19 | exit(1); 20 | } 21 | struct dirent *dd; 22 | while ((dd = readdir(d))) { 23 | printf("%lu %s\n", dd->d_ino, dd->d_name); 24 | struct stat stb; 25 | if (stat(dd->d_name, &stb) < 0) continue; 26 | // ^^^^^^^^^^ - здесь ошибка: должен быть полный путь, а не последняя компонента пути 27 | printf("stat: %lu %llu\n", stb.st_ino, stb.st_dev); 28 | } 29 | closedir(d); 30 | } 31 | -------------------------------------------------------------------------------- /2019-2020/13-signal-safe/01-ping-pong-basic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int fd[2]; 7 | int pid; 8 | 9 | void handler(int s) 10 | { 11 | int x; 12 | if (!pid) pid = getppid(); 13 | read(fd[0], &x, sizeof(x)); 14 | printf("%d %d %d\n", pid, getpid(), x); fflush(stdout); 15 | ++x; 16 | write(fd[1], &x, sizeof(x)); 17 | kill(pid, SIGUSR1); 18 | } 19 | 20 | int main() 21 | { 22 | pipe(fd); 23 | 24 | sigaction(SIGUSR1, &(struct sigaction) { .sa_handler = handler }, NULL); 25 | 26 | pid = fork(); 27 | if (!pid) { 28 | 29 | while (1) { 30 | pause(); 31 | } 32 | 33 | _exit(0); 34 | } 35 | 36 | { 37 | int x = 1; 38 | write(fd[1], &x, sizeof(x)); 39 | kill(pid, SIGUSR1); 40 | } 41 | 42 | while (1) { 43 | pause(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /2017-2018/sem12/ex02-sig2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | /* 7 | Различие SystemV и BSD семантики обработки сигналов. 8 | BSD семантика: 9 | gcc ex01-sig2.c -O2 -Wall -std=gnu11 -oex01-sig2 10 | SystemV семантика 11 | gcc ex01-sig2.c -O2 -Wall -std=c11 -D_POSIX_C_SOURCE=299901 -oex01-sig2 12 | */ 13 | void handler(int s) 14 | { 15 | fprintf(stderr, "signal: %d\n", s); 16 | } 17 | 18 | int main() 19 | { 20 | int a, b; 21 | signal(SIGINT, handler); 22 | signal(SIGFPE, handler); 23 | int r; 24 | restart: 25 | while ((r = scanf("%d%d", &a, &b)) == 2) { 26 | printf("%d\n", a / b); 27 | } 28 | if (r == EOF) { 29 | if (feof(stdin)) { 30 | printf("EOF!\n"); 31 | } else if (ferror(stdin)) { 32 | printf("%s\n", strerror(errno)); 33 | goto restart; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /2017-2018/sem12/ex03-sig3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void handler(int s) 7 | { 8 | fprintf(stderr, "signal: %d\n", s); 9 | } 10 | 11 | /* 12 | Использование системного вызова sigaction 13 | */ 14 | int main() 15 | { 16 | int a, b; 17 | struct sigaction safpe = 18 | { 19 | .sa_handler = handler, 20 | .sa_flags = SA_RESTART 21 | }; 22 | sigaction(SIGINT, &safpe, NULL); 23 | sigaction(SIGFPE, &(struct sigaction) { .sa_handler = handler, .sa_flags = SA_RESTART }, NULL); 24 | int r; 25 | restart: 26 | while ((r = scanf("%d%d", &a, &b)) == 2) { 27 | printf("%d\n", a / b); 28 | } 29 | if (r == EOF) { 30 | if (feof(stdin)) { 31 | printf("EOF!\n"); 32 | } else if (ferror(stdin)) { 33 | printf("%s\n", strerror(errno)); 34 | goto restart; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /2023-2024/format.yaml: -------------------------------------------------------------------------------- 1 | LineEnding: LF 2 | BasedOnStyle: LLVM 3 | IndentWidth: 4 4 | ColumnLimit: 120 5 | UseTab: Never 6 | SortIncludes: Never 7 | SpaceAfterCStyleCast: true 8 | IndentCaseLabels: false 9 | InsertBraces: true 10 | InsertNewlineAtEOF: true 11 | IndentGotoLabels: false 12 | AlwaysBreakAfterReturnType: AllDefinitions 13 | AllowShortEnumsOnASingleLine: true 14 | BreakBeforeBraces: Custom 15 | BraceWrapping: 16 | AfterCaseLabel: false 17 | AfterClass: true 18 | AfterControlStatement: Never 19 | AfterEnum: true 20 | AfterExternBlock: false 21 | AfterFunction: true 22 | AfterNamespace: true 23 | AfterObjCDeclaration: false 24 | AfterStruct: true 25 | AfterUnion: true 26 | BeforeCatch: false 27 | BeforeElse: false 28 | BeforeLambdaBody: false 29 | BeforeWhile: false 30 | IndentBraces: false 31 | SplitEmptyFunction: true 32 | SplitEmptyRecord: true 33 | SplitEmptyNamespace: true 34 | -------------------------------------------------------------------------------- /old/203/pipe/pipe2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | int prevfd = -1; 9 | for (int i = 1; i < argc; ++i) { 10 | int fds[2]; 11 | if (i < argc - 1) { 12 | pipe(fds); 13 | } 14 | if (!fork()) { 15 | if (i > 1) { 16 | dup2(prevfd, 0); 17 | close(prevfd); 18 | } 19 | if (i < argc - 1) { 20 | dup2(fds[1], 1); 21 | close(fds[1]); 22 | close(fds[0]); 23 | } 24 | execlp(argv[i], argv[i], NULL); 25 | _exit(1); 26 | } 27 | if (i < argc - 1) { 28 | close(fds[1]); 29 | } 30 | if (i > 1) { 31 | close(prevfd); 32 | } 33 | prevfd = fds[0]; 34 | } 35 | while (wait(NULL) > 0) {} 36 | } 37 | -------------------------------------------------------------------------------- /2017-2018/sem06/ex02-mmap1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /* 12 | Использование mmap для подсчета количества цифровых символов 13 | */ 14 | 15 | int main(int argc, char *argv[]) 16 | { 17 | int fd = open(argv[1], O_RDONLY, 0); 18 | if (fd < 0) { 19 | fprintf(stderr, "open: %s\n", strerror(errno)); 20 | return 1; 21 | } 22 | struct stat stb; 23 | fstat(fd, &stb); 24 | unsigned char *ptr = mmap(NULL, stb.st_size, PROT_READ, MAP_SHARED, fd, 0); 25 | if (ptr == MAP_FAILED) { 26 | fprintf(stderr, "mmap: %s\n", strerror(errno)); 27 | return 1; 28 | } 29 | close(fd); 30 | int count = 0; 31 | for (int i = 0; i < stb.st_size; ++i) { 32 | count += (ptr[i] >= '0' && ptr[i] <= '9'); 33 | } 34 | printf("%d\n", count); 35 | } 36 | -------------------------------------------------------------------------------- /2017-2018/sem07/ex04-rand-oop/trng.c: -------------------------------------------------------------------------------- 1 | #include "randint.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | struct TrngState 9 | { 10 | struct RandomState b; 11 | int fd; 12 | }; 13 | 14 | static void destroy(struct RandomState *rst) 15 | { 16 | struct TrngState *pst = (struct TrngState *) rst; 17 | close(pst->fd); 18 | free(rst); 19 | } 20 | 21 | static double next(struct RandomState *rst) 22 | { 23 | struct TrngState *pst = (struct TrngState *) rst; 24 | unsigned val; 25 | read(pst->fd, &val, sizeof(val)); 26 | return val / (UINT_MAX + 1.); 27 | } 28 | 29 | static const struct RandomOps ops = 30 | { 31 | destroy, 32 | next 33 | }; 34 | 35 | struct RandomState *init_trng_gen(const char *str) 36 | { 37 | struct TrngState *pst = calloc(1, sizeof(*pst)); 38 | pst->b.ops = &ops; 39 | pst->fd = open("/dev/urandom", O_RDONLY, 0); 40 | return &pst->b; 41 | } 42 | 43 | -------------------------------------------------------------------------------- /2017-2018/sem06/ex06-mmap5.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /* 12 | отображение "анонимных" страниц в адресное пространство. 13 | shared отображение будет разделяться между процессом 14 | и его сыновьями, то есть они будут работать с 15 | разделяемой памятью 16 | */ 17 | 18 | int main(int argc, char *argv[]) 19 | { 20 | unsigned char *ptr = mmap(NULL, getpagesize() * 256, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); 21 | if (ptr == MAP_FAILED) { 22 | fprintf(stderr, "mmap: %s\n", strerror(errno)); 23 | return 1; 24 | } 25 | int count = 0; 26 | int size = getpagesize() * 16; 27 | for (int i = 0; i < size; ++i) { 28 | if (ptr[i] >= '0' && ptr[i] <= '9') { 29 | ptr[i] = 'a'; 30 | ++count; 31 | } 32 | } 33 | printf("%d\n", count); 34 | } 35 | -------------------------------------------------------------------------------- /2017-2018/sem02/example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | extern char **environ; 8 | 9 | int main(int argc, char **argv) 10 | { 11 | // печать аргументов командной строки 12 | for (int i = 1; i < argc; ++i) { 13 | printf("%d: %s\n", i, argv[i]); 14 | } 15 | // печать переменных окружения 16 | for (int i = 0; environ[i]; ++i) { 17 | printf("%s\n", environ[i]); 18 | } 19 | // установка локали в зависимости от окружения 20 | setlocale(LC_ALL, ""); 21 | // запрос значения переменной окружения 22 | char *s = getenv(argv[1]); 23 | if (s) { 24 | printf("%s\n", s); 25 | } 26 | FILE *f = fopen(argv[2], "r"); 27 | if (!f) { 28 | // сообщение об ошибке выводится на stderr 29 | // в конце вывода обязателен \n 30 | fprintf(stderr, "error: %s\n", strerror(errno)); 31 | // ненулевой код завершения программы 32 | return 1; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /2017-2018/sem05/ex06-scandir-2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /* 12 | * Использование нестандартной функции asprintf (GNU extension) 13 | * Компилировать с опцией -D_GNU_SOURCE 14 | */ 15 | 16 | int main(int argc, char *argv[]) 17 | { 18 | DIR *d = opendir(argv[1]); 19 | if (!d) { 20 | fprintf(stderr, "error: %s\n", strerror(errno)); 21 | exit(1); 22 | } 23 | struct dirent *dd; 24 | char *path = NULL; 25 | while ((dd = readdir(d))) { 26 | free(path); 27 | int slen = asprintf(&path, "%s/%s", argv[1], dd->d_name); 28 | 29 | printf("%s %d %lu %s\n", path, slen, dd->d_ino, dd->d_name); 30 | struct stat stb; 31 | if (stat(path, &stb) < 0) continue; 32 | printf("stat: %lu %llu\n", stb.st_ino, stb.st_dev); 33 | } 34 | free(path); 35 | closedir(d); 36 | } 37 | -------------------------------------------------------------------------------- /2017-2018/sem13/ex01-sem1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // заголовочные файлы для SysV IPC семафоров 7 | #include 8 | #include 9 | 10 | enum { KEY = 0xdeadbeef }; 11 | 12 | /* 13 | * пример на создание/удаление и изменение свойств SysV IPC массивов семафоров 14 | */ 15 | int main(void) 16 | { 17 | // получаем массив из 3 семафоров 18 | int semid = semget(KEY, 3, 0600 | IPC_CREAT | IPC_EXCL); 19 | if (semid < 0) { 20 | fprintf(stderr, "error: %s\n", strerror(errno)); 21 | exit(1); 22 | } 23 | 24 | // устанавливаем все значения одновременно 25 | semctl(semid, 0, SETALL, (unsigned short[]) { 20, 0, 20000 }); 26 | // устанавливаем значение семафора с индексом 1 27 | semctl(semid, 1, SETVAL, 10); 28 | // выводим значения семафоров 0 и 1 29 | printf("%d\n%d\n", semctl(semid, 0, GETVAL), semctl(semid, 1, GETVAL)); 30 | 31 | // удаляем массив семафоров 32 | semctl(semid, 0, IPC_RMID); 33 | } 34 | -------------------------------------------------------------------------------- /2017-2018/sem14/client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | enum { PORTNUM = 11111 }; 11 | 12 | int main(int argc, char *argv[]) 13 | { 14 | int fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 15 | if (fd < 0) { 16 | fprintf(stderr, "socket: %s\n", strerror(errno)); 17 | return 1; 18 | } 19 | 20 | int port = strtol(argv[1], 0, 10); 21 | 22 | struct sockaddr_in s1; 23 | inet_aton(argv[2], &s1.sin_addr); 24 | s1.sin_family = AF_INET; 25 | s1.sin_port = htons(port); 26 | if (connect(fd, (struct sockaddr *) &s1, sizeof(s1)) < 0) { 27 | fprintf(stderr, "connect: %s\n", strerror(errno)); 28 | return 1; 29 | } 30 | 31 | char c; 32 | while (read(0, &c, sizeof(c)) == 1) { 33 | write(fd, &c, sizeof(c)); 34 | read(fd, &c, sizeof(c)); 35 | write(1, &c, sizeof(c)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /2017-2018/sem10/ex03-arbitrary-argv0.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main() 11 | { 12 | int pid = fork(); 13 | if (!pid) { 14 | // в качестве argv[0] в запускаемую программу может быть 15 | // передано что угодно 16 | execlp("./prog3.xx", "./fork3", "-l", NULL); 17 | fprintf(stderr, "exec failed: %s\n", strerror(errno)); 18 | _exit(1); 19 | } 20 | 21 | int status; 22 | int p = waitpid(-1, &status, 0); 23 | if (p < 0) { 24 | fprintf(stderr, "error: %s\n", strerror(errno)); 25 | exit(1); 26 | } 27 | if (!p) { 28 | printf("no processes\n"); 29 | exit(1); 30 | } 31 | printf("%d\n", p); 32 | if (WIFEXITED(status)) { 33 | printf("%d\n", WEXITSTATUS(status)); 34 | } else if (WIFSIGNALED(status)) { 35 | printf("%d\n", WTERMSIG(status)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /2017-2018/sem11/ex06-ping-pong.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | enum { MAXVAL = 10000 }; 8 | 9 | void work(int rfd, int wfd) 10 | { 11 | int x; 12 | while (read(rfd, &x, sizeof(x)) == sizeof(x)) { 13 | ++x; 14 | printf("%d %d\n", getpid(), x - 1); fflush(stdout); 15 | if (x == MAXVAL) break; 16 | write(wfd, &x, sizeof(x)); 17 | } 18 | } 19 | 20 | int main() 21 | { 22 | int p12[2]; 23 | int p21[2]; 24 | 25 | pipe(p12); 26 | pipe(p21); 27 | 28 | if (!fork()) { 29 | close(p21[1]); close(p12[0]); 30 | work(p21[0], p12[1]); 31 | _exit(1); 32 | } 33 | if (!fork()) { 34 | close(p12[1]); close(p21[0]); 35 | work(p12[0], p21[1]); 36 | _exit(1); 37 | } 38 | int z = 1; 39 | write(p21[1], &z, sizeof(z)); 40 | 41 | close(p12[0]); close(p12[1]); 42 | close(p21[0]); close(p21[1]); 43 | wait(NULL); 44 | wait(NULL); 45 | } 46 | -------------------------------------------------------------------------------- /2017-2018/sem06/ex03-mmap2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /* 12 | модификация файла, отображенного в память 13 | */ 14 | 15 | int main(int argc, char *argv[]) 16 | { 17 | int fd = open(argv[1], O_RDWR, 0); 18 | if (fd < 0) { 19 | fprintf(stderr, "open: %s\n", strerror(errno)); 20 | return 1; 21 | } 22 | struct stat stb; 23 | fstat(fd, &stb); 24 | unsigned char *ptr = mmap(NULL, stb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 25 | if (ptr == MAP_FAILED) { 26 | fprintf(stderr, "mmap: %s\n", strerror(errno)); 27 | return 1; 28 | } 29 | close(fd); 30 | int count = 0; 31 | for (int i = 0; i < stb.st_size; ++i) { 32 | if (ptr[i] >= '0' && ptr[i] <= '9') { 33 | ptr[i] = 'a'; 34 | ++count; 35 | } 36 | } 37 | printf("%d\n", count); 38 | } 39 | -------------------------------------------------------------------------------- /2017-2018/sem10/ex04-shell-use.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | // использование стандартного интерпретатора 11 | // командной строки /bin/sh 12 | int main(int argc, char *argv[]) 13 | { 14 | int pid = fork(); 15 | if (!pid) { 16 | // process argv[1] 17 | execlp("/bin/sh", "sh", "-c", argv[1], NULL); 18 | fprintf(stderr, "exec failed: %s\n", strerror(errno)); 19 | _exit(1); 20 | } 21 | 22 | int status; 23 | int p = waitpid(-1, &status, 0); 24 | if (p < 0) { 25 | fprintf(stderr, "error: %s\n", strerror(errno)); 26 | exit(1); 27 | } 28 | if (!p) { 29 | printf("no processes\n"); 30 | exit(1); 31 | } 32 | printf("%d\n", p); 33 | if (WIFEXITED(status)) { 34 | printf("%d\n", WEXITSTATUS(status)); 35 | } else if (WIFSIGNALED(status)) { 36 | printf("%d\n", WTERMSIG(status)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /2017-2018/sem06/ex05-mmap4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /* 12 | изменения, внесенные в файл, отображенный в private-режиме, 13 | не сохраняются в файл 14 | */ 15 | 16 | int main(int argc, char *argv[]) 17 | { 18 | int fd = open(argv[1], O_RDONLY, 0); 19 | if (fd < 0) { 20 | fprintf(stderr, "open: %s\n", strerror(errno)); 21 | return 1; 22 | } 23 | struct stat stb; 24 | fstat(fd, &stb); 25 | unsigned char *ptr = mmap(NULL, stb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 26 | if (ptr == MAP_FAILED) { 27 | fprintf(stderr, "mmap: %s\n", strerror(errno)); 28 | return 1; 29 | } 30 | close(fd); 31 | int count = 0; 32 | for (int i = 0; i < stb.st_size; ++i) { 33 | if (ptr[i] >= '0' && ptr[i] <= '9') { 34 | ptr[i] = 'a'; 35 | ++count; 36 | } 37 | } 38 | printf("%d\n", count); 39 | } 40 | -------------------------------------------------------------------------------- /2017-2018/sem05/ex04-scandir-bad-2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /* 12 | * В этом примере _НЕДОПУСТИМО_ обрабатывается содержимое каталога 13 | */ 14 | 15 | int main(int argc, char *argv[]) 16 | { 17 | DIR *d = opendir(argv[1]); 18 | if (!d) { 19 | fprintf(stderr, "error: %s\n", strerror(errno)); 20 | exit(1); 21 | } 22 | struct dirent *dd; 23 | char path[PATH_MAX]; 24 | while ((dd = readdir(d))) { 25 | strcat(strcat(strcpy(path, argv[1]), "/"), dd->d_name); 26 | // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 27 | // ОЧЕНЬ-ОЧЕНЬ-ОЧЕНЬ плохо. Возможно переполнение буфера! 28 | // sprintf также плохо 29 | printf("%s %lu %s\n", path, dd->d_ino, dd->d_name); 30 | struct stat stb; 31 | if (stat(path, &stb) < 0) continue; 32 | printf("stat: %lu %llu\n", stb.st_ino, stb.st_dev); 33 | } 34 | closedir(d); 35 | } 36 | -------------------------------------------------------------------------------- /2017-2018/sem08/ex07-race-cond.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | enum { N = 10 }; 9 | 10 | void *thr_func(void *ptr) 11 | { 12 | int c; 13 | // пара чтение символа-запись символа не атомарна - Race Condition 14 | while ((c = getchar()) != EOF) { 15 | putchar(c); 16 | } 17 | return NULL; 18 | } 19 | 20 | int main() 21 | { 22 | pthread_t ids[N]; 23 | 24 | pthread_attr_t attr; 25 | 26 | pthread_attr_init(&attr); 27 | 28 | pthread_attr_setstacksize(&attr, 16384); 29 | pthread_attr_setguardsize(&attr, 0); 30 | 31 | int i; 32 | for (i = 0; i < N; ++i) { 33 | int err; 34 | err = pthread_create(&ids[i], &attr, thr_func, (void*) (intptr_t) i); 35 | if (err) { 36 | fprintf(stderr, "error: %d %s\n", i, strerror(err)); 37 | pause(); 38 | } 39 | } 40 | 41 | pthread_attr_destroy(&attr); 42 | 43 | for (int i = 0; i < N; ++i) { 44 | pthread_join(ids[i], NULL); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /2017-2018/sem10/ex02-waitpid.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main() 11 | { 12 | int pid = fork(); 13 | if (!pid) { 14 | raise(SIGSEGV); 15 | //_exit(500); 16 | } 17 | int pid2 = fork(); 18 | if (!pid2) { 19 | _exit(120); 20 | } 21 | 22 | //usleep(100); 23 | int status; 24 | // waitpid позволяет проверить, завершился ли какой-либо 25 | // из процессов-сыновей без приостановки выполнения 26 | // процесса-родителя 27 | int p = waitpid(-1, &status, WNOHANG); 28 | if (p < 0) { 29 | fprintf(stderr, "error: %s\n", strerror(errno)); 30 | exit(1); 31 | } 32 | if (!p) { 33 | printf("no processes\n"); 34 | exit(1); 35 | } 36 | printf("%d\n", p); 37 | if (WIFEXITED(status)) { 38 | printf("%d\n", WEXITSTATUS(status)); 39 | } else if (WIFSIGNALED(status)) { 40 | printf("%d\n", WTERMSIG(status)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /2019-2020/13-signal-safe/02-ping-pong-siginfo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int fd[2]; 7 | 8 | void handler(int s, siginfo_t *pinfo, void *ptr) 9 | { 10 | int pid = pinfo->si_pid; 11 | int x; 12 | read(fd[0], &x, sizeof(x)); 13 | printf("%d %d %d\n", pid, getpid(), x); fflush(stdout); 14 | ++x; 15 | write(fd[1], &x, sizeof(x)); 16 | if (pid > 0) { 17 | kill(pid, SIGUSR1); 18 | } 19 | } 20 | 21 | int main() 22 | { 23 | pipe(fd); 24 | 25 | sigaction(SIGUSR1, &(struct sigaction) { .sa_sigaction = handler, .sa_flags = SA_SIGINFO }, NULL); 26 | 27 | int pid = fork(); 28 | if (!pid) { 29 | //sigaction(SIGUSR1, &(struct sigaction) { .sa_handler = handler }, NULL); 30 | pid = getppid(); 31 | 32 | while (1) { 33 | pause(); 34 | } 35 | 36 | _exit(0); 37 | } 38 | 39 | { 40 | int x = 1; 41 | write(fd[1], &x, sizeof(x)); 42 | kill(pid, SIGUSR1); 43 | } 44 | 45 | while (1) { 46 | pause(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /2019-2020/11-pipe/4-pingpong.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | void work(int rfd, int wfd, int maxval) 8 | { 9 | while (1) { 10 | int v; 11 | int r = read(rfd, &v, sizeof(v)); 12 | if (r <= 0) break; 13 | ++v; 14 | printf("%d %d\n", getpid(), v - 1); fflush(stdout); 15 | if (v == maxval) { 16 | //close(wfd); 17 | break; 18 | } 19 | write(wfd, &v, sizeof(v)); 20 | } 21 | } 22 | 23 | int main() 24 | { 25 | int fd12[2]; 26 | int fd21[2]; 27 | 28 | pipe(fd12); 29 | pipe(fd21); 30 | 31 | if (!fork()) { 32 | close(fd12[0]); close(fd21[1]); 33 | work(fd21[0], fd12[1], 101); 34 | _exit(1); 35 | } 36 | if (!fork()) { 37 | close(fd12[1]); close(fd21[0]); 38 | work(fd12[0], fd21[1], 101); 39 | _exit(1); 40 | } 41 | 42 | int v = 1; 43 | write(fd21[1], &v, sizeof(v)); 44 | 45 | close(fd12[0]); close(fd21[1]); 46 | close(fd12[1]); close(fd21[0]); 47 | while (wait(NULL) > 0) {} 48 | } 49 | -------------------------------------------------------------------------------- /2017-2018/sem08/ex06-thread-unsafe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | enum { N = 10 }; 9 | 10 | // недопустимость использования thread-unsafe функций 11 | // в многопоточной программе 12 | void *thr_func(void *ptr) 13 | { 14 | int c; 15 | while ((c = getchar_unlocked()) != EOF) { 16 | putchar_unlocked(c); 17 | } 18 | return NULL; 19 | } 20 | 21 | int main() 22 | { 23 | pthread_t ids[N]; 24 | 25 | pthread_attr_t attr; 26 | 27 | pthread_attr_init(&attr); 28 | 29 | pthread_attr_setstacksize(&attr, 16384); 30 | pthread_attr_setguardsize(&attr, 0); 31 | 32 | int i; 33 | for (i = 0; i < N; ++i) { 34 | int err; 35 | err = pthread_create(&ids[i], &attr, thr_func, (void*) (intptr_t) i); 36 | if (err) { 37 | fprintf(stderr, "error: %d %s\n", i, strerror(err)); 38 | pause(); 39 | } 40 | } 41 | 42 | pthread_attr_destroy(&attr); 43 | 44 | for (int i = 0; i < N; ++i) { 45 | pthread_join(ids[i], NULL); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /2019-2020/08-dlopen/r.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "r.h" 6 | 7 | struct StdlibRandomContext 8 | { 9 | struct RandomContext b; 10 | 11 | unsigned int seed; 12 | }; 13 | 14 | static void rand_init(struct RandomContext *cntx) 15 | { 16 | struct StdlibRandomContext *rc = (struct StdlibRandomContext *) cntx; 17 | rc->seed = time(NULL); 18 | } 19 | 20 | static int rand_n(struct RandomContext *cntx, int n) 21 | { 22 | struct StdlibRandomContext *rc = (struct StdlibRandomContext *) cntx; 23 | assert(n > 0); 24 | int res = (int)((rand_r(&rc->seed) / (RAND_MAX + 1.0)) * n); 25 | return res; 26 | } 27 | 28 | static void rand_destroy(struct RandomContext *cntx) 29 | { 30 | struct StdlibRandomContext *rc = (struct StdlibRandomContext *) cntx; 31 | free(rc); 32 | } 33 | 34 | static const struct RandomOperations ops = 35 | { 36 | rand_init, 37 | rand_destroy, 38 | rand_n 39 | }; 40 | 41 | struct RandomContext * 42 | CREATE_FUNC_NAME(stdlib,1)() 43 | { 44 | struct StdlibRandomContext *rc = calloc(1, sizeof(*rc)); 45 | rc->b.ops = &ops; 46 | return &rc->b; 47 | } 48 | -------------------------------------------------------------------------------- /2019-2020/13-signal-safe/06-ping-pong-signalfd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void work(int sfd, int fd[2]) 8 | { 9 | sigset_t s2; 10 | sigemptyset(&s2); 11 | 12 | while (1) { 13 | int x; 14 | struct signalfd_siginfo ssi; 15 | read(sfd, &ssi, sizeof(ssi)); 16 | read(fd[0], &x, sizeof(x)); 17 | printf("%d %d %d\n", ssi.ssi_pid, getpid(), x); fflush(stdout); 18 | ++x; 19 | write(fd[1], &x, sizeof(x)); 20 | kill(ssi.ssi_pid, SIGUSR1); 21 | } 22 | } 23 | 24 | int main() 25 | { 26 | int fd[2]; 27 | int pid; 28 | 29 | pipe(fd); 30 | 31 | sigset_t s1; 32 | sigemptyset(&s1); 33 | sigaddset(&s1, SIGUSR1); 34 | 35 | sigprocmask(SIG_BLOCK, &s1, NULL); 36 | 37 | int sfd = signalfd(-1, &s1, 0); 38 | 39 | pid = fork(); 40 | if (!pid) { 41 | work(sfd, fd); 42 | 43 | 44 | _exit(0); 45 | } 46 | 47 | { 48 | int x = 1; 49 | write(fd[1], &x, sizeof(x)); 50 | kill(pid, SIGUSR1); 51 | } 52 | work(sfd, fd); 53 | } 54 | -------------------------------------------------------------------------------- /2019-2020/13-signal-safe/04-ping-pong-sigsuspend.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int fd[2]; 7 | int pid; 8 | 9 | void handler(int s) 10 | { 11 | int x; 12 | read(fd[0], &x, sizeof(x)); 13 | printf("%d %d %d\n", pid, getpid(), x); fflush(stdout); 14 | ++x; 15 | write(fd[1], &x, sizeof(x)); 16 | kill(pid, SIGUSR1); 17 | } 18 | 19 | int main() 20 | { 21 | pipe(fd); 22 | 23 | sigset_t s1, s2; 24 | sigemptyset(&s1); 25 | sigaddset(&s1, SIGUSR1); 26 | sigemptyset(&s2); 27 | 28 | sigprocmask(SIG_BLOCK, &s1, NULL); 29 | 30 | pid = fork(); 31 | if (!pid) { 32 | sigaction(SIGUSR1, &(struct sigaction) { .sa_handler = handler }, NULL); 33 | pid = getppid(); 34 | 35 | while (1) { 36 | sigsuspend(&s2); 37 | } 38 | 39 | _exit(0); 40 | } 41 | 42 | sigaction(SIGUSR1, &(struct sigaction) { .sa_handler = handler }, NULL); 43 | { 44 | int x = 1; 45 | write(fd[1], &x, sizeof(x)); 46 | kill(pid, SIGUSR1); 47 | } 48 | 49 | while (1) { 50 | sigsuspend(&s2); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /2017-2018/sem10/ex05-execve.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | extern char **environ; 11 | 12 | // передача произвольного окружения 13 | // в программу, запускаемую с помощью системного вызова execve 14 | int main(int argc, char *argv[]) 15 | { 16 | int pid = fork(); 17 | if (!pid) { 18 | char *args[2] = { "prog.py", NULL }; 19 | char *env[2] = { "var=value", NULL }; 20 | execve("/bin/sh", args, NULL); 21 | fprintf(stderr, "exec failed: %s\n", strerror(errno)); 22 | _exit(1); 23 | } 24 | 25 | int status; 26 | int p = waitpid(-1, &status, 0); 27 | if (p < 0) { 28 | fprintf(stderr, "error: %s\n", strerror(errno)); 29 | exit(1); 30 | } 31 | if (!p) { 32 | printf("no processes\n"); 33 | exit(1); 34 | } 35 | printf("%d\n", p); 36 | if (WIFEXITED(status)) { 37 | printf("%d\n", WEXITSTATUS(status)); 38 | } else if (WIFSIGNALED(status)) { 39 | printf("%d\n", WTERMSIG(status)); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /2017-2018/sem08/ex05-stress.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | // стресс-тест на максимальное число создаваемых нитей 9 | enum { N = 100000 }; 10 | 11 | void *thr_func(void *ptr) 12 | { 13 | printf("%d\n", (int) (intptr_t) ptr); 14 | pause(); 15 | return NULL; 16 | } 17 | 18 | int main() 19 | { 20 | pthread_t ids[N]; 21 | 22 | pthread_attr_t attr; 23 | 24 | pthread_attr_init(&attr); 25 | 26 | // устанавливаем минимальный размер стека 27 | // и отключаем "сторожевую" страницу внизу стека каждой нити 28 | size_t minstacksize = sysconf(_SC_THREAD_STACK_MIN); 29 | pthread_attr_setstacksize(&attr, minstacksize); 30 | pthread_attr_setguardsize(&attr, 0); 31 | 32 | int i; 33 | for (i = 0; i < N; ++i) { 34 | int err; 35 | err = pthread_create(&ids[i], &attr, thr_func, (void*) (intptr_t) i); 36 | if (err) { 37 | fprintf(stderr, "error: %d %s\n", i, strerror(err)); 38 | pause(); 39 | } 40 | } 41 | 42 | pthread_attr_destroy(&attr); 43 | 44 | for (int i = 0; i < N; ++i) { 45 | pthread_join(ids[i], NULL); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /2019-2020/13-signal-safe/03-ping-pong-sigprocmask.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int fd[2]; 7 | int pid; 8 | 9 | void handler(int s) 10 | { 11 | int x; 12 | read(fd[0], &x, sizeof(x)); 13 | printf("%d %d %d\n", pid, getpid(), x); fflush(stdout); 14 | ++x; 15 | write(fd[1], &x, sizeof(x)); 16 | kill(pid, SIGUSR1); 17 | } 18 | 19 | int main() 20 | { 21 | pipe(fd); 22 | 23 | sigset_t s1, s2; 24 | sigemptyset(&s1); 25 | sigaddset(&s1, SIGUSR1); 26 | sigemptyset(&s2); 27 | 28 | sigprocmask(SIG_BLOCK, &s1, NULL); 29 | 30 | pid = fork(); 31 | if (!pid) { 32 | sigaction(SIGUSR1, &(struct sigaction) { .sa_handler = handler }, NULL); 33 | pid = getppid(); 34 | 35 | sigprocmask(SIG_UNBLOCK, &s1, NULL); 36 | while (1) { 37 | pause(); 38 | } 39 | 40 | _exit(0); 41 | } 42 | 43 | sigaction(SIGUSR1, &(struct sigaction) { .sa_handler = handler }, NULL); 44 | { 45 | int x = 1; 46 | write(fd[1], &x, sizeof(x)); 47 | kill(pid, SIGUSR1); 48 | } 49 | sigprocmask(SIG_UNBLOCK, &s1, NULL); 50 | 51 | while (1) { 52 | pause(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /2017-2018/sem05/ex05-scandir-1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /* 12 | * Использование snprintf для получения полного пути 13 | */ 14 | 15 | int main(int argc, char *argv[]) 16 | { 17 | DIR *d = opendir(argv[1]); 18 | if (!d) { 19 | fprintf(stderr, "error: %s\n", strerror(errno)); 20 | exit(1); 21 | } 22 | struct dirent *dd; 23 | char path[PATH_MAX]; 24 | while ((dd = readdir(d))) { 25 | int slen = snprintf(path, sizeof(path), "%s/%s", argv[1], dd->d_name); 26 | // в переменной slen находится длина строки в предположении, что буфер неограничен 27 | if (slen + 1 > sizeof(path)) { 28 | // буфер оказался недостаточного размера для размещения всего пути 29 | // как-то обработать эту ситуацию... 30 | continue; 31 | } 32 | 33 | printf("%s %d %lu %s\n", path, slen, dd->d_ino, dd->d_name); 34 | struct stat stb; 35 | if (stat(path, &stb) < 0) continue; 36 | printf("stat: %lu %llu\n", stb.st_ino, stb.st_dev); 37 | } 38 | closedir(d); 39 | } 40 | -------------------------------------------------------------------------------- /2019-2020/08-dlopen/m.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "r.h" 9 | 10 | typedef struct RandomContext * (*create_func_t)(void); 11 | 12 | struct RandomContext *random_factory(const char *name) 13 | { 14 | char path[PATH_MAX]; 15 | snprintf(path, sizeof(path), "./rand_%s.so", name); 16 | void *handle = dlopen(path, RTLD_LAZY); 17 | if (!handle) { 18 | fprintf(stderr, "error: %s\n", dlerror()); 19 | exit(1); 20 | } 21 | 22 | char fn[512]; 23 | snprintf(fn, sizeof(fn), "create_%s_random_v%d", name, INTERFACE_VERSION); 24 | void *func = dlsym(handle, fn); 25 | if (!func) { 26 | fprintf(stderr, "error: %s\n", dlerror()); 27 | exit(1); 28 | } 29 | return ((create_func_t) func)(); 30 | } 31 | 32 | int main(int argc, char *argv[]) 33 | { 34 | int max_rand = strtol(argv[1], NULL, 10); 35 | int count = strtol(argv[2], NULL, 10); 36 | 37 | struct RandomContext *cntx = random_factory(argv[3]); 38 | 39 | cntx->ops->init(cntx); 40 | 41 | for (int i = 0; i < count; ++i) { 42 | printf("%d\n", cntx->ops->rand_n(cntx, max_rand)); 43 | } 44 | 45 | cntx->ops->destroy(cntx); 46 | } 47 | -------------------------------------------------------------------------------- /2017-2018/sem05/ex10-time.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* 5 | * Пример работы с функциями time, localtime_r, mktime 6 | */ 7 | 8 | int main() 9 | { 10 | // получаем текущее время в формате time_t 11 | time_t cur = time(NULL); 12 | printf("%ld %zu\n", cur, sizeof(cur)); 13 | 14 | // конвертируем время из формата time_t в формат struct tm 15 | struct tm ttm; 16 | localtime_r(&cur, &ttm); 17 | 18 | // выводим время 19 | printf("%04d-%02d-%02d %02d:%02d:%02d %d\n", 20 | ttm.tm_year + 1900, ttm.tm_mon + 1, ttm.tm_mday, 21 | ttm.tm_hour, ttm.tm_min, ttm.tm_sec, ttm.tm_isdst); 22 | 23 | ttm.tm_mday += 59; 24 | ttm.tm_isdst = -1; // если не знаем статус зимнего/летнего времени, устанавливаем флаг в -1 25 | // как правило, неизвестно, будет ли действовать летнее время, поэтому перед вызовом 26 | // mktime необходимо не забыть присвоить tm_isdst в -1 27 | // mktime конвертирует время в формат time_t и нормализует поля в структуре, переданной на вход 28 | time_t next = mktime(&ttm); 29 | printf("%ld\n", next); 30 | printf("%04d-%02d-%02d %02d:%02d:%02d %d\n", 31 | ttm.tm_year + 1900, ttm.tm_mon + 1, ttm.tm_mday, 32 | ttm.tm_hour, ttm.tm_min, ttm.tm_sec, ttm.tm_isdst); 33 | } 34 | -------------------------------------------------------------------------------- /2019-2020/05-opendir/1-snprintf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | void work(const char *dir) 11 | { 12 | DIR *d = opendir(dir); 13 | if (!d) { 14 | fprintf(stderr, "%s: %s\n", dir, strerror(errno)); 15 | return; 16 | } 17 | 18 | struct dirent *dd; 19 | errno = 0; 20 | while ((dd = readdir(d)) != NULL) { 21 | printf("%lu %s\n", dd->d_ino, dd->d_name); 22 | char buf[PATH_MAX]; 23 | 24 | int res = snprintf(buf, sizeof(buf), "%s/%s", dir, dd->d_name); 25 | if (res >= sizeof(buf)) { 26 | fprintf(stderr, "path too long\n"); 27 | continue; 28 | } 29 | 30 | struct stat sb; 31 | if (lstat(buf, &sb) < 0) { 32 | fprintf(stderr, "%s: %s\n", buf, strerror(errno)); 33 | } else { 34 | printf("dev, ino: %lx %lu\n", sb.st_dev, sb.st_ino); 35 | } 36 | } 37 | if (errno) { 38 | fprintf(stderr, "%s: read error: %s\n", dir, strerror(errno)); 39 | } 40 | 41 | closedir(d); 42 | } 43 | 44 | int main(int argc, char *argv[]) 45 | { 46 | work(argv[1]); 47 | } 48 | -------------------------------------------------------------------------------- /2017-2018/sem06/ex04-mmap3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /* 12 | Память отображается страницами (x86 - 4KiB), поэтому 13 | последняя страница будет доступна как полная, 14 | однако изменения на последней странице за текущим концом 15 | файла не будут записаны в файл. 16 | */ 17 | 18 | int main(int argc, char *argv[]) 19 | { 20 | int fd = open(argv[1], O_RDWR, 0); 21 | if (fd < 0) { 22 | fprintf(stderr, "open: %s\n", strerror(errno)); 23 | return 1; 24 | } 25 | struct stat stb; 26 | fstat(fd, &stb); 27 | unsigned char *ptr = mmap(NULL, stb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 28 | if (ptr == MAP_FAILED) { 29 | fprintf(stderr, "mmap: %s\n", strerror(errno)); 30 | return 1; 31 | } 32 | int count = 0; 33 | for (int i = 0; i < 4096; ++i) { 34 | if (ptr[i] >= '0' && ptr[i] <= '9') { 35 | ptr[i] = 'a'; 36 | ++count; 37 | } else if (!ptr[i]) { 38 | ptr[i] = 'x'; 39 | } 40 | } 41 | printf("%d\n", count); 42 | ftruncate(fd, 1024); // меняем размер файла 43 | close(fd); 44 | } 45 | -------------------------------------------------------------------------------- /2019-2020/08-dlopen/r2.c: -------------------------------------------------------------------------------- 1 | #include "r.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | struct UrandomRandomContext 11 | { 12 | struct RandomContext b; 13 | int rand_fd; 14 | }; 15 | 16 | static void rand_init(struct RandomContext *cntx) 17 | { 18 | struct UrandomRandomContext *rc = (struct UrandomRandomContext *) cntx; 19 | rc->rand_fd = open("/dev/urandom", O_RDONLY); 20 | assert(rc->rand_fd >= 0); 21 | } 22 | 23 | static int rand_n(struct RandomContext *cntx, int n) 24 | { 25 | struct UrandomRandomContext *rc = (struct UrandomRandomContext *) cntx; 26 | unsigned val; 27 | read(rc->rand_fd, &val, sizeof(val)); 28 | return val % n; 29 | } 30 | 31 | static void rand_destroy(struct RandomContext *cntx) 32 | { 33 | struct UrandomRandomContext *rc = (struct UrandomRandomContext *) cntx; 34 | close(rc->rand_fd); 35 | free(rc); 36 | } 37 | 38 | static const struct RandomOperations ops = 39 | { 40 | rand_init, 41 | rand_destroy, 42 | rand_n 43 | }; 44 | 45 | struct RandomContext * 46 | create_urandom_random() 47 | { 48 | struct UrandomRandomContext *rc = calloc(1, sizeof(*rc)); 49 | rc->b.ops = &ops; 50 | rc->rand_fd = -1; 51 | return &rc->b; 52 | } 53 | -------------------------------------------------------------------------------- /2017-2018/sem10/ex06-redir.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | // перенаправление стандартных потоков 12 | int main(int argc, char *argv[]) 13 | { 14 | int pid = fork(); 15 | if (!pid) { 16 | int fd = open("wc.txt", O_CREAT | O_TRUNC | O_WRONLY, 0600); 17 | // нестандартный системный вызов dup3 позволяет указать 18 | // флаг принудительного закрытие при exec 19 | dup3(fd, 1, FD_CLOEXEC); 20 | close(fd); 21 | fd = open("fork7.c", O_RDONLY, 0); 22 | dup2(fd, 0); 23 | close(fd); 24 | execlp("./inter", "wc", "-c", NULL); 25 | fprintf(stderr, "exec failed: %s\n", strerror(errno)); 26 | _exit(1); 27 | } 28 | 29 | int status; 30 | int p = waitpid(-1, &status, 0); 31 | if (p < 0) { 32 | fprintf(stderr, "error: %s\n", strerror(errno)); 33 | exit(1); 34 | } 35 | if (!p) { 36 | printf("no processes\n"); 37 | exit(1); 38 | } 39 | printf("%d\n", p); 40 | if (WIFEXITED(status)) { 41 | printf("%d\n", WEXITSTATUS(status)); 42 | } else if (WIFSIGNALED(status)) { 43 | printf("%d\n", WTERMSIG(status)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /2019-2020/05-opendir/2-asprintf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | void work(const char *dir) 12 | { 13 | DIR *d = opendir(dir); 14 | if (!d) { 15 | fprintf(stderr, "%s: %s\n", dir, strerror(errno)); 16 | return; 17 | } 18 | 19 | struct dirent *dd; 20 | errno = 0; 21 | while ((dd = readdir(d)) != NULL) { 22 | if (!strcmp(dd->d_name, ".") || !strcmp(dd->d_name, "..")) 23 | continue; 24 | printf("%lu %s\n", dd->d_ino, dd->d_name); 25 | 26 | char *buf = NULL; 27 | 28 | asprintf(&buf, "%s/%s", dir, dd->d_name); 29 | 30 | struct stat sb; 31 | if (lstat(buf, &sb) < 0) { 32 | fprintf(stderr, "%s: %s\n", buf, strerror(errno)); 33 | } else { 34 | printf("dev, ino: %lx %lu\n", sb.st_dev, sb.st_ino); 35 | if (S_ISDIR(sb.st_mode)) { 36 | work(buf); 37 | } 38 | } 39 | free(buf); 40 | } 41 | if (errno) { 42 | fprintf(stderr, "%s: read error: %s\n", dir, strerror(errno)); 43 | } 44 | 45 | closedir(d); 46 | } 47 | 48 | int main(int argc, char *argv[]) 49 | { 50 | work(argv[1]); 51 | } 52 | -------------------------------------------------------------------------------- /2019-2020/06-mmap/3-generate.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | typedef unsigned long long ValueType; 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | char *path = argv[1]; 16 | int count = strtol(argv[2], NULL, 10); 17 | 18 | int fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0600); 19 | if (fd < 0) { 20 | fprintf(stderr, "%s: %s\n", path, strerror(errno)); 21 | exit(1); 22 | } 23 | 24 | struct stat sb; 25 | fstat(fd, &sb); 26 | if (!S_ISREG(sb.st_mode)) { 27 | fprintf(stderr, "%s: not regular\n", path); 28 | exit(1); 29 | } 30 | 31 | off_t fsize = (off_t) count * (off_t) sizeof(ValueType); 32 | 33 | if (ftruncate(fd, fsize) < 0) { 34 | fprintf(stderr, "%s: %s\n", path, strerror(errno)); 35 | exit(1); 36 | } 37 | 38 | ValueType *ptr = mmap(NULL, fsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 39 | if (ptr == MAP_FAILED) { 40 | fprintf(stderr, "%s: %s\n", path, strerror(errno)); 41 | exit(1); 42 | } 43 | close(fd); 44 | 45 | for (int i = 1; i <= count; ++i) { 46 | ptr[count - i] = i; 47 | } 48 | 49 | munmap(ptr, fsize); 50 | } 51 | -------------------------------------------------------------------------------- /2018-2019/sem02/08-copy3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | enum { BUFSIZE = 4096 }; 11 | 12 | int main(int argc, char *argv[]) 13 | { 14 | const char *infile = argv[1]; 15 | const char *outfile = argv[2]; 16 | 17 | int rfd = open(infile, O_RDONLY, 0); 18 | if (rfd < 0) { 19 | fprintf(stderr, "error: %s\n", strerror(errno)); 20 | exit(1); 21 | } 22 | int wfd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0600); 23 | if (wfd < 0) { 24 | fprintf(stderr, "error: %s\n", strerror(errno)); 25 | exit(1); 26 | } 27 | 28 | char buf[BUFSIZE]; 29 | ssize_t r, w; 30 | while (1) { 31 | r = read(rfd, &buf, sizeof(buf)); 32 | if (r < 0) { 33 | fprintf(stderr, "error: %s\n", strerror(errno)); 34 | exit(1); 35 | } 36 | if (!r) break; 37 | char *p = buf; 38 | while (r > 0) { 39 | w = write(wfd, p, r); 40 | if (w < 0) { 41 | fprintf(stderr, "error: %s\n", strerror(errno)); 42 | exit(1); 43 | } 44 | r -= w; 45 | p += w; 46 | } 47 | } 48 | 49 | close(rfd); 50 | close(wfd); 51 | } 52 | -------------------------------------------------------------------------------- /2019-2020/13-signal-safe/05-ping-pong-async-safe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | volatile sig_atomic_t usr_flag; 7 | 8 | void handler(int s) 9 | { 10 | usr_flag = 1; 11 | } 12 | 13 | void work(int pid, int fd[2]) 14 | { 15 | sigset_t s2; 16 | sigemptyset(&s2); 17 | 18 | while (1) { 19 | while (!usr_flag) { 20 | sigsuspend(&s2); 21 | } 22 | usr_flag = 0; 23 | int x; 24 | read(fd[0], &x, sizeof(x)); 25 | printf("%d %d %d\n", pid, getpid(), x); fflush(stdout); 26 | ++x; 27 | write(fd[1], &x, sizeof(x)); 28 | kill(pid, SIGUSR1); 29 | } 30 | } 31 | 32 | int main() 33 | { 34 | int fd[2]; 35 | int pid; 36 | 37 | pipe(fd); 38 | 39 | sigset_t s1; 40 | sigemptyset(&s1); 41 | sigaddset(&s1, SIGUSR1); 42 | 43 | sigprocmask(SIG_BLOCK, &s1, NULL); 44 | 45 | pid = fork(); 46 | if (!pid) { 47 | sigaction(SIGUSR1, &(struct sigaction) { .sa_handler = handler }, NULL); 48 | work(getppid(), fd); 49 | 50 | 51 | _exit(0); 52 | } 53 | 54 | sigaction(SIGUSR1, &(struct sigaction) { .sa_handler = handler }, NULL); 55 | { 56 | int x = 1; 57 | write(fd[1], &x, sizeof(x)); 58 | kill(pid, SIGUSR1); 59 | } 60 | work(pid, fd); 61 | } 62 | -------------------------------------------------------------------------------- /2019-2020/09-fork/1-fork-wait.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main() 11 | { 12 | //char buf[256]; 13 | //setbuffer(stdout, buf, sizeof(buf)); 14 | pid_t pid = fork(); 15 | if (pid < 0) { 16 | fprintf(stderr, "fork: %s\n", strerror(errno)); 17 | exit(1); 18 | } else if (!pid) { 19 | printf("%d %d\n", getpid(), getppid()); 20 | char *p = (char*) (intptr_t) getpid(); 21 | printf("%c\n", *p); 22 | abort(); 23 | return 111; 24 | exit(42); 25 | } else { 26 | int status = 0; 27 | struct rusage ru; 28 | pid_t p = wait4(-1, &status, 0, &ru); 29 | if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { 30 | printf("ok %d %lld\n", p, ru.ru_utime.tv_sec * 100000LL + ru.ru_utime.tv_usec); 31 | } else if (WIFEXITED(status)) { 32 | printf("exit %d %d %lld\n", WEXITSTATUS(status), p, ru.ru_utime.tv_sec * 100000LL + ru.ru_utime.tv_usec); 33 | } else if (WIFSIGNALED(status)) { 34 | printf("signal %d %d %lld\n", WTERMSIG(status), p, ru.ru_utime.tv_sec * 100000LL + ru.ru_utime.tv_usec); 35 | } 36 | printf("%d %d\n", getpid(), pid); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /2019-2020/04-stat-time/1-stat.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int main(int argc, char *argv[]) 13 | { 14 | int retval = 0; 15 | for (int i = 1; i < argc; ++i) { 16 | struct stat sb; 17 | if (lstat(argv[i], &sb) < 0) { 18 | fprintf(stderr, "%s: %s\n", argv[i], strerror(errno)); 19 | retval = 1; 20 | } else { 21 | printf("%s: size: %lld\n", argv[i], (long long) sb.st_size); 22 | printf("%s: access: %03o\n", argv[i], sb.st_mode & 0777); 23 | printf("%s: blocks: %lld\n", argv[i], (long long) sb.st_blocks); 24 | if (S_ISLNK(sb.st_mode)) { 25 | char lnk[PATH_MAX]; 26 | ssize_t z = readlink(argv[i], lnk, sizeof(lnk)); 27 | printf("%s: symlink: %.*s\n", argv[i], (int) z, lnk); 28 | } 29 | struct tm ltm; 30 | localtime_r(&sb.st_mtime, <m); 31 | printf("%s: mtime: %d-%02d-%02d %02d:%02d:%02d %d %d %d\n", argv[i], 32 | ltm.tm_year + 1900, ltm.tm_mon + 1, ltm.tm_mday, 33 | ltm.tm_hour, ltm.tm_min, ltm.tm_sec, 34 | ltm.tm_wday, ltm.tm_yday, ltm.tm_isdst); 35 | } 36 | } 37 | return retval; 38 | } 39 | -------------------------------------------------------------------------------- /2017-2018/sem05/ex07-traverse-bad-1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /* 12 | * Рекурсивный обход дерева файловой системы. 13 | * Недостаток этого решения: количество одновременно используемых 14 | * файловых дескрипторов равно глубине вложенности каталогов. 15 | */ 16 | 17 | int traverse(const char *dir) 18 | { 19 | DIR *d = opendir(dir); 20 | if (!d) { 21 | fprintf(stderr, "error: %s\n", strerror(errno)); 22 | return -1; 23 | } 24 | struct dirent *dd; 25 | char path[PATH_MAX]; 26 | while ((dd = readdir(d))) { 27 | if (!strcmp(dd->d_name, ".") || !strcmp(dd->d_name, "..")) 28 | continue; 29 | int slen = snprintf(path, sizeof(path), "%s/%s", dir, dd->d_name); 30 | if (slen + 1 > sizeof(path)) { 31 | continue; 32 | } 33 | 34 | printf("%s %d %lu %s\n", path, slen, dd->d_ino, dd->d_name); 35 | struct stat stb; 36 | if (lstat(path, &stb) < 0) continue; 37 | printf("stat: %lu %llu\n", stb.st_ino, stb.st_dev); 38 | if (S_ISDIR(stb.st_mode)) { 39 | traverse(path); 40 | } 41 | } 42 | closedir(d); 43 | return 0; 44 | } 45 | 46 | int main(int argc, char *argv[]) 47 | { 48 | traverse(argv[1]); 49 | } 50 | -------------------------------------------------------------------------------- /2019-2020/06-mmap/2-count-digits-mmap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | char *path = argv[1]; 14 | 15 | int fd = open(path, O_RDONLY, 0); 16 | if (fd < 0) { 17 | fprintf(stderr, "%s: %s\n", path, strerror(errno)); 18 | exit(1); 19 | } 20 | struct stat sb; 21 | fstat(fd, &sb); 22 | if (!S_ISREG(sb.st_mode)) { 23 | fprintf(stderr, "%s: not regular\n", path); 24 | exit(1); 25 | } 26 | 27 | if (!sb.st_size) { 28 | return 0; 29 | } 30 | 31 | ssize_t size = sb.st_size; 32 | if (size != sb.st_size) { 33 | fprintf(stderr, "%s: file too big\n", path); 34 | exit(1); 35 | } 36 | 37 | unsigned char *ptr = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); 38 | if (ptr == MAP_FAILED) { 39 | fprintf(stderr, "%s: %s\n", path, strerror(errno)); 40 | exit(1); 41 | } 42 | close(fd); 43 | 44 | long long count[10] = {}; 45 | const unsigned char *eptr = ptr + size; 46 | for (const unsigned char *p = ptr; p < eptr; ++p) { 47 | unsigned char tmp = *p - '0'; 48 | if (tmp <= 9) { 49 | ++count[tmp]; 50 | } 51 | } 52 | 53 | munmap(ptr, size); 54 | for (int i = 0; i < 10; ++i) { 55 | printf("%lld\n", count[i]); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /2017-2018/sem12/ex06-pingpong2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // пинг-понг на сигналах здорового человека 7 | // нет, здоровый человек не использует сигналы! 8 | 9 | volatile int flag = 0; 10 | 11 | void handler() 12 | { 13 | flag = 1; 14 | } 15 | 16 | int main() 17 | { 18 | sigset_t s1, s2; 19 | sigemptyset(&s1); 20 | sigaddset(&s1, SIGUSR1); 21 | sigprocmask(SIG_BLOCK, &s1, &s2); 22 | sigaction(SIGUSR1, &(struct sigaction){ .sa_handler = handler }, NULL); 23 | int fd[2]; 24 | pipe(fd); 25 | int pid = fork(); 26 | if (!pid) { 27 | pid = getppid(); 28 | } else { 29 | int z = 1; 30 | write(fd[1], &z, sizeof(z)); 31 | kill(pid, SIGUSR1); 32 | } 33 | 34 | while (1) { 35 | /* 36 | // этот фрагмент кода содержит race condition 37 | // сигнал может придти в момент после первого sigprocmask 38 | // но до pause, тогда pause() заснет на неопределенное время 39 | // sigsuspend работает атомарно 40 | while (!flag) { 41 | sigprocmask(SIG_SETMASK, &s2, NULL); 42 | pause(); 43 | sigprocmask(SIG_BLOCK, &s1, NULL); 44 | } 45 | */ 46 | while (!flag) { 47 | // атомарная замена последовательности sigprocmask / pause / sigprocmask 48 | sigsuspend(&s2); 49 | } 50 | 51 | flag = 0; 52 | int x; 53 | read(fd[0], &x, sizeof(x)); 54 | printf("%d %d\n", getpid(), x); 55 | ++x; 56 | write(fd[1], &x, sizeof(x)); 57 | kill(pid, SIGUSR1); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /2017-2018/sem14/server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | enum { PORTNUM = 11111 }; 10 | 11 | int main(void) 12 | { 13 | int fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 14 | if (fd < 0) { 15 | fprintf(stderr, "socket: %s\n", strerror(errno)); 16 | return 1; 17 | } 18 | 19 | int value = 1; 20 | setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value)); 21 | setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &value, sizeof(value)); 22 | 23 | struct sockaddr_in s1; 24 | s1.sin_family = AF_INET; 25 | s1.sin_port = htons(PORTNUM); 26 | s1.sin_addr.s_addr = INADDR_ANY; 27 | int r = bind(fd, (struct sockaddr *) &s1, sizeof(s1)); 28 | if (r < 0) { 29 | fprintf(stderr, "bind: %s\n", strerror(errno)); 30 | return 1; 31 | } 32 | 33 | listen(fd, 5); 34 | 35 | while (1) { 36 | struct sockaddr_in s2; 37 | socklen_t slen = sizeof(s2); 38 | int afd = accept(fd, (struct sockaddr *) &s2, &slen); 39 | if (afd < 0) { 40 | fprintf(stderr, "accept: %s\n", strerror(errno)); 41 | return 1; 42 | } 43 | 44 | if (!fork()) { 45 | close(fd); 46 | char c; 47 | while (read(afd, &c, sizeof(c)) == 1) { 48 | write(1, &c, sizeof(c)); 49 | if (isdigit(c)) 50 | ++c; 51 | write(afd, &c, sizeof(c)); 52 | } 53 | _exit(0); 54 | } 55 | close(afd); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /2017-2018/sem13/ex06-msg.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | enum { KEY = 0xdeadbeef }; 12 | 13 | struct MyBuf 14 | { 15 | long mtype; 16 | int val; 17 | }; 18 | 19 | /* 20 | * "пинг-понг" между двумя процессами с помощью одной очереди сообщений SysV IPC 21 | * первый процесс ждет сообщения с типом 1, второй процесс - с типом 2 22 | */ 23 | int main() 24 | { 25 | int msgid = msgget(KEY, 0600 | IPC_CREAT | IPC_EXCL); 26 | if (msgid < 0) { 27 | fprintf(stderr, "error: %s\n", strerror(errno)); 28 | exit(1); 29 | } 30 | for (int i = 1; i <= 2; ++i) { 31 | if (!fork()) { 32 | while (1) { 33 | struct MyBuf rv; 34 | int r = msgrcv(msgid, &rv, sizeof(struct MyBuf) - sizeof(long), i, 0); 35 | if (r < 0) { 36 | fprintf(stderr, "error: %d: %s\n", i, strerror(errno)); 37 | exit(1); 38 | } 39 | printf("%d %d\n", i, rv.val); 40 | ++rv.val; 41 | rv.mtype = 3 - i; 42 | msgsnd(msgid, &rv, sizeof(struct MyBuf) - sizeof(long), 0); 43 | } 44 | _exit(0); 45 | } 46 | } 47 | 48 | msgsnd(msgid, &(struct MyBuf){ 1, 100 }, sizeof(struct MyBuf) - sizeof(long), 0); 49 | 50 | signal(SIGINT, SIG_IGN); 51 | 52 | int r; 53 | while ((r = wait(NULL)) > 0) { 54 | } 55 | fprintf(stderr, "wait: %s\n", strerror(errno)); 56 | msgctl(msgid, IPC_RMID, NULL); 57 | } 58 | -------------------------------------------------------------------------------- /2017-2018/sem12/ex04-sig4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void handler(int s) 8 | { 9 | // в обработчиках сигнала можно безопасно 10 | // использовать только async-signal safe функции 11 | static const char msg[] = "signal whatever\n"; 12 | // даже в случае async-signal safe функций 13 | // нужно сохранить и восстановить переменную errno 14 | int err = errno; 15 | write(2, msg, sizeof(msg) - 1); 16 | errno = err; 17 | } 18 | 19 | int main() 20 | { 21 | sigset_t s1, s2; 22 | 23 | // блокируем SIGINT, SIGKILL не может быть заблокирован 24 | sigemptyset(&s1); 25 | sigaddset(&s1, SIGINT); 26 | sigaddset(&s1, SIGKILL); 27 | sigprocmask(SIG_BLOCK, &s1, &s2); 28 | 29 | int a, b; 30 | struct sigaction safpe = 31 | { 32 | .sa_handler = handler, 33 | .sa_flags = SA_RESTART 34 | }; 35 | sigaction(SIGINT, &safpe, NULL); 36 | sigaction(SIGFPE, &(struct sigaction) { .sa_handler = handler, .sa_flags = SA_RESTART }, NULL); 37 | int r; 38 | restart: 39 | while ((r = scanf("%d%d", &a, &b)) == 2) { 40 | printf("%d\n", a / b); 41 | if (b == 1) { 42 | // восстанавливаем исходное множество блокируемых сигналов, 43 | // то есть разблокируем SIGINT 44 | sigprocmask(SIG_SETMASK, &s2, NULL); 45 | } else if (b == 2) { 46 | // снова блокируем SIGINT 47 | sigprocmask(SIG_BLOCK, &s1, NULL); 48 | } 49 | } 50 | if (r == EOF) { 51 | if (feof(stdin)) { 52 | printf("EOF!\n"); 53 | } else if (ferror(stdin)) { 54 | printf("%s\n", strerror(errno)); 55 | goto restart; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /2019-2020/14-ipc/01-ping-pong.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | void work(int semid, int64_t *ptr, int s1, int s2) 14 | { 15 | while (1) { 16 | struct sembuf b1[] = 17 | { 18 | { .sem_num = s1, -1, 0 }, 19 | }; 20 | int r = semop(semid, b1, sizeof(b1) / sizeof(b1[0])); 21 | if (r < 0) { 22 | fprintf(stderr, "semop: %s\n", strerror(errno)); 23 | exit(1); 24 | } 25 | 26 | printf("%d %lld\n", getpid(), (long long) *ptr); fflush(stdout); 27 | ++(*ptr); 28 | 29 | struct sembuf b2[] = 30 | { 31 | { .sem_num = s2, 1, 0 }, 32 | }; 33 | r = semop(semid, b2, sizeof(b2) / sizeof(b2[0])); 34 | if (r < 0) { 35 | fprintf(stderr, "semop: %s\n", strerror(errno)); 36 | exit(1); 37 | } 38 | } 39 | } 40 | 41 | int main(int argc, char *argv[]) 42 | { 43 | key_t key = strtol(argv[1], NULL, 16); 44 | 45 | int semid = semget(key, 3, 0600 | IPC_CREAT | IPC_EXCL); 46 | if (semid < 0) { 47 | fprintf(stderr, "semget: %s\n", strerror(errno)); 48 | exit(1); 49 | } 50 | 51 | semctl(semid, 1, SETVAL, 1); 52 | 53 | int64_t *ptr = mmap(NULL, sizeof(ptr), PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0); 54 | 55 | if (!fork()) { 56 | work(semid, ptr, 1, 2); 57 | _exit(0); 58 | } 59 | 60 | if (!fork()) { 61 | work(semid, ptr, 2, 1); 62 | _exit(0); 63 | } 64 | 65 | wait(NULL); 66 | wait(NULL); 67 | } 68 | -------------------------------------------------------------------------------- /2017-2018/sem05/ex08-traverse-bad-2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /* 12 | * Рекурсивный обход файловой системы с помощью telldir/seekdir 13 | * Недостаток: позиция, полученная с помощью telldir, может использоваться 14 | * для seekdir, пока каталог не был закрыт. Корректность пары telldir и seekdir 15 | * не гарантируется, если в промежутке каталог закрывается и открывается. 16 | * Поэтому эта программа не является правильной. 17 | */ 18 | 19 | int traverse(const char *dir) 20 | { 21 | DIR *d = opendir(dir); 22 | if (!d) { 23 | fprintf(stderr, "error: %s\n", strerror(errno)); 24 | return -1; 25 | } 26 | struct dirent *dd; 27 | char path[PATH_MAX]; 28 | while ((dd = readdir(d))) { 29 | if (!strcmp(dd->d_name, ".") || !strcmp(dd->d_name, "..")) 30 | continue; 31 | int slen = snprintf(path, sizeof(path), "%s/%s", dir, dd->d_name); 32 | if (slen + 1 > sizeof(path)) { 33 | continue; 34 | } 35 | 36 | printf("%s %d %lu %s\n", path, slen, dd->d_ino, dd->d_name); 37 | struct stat stb; 38 | if (lstat(path, &stb) < 0) continue; 39 | printf("stat: %lu %llu\n", stb.st_ino, stb.st_dev); 40 | if (S_ISDIR(stb.st_mode)) { 41 | // так, как ниже, делать нельзя 42 | long cur = telldir(d); 43 | closedir(d); 44 | traverse(path); 45 | d = opendir(dir); 46 | seekdir(d, cur); 47 | } 48 | } 49 | closedir(d); 50 | return 0; 51 | } 52 | 53 | int main(int argc, char *argv[]) 54 | { 55 | traverse(argv[1]); 56 | } 57 | -------------------------------------------------------------------------------- /2017-2018/sem05/ex09-traverse-1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /* 12 | * Корректный обход файловой системы с сохранением списка каталогов в векторе. 13 | */ 14 | 15 | struct strvec 16 | { 17 | char **v; 18 | size_t a, u; 19 | }; 20 | 21 | int traverse(const char *dir) 22 | { 23 | DIR *d = opendir(dir); 24 | if (!d) { 25 | fprintf(stderr, "error: %s\n", strerror(errno)); 26 | return -1; 27 | } 28 | struct dirent *dd; 29 | char path[PATH_MAX]; 30 | struct strvec vv = { malloc(16 * sizeof(vv.v[0])), 16, 0 }; 31 | 32 | while ((dd = readdir(d))) { 33 | if (!strcmp(dd->d_name, ".") || !strcmp(dd->d_name, "..")) 34 | continue; 35 | int slen = snprintf(path, sizeof(path), "%s/%s", dir, dd->d_name); 36 | if (slen + 1 > sizeof(path)) { 37 | continue; 38 | } 39 | 40 | printf("%s %d %lu %s\n", path, slen, dd->d_ino, dd->d_name); 41 | struct stat stb; 42 | if (lstat(path, &stb) < 0) continue; 43 | printf("stat: %lu %llu\n", stb.st_ino, stb.st_dev); 44 | if (S_ISDIR(stb.st_mode)) { 45 | if (vv.u == vv.a) { 46 | vv.v = realloc(vv.v, (vv.a *= 2) * sizeof(vv.v[0])); 47 | } 48 | vv.v[vv.u++] = strdup(dd->d_name); 49 | } 50 | } 51 | closedir(d); 52 | for (size_t i = 0; i < vv.u; ++i) { 53 | snprintf(path, sizeof(path), "%s/%s", dir, vv.v[i]); 54 | traverse(path); 55 | free(vv.v[i]); 56 | } 57 | free(vv.v); 58 | return 0; 59 | } 60 | 61 | int main(int argc, char *argv[]) 62 | { 63 | traverse(argv[1]); 64 | } 65 | -------------------------------------------------------------------------------- /2019-2020/shestimer/t_2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | struct RandomOps { 9 | void (*destruct)(struct Random*); 10 | unsigned (*next)(struct Random*); 11 | }; 12 | 13 | 14 | struct Random { 15 | int count; 16 | struct RandomOps *ops; 17 | }; 18 | 19 | struct RandomDev { 20 | struct Random r; 21 | int fd; 22 | }; 23 | 24 | struct RandomST { 25 | struct Random r; 26 | }; 27 | 28 | void destructDev(struct Random *w) { 29 | struct RandomDev *r = w; 30 | if (r->fd != -1) { 31 | close(r->fd); 32 | } 33 | free(r); 34 | } 35 | 36 | void destructST(struct Random *w) { 37 | struct RandomST *r = w; 38 | free(r); 39 | } 40 | 41 | unsigned next_r(struct Random* w) { 42 | unsigned x; 43 | read(r->fd, &x, sizeof(x)); 44 | return x; 45 | } 46 | 47 | unsigned next_empty(struct Random* w) { 48 | struct RandomST *r = w; 49 | return rand(); 50 | } 51 | 52 | struct RandomOps dev = { destructDev, next_r }; 53 | struct RandomOps st = { destructST, next_empty }; 54 | 55 | unsigned next(struct Random *r) { 56 | ++r->count; 57 | return r->ops->next(r); 58 | } 59 | 60 | struct Random *create_random(const char* name) { 61 | if (name && *name) { 62 | struct RandomDev *r; 63 | r = calloc(1, sizeof(struct RandomDev)); 64 | int fd = open(name, O_RDONLY); 65 | r->fd = fd; 66 | r->r.ops = &dev; 67 | return r; 68 | } else { 69 | struct RandomST* r; 70 | r = calloc(1, sizeof(struct RandomST)); 71 | r->r.ops = &st; 72 | return r; 73 | } 74 | } 75 | 76 | int main(int argc, char *argv[]) { 77 | srand(time(0)); 78 | const int maxt = 10; 79 | struct Random *r = create_random(argv[1]); 80 | for (int i = 0; i < maxt; ++i) { 81 | printf("%u\n", next(r) % 100); 82 | } 83 | r->ops->destruct(r); 84 | return 0; 85 | } 86 | -------------------------------------------------------------------------------- /2018-2019/sem07/01-count-digits.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | enum { DIGIT_COUNT = '9' - '0' + 1 }; 13 | 14 | void print_counters(const long long *counts, int size) 15 | { 16 | for (int i = 0; i < size; ++i) { 17 | printf("%d %lld\n", i, counts[i]); 18 | } 19 | } 20 | 21 | int main(int argc, char *argv[]) 22 | { 23 | long long counts[DIGIT_COUNT] = {}; 24 | int fd = open(argv[1], O_RDONLY, 0); 25 | if (fd < 0) { 26 | fprintf(stderr, "open failed: %s\n", strerror(errno)); 27 | return 1; 28 | } 29 | 30 | struct stat stb; 31 | fstat(fd, &stb); // в каких случаях fstat может вернуть ошибку? 32 | 33 | off_t size = stb.st_size; 34 | if (!size) { // поведение mmap при файле нулевого размера - UB 35 | // но файл нулевого размера - это нормально 36 | print_counters(counts, DIGIT_COUNT); 37 | close(fd); 38 | return 0; 39 | } 40 | 41 | if ((size_t) size != size) { 42 | // если размер файла непредставим в типе size_t 43 | fprintf(stderr, "file is too big\n"); 44 | close(fd); 45 | return 1; 46 | } 47 | 48 | void *vptr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); 49 | if (vptr == MAP_FAILED) { 50 | fprintf(stderr, "mmap failed: %s\n", strerror(errno)); 51 | close(fd); 52 | return 1; 53 | } 54 | 55 | // после mmap файловый дескриптор можно закрыть 56 | close(fd); 57 | 58 | const unsigned char *cptr = vptr; 59 | for (size_t i = 0; i < size; ++i) { 60 | unsigned val = *cptr++ - '0'; 61 | if (val < DIGIT_COUNT) { 62 | ++counts[val]; 63 | } 64 | } 65 | 66 | print_counters(counts, DIGIT_COUNT); 67 | munmap(vptr, size); 68 | } 69 | -------------------------------------------------------------------------------- /2017-2018/sem13/ex03-sem3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | enum { KEY = 0xdeadbeef }; 12 | enum { COUNT = 4 }; 13 | 14 | /* 15 | * пример на "инвертированную" семантику семафоров: 16 | * 0 - семафор открыт 17 | * 1 - семафор закрыт 18 | */ 19 | int main(void) 20 | { 21 | int semid = semget(KEY, 1, 0600 | IPC_CREAT | IPC_EXCL); 22 | if (semid < 0) { 23 | fprintf(stderr, "error: %s\n", strerror(errno)); 24 | exit(1); 25 | } 26 | 27 | for (int i = 1; i <= COUNT; ++i) { 28 | if (!fork()) { 29 | while (1) { 30 | // ждем значения 0 на семафоре и сразу же устанавливаем его в 1 31 | // обе операции будут выполняться атомарно в совокупности 32 | // для "инвертированной" семантики это - закрытие семафора 33 | struct sembuf ops[2] = 34 | { 35 | { .sem_num = 0, .sem_op = 0, .sem_flg = 0 }, 36 | { .sem_num = 0, .sem_op = 1, .sem_flg = 0 }, 37 | }; 38 | if (semop(semid, ops, 2) < 0) { 39 | fprintf(stderr, "error: %s\n", strerror(errno)); 40 | exit(1); 41 | } 42 | printf("%d in\n", i); fflush(stdout); 43 | usleep(100000); 44 | printf("%d out\n", i); fflush(stdout); 45 | // вычитаем 1 из значения семафора 46 | // для "инвертированной" семантики это - открытие семафора 47 | semop(semid, (struct sembuf[]) {{ .sem_num = 0, .sem_op = -1, .sem_flg = 0}}, 1); 48 | } 49 | } 50 | } 51 | 52 | // игнорирование SIGINT в отце будет иметь такой же эффект, как и 53 | // установка пустого обработчика (см. предыдущий пример) 54 | signal(SIGINT, SIG_IGN); 55 | 56 | int r; 57 | while ((r = wait(NULL)) > 0) {} 58 | fprintf(stderr, "wait: %s\n", strerror(errno)); 59 | 60 | semctl(semid, 0, IPC_RMID); 61 | } 62 | -------------------------------------------------------------------------------- /2017-2018/sem13/ex04-sem4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | enum { KEY = 0xdeadbeef }; 12 | enum { COUNT = 2 }; // число пингпонгующихся процессов 13 | enum { INIT_VAL = 132 }; // начальное значение, которым обмениваемся 14 | 15 | void handler(int s) 16 | { 17 | } 18 | 19 | /* 20 | * пример на "пинг-понг" без ограничения на максимальное значение 21 | * программа "зависнет" при достижении значения 32767 22 | * семафор [0] хранит пересылаемое значение 23 | * [1] открывается, когда приходит очередь первого сына 24 | * [2] открывается, когда приходит очередь второго сына 25 | */ 26 | int main(void) 27 | { 28 | int semid = semget(KEY, 3, 0600 | IPC_CREAT | IPC_EXCL); 29 | if (semid < 0) { 30 | fprintf(stderr, "error: %s\n", strerror(errno)); 31 | exit(1); 32 | } 33 | // устанавливаем начальное значение 34 | semctl(semid, 0, SETALL, (unsigned short[]) { INIT_VAL, 1, 0 }); 35 | 36 | for (int i = 1; i <= COUNT; ++i) { 37 | if (!fork()) { 38 | while (1) { 39 | // ждем своей очереди 40 | struct sembuf ops[1] = 41 | { 42 | { .sem_num = i, .sem_op = -1, .sem_flg = 0 }, 43 | }; 44 | if (semop(semid, ops, 1) < 0) { 45 | fprintf(stderr, "error: %s\n", strerror(errno)); 46 | exit(1); 47 | } 48 | printf("%d %d\n", i, semctl(semid, 0, GETVAL)); fflush(stdout); 49 | // передаем ход следующему и увеличиваем передаваемое значение 50 | semop(semid, (struct sembuf[]) {{ .sem_num = 3 - i, .sem_op = 1, .sem_flg = 0}, {.sem_num = 0, .sem_op = 1, .sem_flg = 0}}, 2); 51 | } 52 | } 53 | } 54 | 55 | sigaction(SIGINT, &(struct sigaction) { .sa_handler = handler, .sa_flags = SA_RESTART }, NULL); 56 | 57 | int r; 58 | while ((r = wait(NULL)) > 0) {} 59 | fprintf(stderr, "wait: %s\n", strerror(errno)); 60 | 61 | semctl(semid, 0, IPC_RMID); 62 | } 63 | -------------------------------------------------------------------------------- /2017-2018/sem13/ex05-sem5.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | enum { KEY = 0xdeadbeef }; 12 | enum { COUNT = 2 }; 13 | enum { MAX = 10000 }; // максимальное значение 14 | enum { INIT_VAL = 132 }; // начальное значение, которым обмениваемся 15 | 16 | void handler(int s) 17 | { 18 | } 19 | 20 | /* 21 | * Пример на пинг-понг с ограничением максимального значения 22 | */ 23 | int main() 24 | { 25 | int semid = semget(KEY, 3, 0600 | IPC_CREAT | IPC_EXCL); 26 | if (semid < 0) { 27 | fprintf(stderr, "error: %s\n", strerror(errno)); 28 | exit(1); 29 | } 30 | semctl(semid, 0, SETALL, (unsigned short[]) { INIT_VAL, 1, 0 }); 31 | 32 | for (int i = 1; i <= COUNT; ++i) { 33 | if (!fork()) { 34 | while (1) { 35 | struct sembuf ops[1] = 36 | { 37 | { .sem_num = i, .sem_op = -1, .sem_flg = 0 }, 38 | }; 39 | // когда массив семафоров будет удален, semop завершится с кодом ошибки EIDRM 40 | if (semop(semid, ops, 1) < 0) { 41 | fprintf(stderr, "error: %s\n", strerror(errno)); 42 | exit(1); 43 | } 44 | int val = semctl(semid, 0, GETVAL); 45 | printf("%d %d\n", i, val); fflush(stdout); 46 | if (val == MAX) { 47 | // при достижении максимального значения удаляем массив семафоров и завершаем работу 48 | semctl(semid, 0, IPC_RMID); 49 | exit(0); 50 | } 51 | semop(semid, (struct sembuf[]) {{ .sem_num = 3 - i, .sem_op = 1, .sem_flg = 0}, {.sem_num = 0, .sem_op = 1, .sem_flg = 0}}, 2); 52 | } 53 | } 54 | } 55 | 56 | sigaction(SIGINT, &(struct sigaction) { .sa_handler = handler, .sa_flags = SA_RESTART }, NULL); 57 | 58 | int r; 59 | while ((r = wait(NULL)) > 0) {} 60 | fprintf(stderr, "wait: %s\n", strerror(errno)); 61 | 62 | // массив семафоров уже будет удален одним из сыновей, 63 | // эта операция, строго говоря, излишняя 64 | semctl(semid, 0, IPC_RMID); 65 | } 66 | -------------------------------------------------------------------------------- /old/oop/random/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | typedef struct Random Random; 10 | 11 | typedef struct RandomOps { 12 | int (*next)(Random *); 13 | Random *(*destroy)(Random *); 14 | } RandomOps; 15 | 16 | 17 | 18 | typedef struct Random { 19 | int count; 20 | RandomOps *ops; 21 | } Random; 22 | 23 | 24 | 25 | typedef struct RandomPseudo { 26 | Random base; 27 | } RandomPseudo; 28 | 29 | typedef struct RandomFile { 30 | Random base; 31 | int fd; 32 | } RandomFile; 33 | 34 | int nextPseudo(Random *r_) { 35 | r_->count++; 36 | return rand(); 37 | } 38 | 39 | int nextFile(Random *r_) { 40 | r_->count++; 41 | RandomFile *r = (RandomFile *)r_; 42 | int res; 43 | read(r->fd, &res, sizeof(res)); 44 | return res; 45 | } 46 | 47 | RandomFile *destroyFile(RandomFile *r) { 48 | close(r->fd); 49 | free(r); 50 | return NULL; 51 | } 52 | 53 | RandomPseudo *destroyPseudo(RandomPseudo *r) { 54 | free(r); 55 | return NULL; 56 | } 57 | 58 | RandomOps randomFileOps = {nextFile, destroyFile}; 59 | RandomOps randomPseudoOps = {nextPseudo, destroyPseudo}; 60 | 61 | RandomFile *initFile(const char *filename) { 62 | RandomFile *res = malloc(sizeof(*res)); 63 | res->base.ops = &randomFileOps; 64 | res->base.count = 0; 65 | res->fd = open(filename, O_RDONLY); 66 | return res; 67 | } 68 | 69 | RandomPseudo *initPseudo(int t) { 70 | RandomPseudo *res = malloc(sizeof(*res)); 71 | res->base.ops = &randomPseudoOps; 72 | res->base.count = 0; 73 | srand(t); 74 | return res; 75 | } 76 | 77 | int f(Random *r) { 78 | r->ops->next(r); 79 | } 80 | 81 | int main(void) { 82 | Random *r1 = (Random *)initPseudo(123); 83 | Random *r2 = (Random *)initFile("/dev/random"); 84 | printf("%d\n", r1->ops->next(r1)); 85 | printf("%d\n", r2->ops->next(r2)); 86 | f(r1); f(r2); 87 | r1 = r1->ops->destroy(r1); 88 | printf("\t%d\n", r2->count); 89 | void *dl_handle = dlopen("./lib.so",RTLD_NOW); 90 | perror(dlerror()); 91 | int (*next)(Random *) = dlsym(dl_handle, "next42"); 92 | perror(dlerror()); 93 | printf("%d\n", next(NULL)); 94 | dlclose(dl_handle); 95 | } 96 | -------------------------------------------------------------------------------- /2017-2018/sem13/ex02-sem2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | enum { KEY = 0xdeadbeef }; 12 | enum { COUNT = 10 }; 13 | enum { INIT = 6 }; 14 | 15 | // пустой обработчик сигнала SIGINT 16 | void handler(int s) 17 | { 18 | } 19 | 20 | int main() 21 | { 22 | // создаем массив из одного семафора 23 | int semid = semget(KEY, 1, 0600 | IPC_CREAT | IPC_EXCL); 24 | if (semid < 0) { 25 | fprintf(stderr, "error: %s\n", strerror(errno)); 26 | exit(1); 27 | } 28 | // устанавливаем начальное значение семафора 29 | semctl(semid, 0, SETVAL, INIT); 30 | 31 | for (int i = 1; i <= COUNT; ++i) { 32 | if (!fork()) { 33 | while (1) { 34 | // отдельно объявляем массив операций с семафором 35 | struct sembuf ops[1] = 36 | { 37 | { .sem_num = 0, .sem_op = -i, .sem_flg = 0 }, 38 | }; 39 | // операция down(i) над семафором 0 40 | if (semop(semid, ops, 1) < 0) { 41 | fprintf(stderr, "error: %s\n", strerror(errno)); 42 | exit(1); 43 | } 44 | printf("%d in\n", i); fflush(stdout); 45 | usleep(100000); 46 | printf("%d out\n", i); fflush(stdout); 47 | // массив операций объявлен как параметр в вызове semop 48 | // операция up(i) над семафором 0 49 | semop(semid, (struct sembuf[]) {{ .sem_num = 0, .sem_op = i, .sem_flg = 0}}, 1); 50 | } 51 | } 52 | } 53 | 54 | // в отце устанавливаем обработчик SIGINT с семантикой перезапускаемых системных вызовов 55 | // обработчик SIGINT нужен, чтобы отец не завершился из-за сигнала SIGINT 56 | sigaction(SIGINT, &(struct sigaction) { .sa_handler = handler, .sa_flags = SA_RESTART }, NULL); 57 | 58 | // когда созданные отцом процессы получат SIGINT, они будут завершаться 59 | // системный вызов wait() будет возвращать PID этих процессов, 60 | // пока не останется ни одного процесса, после чего wait() вернет -1, и цикл закончится 61 | int r; 62 | while ((r = wait(NULL)) > 0) {} 63 | fprintf(stderr, "wait: %s\n", strerror(errno)); 64 | 65 | // удаляем массив семафоров 66 | semctl(semid, 0, IPC_RMID); 67 | } 68 | -------------------------------------------------------------------------------- /old/philosophers/philosophers.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int semid, shmid; 12 | 13 | void inthnd(int s) 14 | { 15 | semctl(semid, 0, IPC_RMID); 16 | shmctl(shmid, IPC_RMID, NULL); 17 | exit(0); 18 | } 19 | 20 | int main(int argc, char *argv[]) 21 | { 22 | key_t semk = strtol(argv[1], NULL, 10); 23 | int n = strtol(argv[2], NULL, 10); 24 | int seed = strtol(argv[3], NULL, 10); 25 | 26 | signal(SIGINT, inthnd); 27 | 28 | semid = semget(semk, n, 0600 | IPC_CREAT); 29 | if (semid < 0) { 30 | perror(""); 31 | exit(1); 32 | } 33 | 34 | shmid = shmget(semk, n + 1, 0600 | IPC_CREAT); 35 | char *mem = shmat(shmid, NULL, 0); 36 | 37 | short initval[n]; 38 | //memset(initval, 0, sizeof(initval)); 39 | for (int i = 0; i < n; ++i) { 40 | initval[i] = 1; 41 | mem[i] = '?'; 42 | } 43 | semctl(semid, 0, SETALL, initval); 44 | mem[n] = 0; 45 | 46 | 47 | for (int i = 0; i < n; ++i) { 48 | if (!fork()) { 49 | srand(seed + i); 50 | while (1) { 51 | // waiting 52 | mem[i] = 'S'; 53 | int wt = (int) (rand() / (RAND_MAX + 1.0) * 10) + 1; 54 | usleep(100000 * wt); 55 | 56 | int f1 = i; 57 | int f2 = (i + 1) % n; 58 | /* 59 | if (f1 > f2) { 60 | int t = f1; f1 = f2; f2 = t; 61 | } 62 | */ 63 | 64 | mem[i] = 'W'; 65 | semop(semid, (struct sembuf[2]) {{ .sem_num = f1, .sem_op = -1, .sem_flg = SEM_UNDO }, { .sem_num = f2, .sem_op = -1, .sem_flg = SEM_UNDO }}, 2); 66 | 67 | // eating 68 | mem[i] = 'E'; 69 | wt = wt / 2 + 1; 70 | usleep(100000 * wt); 71 | 72 | mem[i] = 'R'; 73 | //usleep(100000); 74 | semop(semid, (struct sembuf[1]) {{ .sem_num = f2, .sem_op = 1, .sem_flg = SEM_UNDO }}, 1); 75 | semop(semid, (struct sembuf[1]) {{ .sem_num = f1, .sem_op = 1, .sem_flg = SEM_UNDO }}, 1); 76 | } 77 | exit(0); 78 | } 79 | } 80 | 81 | while (1) { 82 | usleep(100000); 83 | printf("State: %s\r", mem);fflush(stdout); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /2019-2020/14-ipc/02-philosophers.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | volatile sig_atomic_t int_flag = 0; 15 | void handler(int s) 16 | { 17 | int_flag = 1; 18 | } 19 | 20 | void work(int semid, int index, char *status, int count) 21 | { 22 | while (1) { 23 | int f1 = index; 24 | int f2 = (index + 1) % count; 25 | 26 | status[index] = 'W'; 27 | struct sembuf b1[] = 28 | { 29 | { .sem_num = f1, -1, SEM_UNDO }, 30 | { .sem_num = f2, -1, SEM_UNDO }, 31 | }; 32 | int r = semop(semid, b1, sizeof(b1) / sizeof(b1[0])); 33 | if (r < 0) { 34 | if (errno == EIDRM) { 35 | fprintf(stderr, "exiting\n"); 36 | } 37 | break; 38 | } 39 | status[index] = 'E'; 40 | usleep(100000); 41 | struct sembuf b2[] = 42 | { 43 | { .sem_num = f1, 1, SEM_UNDO }, 44 | { .sem_num = f2, 1, SEM_UNDO }, 45 | }; 46 | r = semop(semid, b2, sizeof(b2) / sizeof(b2[0])); 47 | if (r < 0) { 48 | if (errno == EIDRM) { 49 | fprintf(stderr, "exiting\n"); 50 | } 51 | break; 52 | } 53 | status[index] = 'S'; 54 | usleep(100000); 55 | } 56 | } 57 | 58 | int main(int argc, char *argv[]) 59 | { 60 | int count = strtol(argv[1], NULL, 10); 61 | key_t key = strtol(argv[2], NULL, 16); 62 | 63 | char *status = mmap(NULL, count + 1, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); 64 | memset(status, '-', count); 65 | status[count] = 0; 66 | 67 | int semid = semget(key, count, IPC_CREAT | IPC_EXCL | 0600); 68 | if (semid < 0) { 69 | fprintf(stderr, "semget: %s\n", strerror(errno)); 70 | exit(1); 71 | } 72 | 73 | short *ptr = calloc(count, sizeof(ptr[0])); 74 | for (int i = 0; i < count; ++i) ptr[i] = 1; 75 | semctl(semid, 0, SETALL, ptr); 76 | 77 | for (int i = 0; i < count; ++i) { 78 | if (!fork()) { 79 | work(semid, i, status, count); 80 | _exit(0); 81 | } 82 | } 83 | 84 | sigaction(SIGINT, &(struct sigaction) { .sa_handler = handler }, NULL); 85 | sigaction(SIGTERM, &(struct sigaction) { .sa_handler = handler }, NULL); 86 | 87 | while (!int_flag) { 88 | printf("%s\r", status); fflush(stdout); 89 | usleep(100000); 90 | } 91 | 92 | semctl(semid, 0, IPC_RMID); 93 | 94 | while (wait(NULL) > 0) {} 95 | } 96 | -------------------------------------------------------------------------------- /old/fork-exec/exec.c: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "param.h" 3 | #include "memlayout.h" 4 | #include "mmu.h" 5 | #include "proc.h" 6 | #include "defs.h" 7 | #include "x86.h" 8 | #include "elf.h" 9 | 10 | int 11 | exec(char *path, char **argv) 12 | { 13 | char *s, *last; 14 | int i, off; 15 | uint argc, sz, sp, ustack[3+MAXARG+1]; 16 | struct elfhdr elf; 17 | struct inode *ip; 18 | struct proghdr ph; 19 | pde_t *pgdir, *oldpgdir; 20 | 21 | begin_op(); 22 | 23 | if((ip = namei(path)) == 0){ 24 | end_op(); 25 | return -1; 26 | } 27 | ilock(ip); 28 | pgdir = 0; 29 | 30 | // Check ELF header 31 | if(readi(ip, (char*)&elf, 0, sizeof(elf)) < sizeof(elf)) 32 | goto bad; 33 | if(elf.magic != ELF_MAGIC) 34 | goto bad; 35 | 36 | if((pgdir = setupkvm()) == 0) 37 | goto bad; 38 | 39 | // Load program into memory. 40 | sz = 0; 41 | for(i=0, off=elf.phoff; i= MAXARG) 72 | goto bad; 73 | sp = (sp - (strlen(argv[argc]) + 1)) & ~3; 74 | if(copyout(pgdir, sp, argv[argc], strlen(argv[argc]) + 1) < 0) 75 | goto bad; 76 | ustack[3+argc] = sp; 77 | } 78 | ustack[3+argc] = 0; 79 | 80 | ustack[0] = 0xffffffff; // fake return PC 81 | ustack[1] = argc; 82 | ustack[2] = sp - (argc+1)*4; // argv pointer 83 | 84 | sp -= (3+argc+1) * 4; 85 | if(copyout(pgdir, sp, ustack, (3+argc+1)*4) < 0) 86 | goto bad; 87 | 88 | // Save program name for debugging. 89 | for(last=s=path; *s; s++) 90 | if(*s == '/') 91 | last = s+1; 92 | safestrcpy(proc->name, last, sizeof(proc->name)); 93 | 94 | // Commit to the user image. 95 | oldpgdir = proc->pgdir; 96 | proc->pgdir = pgdir; 97 | proc->sz = sz; 98 | proc->tf->eip = elf.entry; // main 99 | proc->tf->esp = sp; 100 | switchuvm(proc); 101 | freevm(oldpgdir); 102 | return 0; 103 | 104 | bad: 105 | if(pgdir) 106 | freevm(pgdir); 107 | if(ip){ 108 | iunlockput(ip); 109 | end_op(); 110 | } 111 | return -1; 112 | } 113 | -------------------------------------------------------------------------------- /old/fork-exec/proc.h: -------------------------------------------------------------------------------- 1 | // Per-CPU state 2 | struct cpu { 3 | uchar apicid; // Local APIC ID 4 | struct context *scheduler; // swtch() here to enter scheduler 5 | struct taskstate ts; // Used by x86 to find stack for interrupt 6 | struct segdesc gdt[NSEGS]; // x86 global descriptor table 7 | volatile uint started; // Has the CPU started? 8 | int ncli; // Depth of pushcli nesting. 9 | int intena; // Were interrupts enabled before pushcli? 10 | 11 | // Cpu-local storage variables; see below 12 | struct cpu *cpu; 13 | struct proc *proc; // The currently-running process. 14 | }; 15 | 16 | extern struct cpu cpus[NCPU]; 17 | extern int ncpu; 18 | 19 | // Per-CPU variables, holding pointers to the 20 | // current cpu and to the current process. 21 | // The asm suffix tells gcc to use "%gs:0" to refer to cpu 22 | // and "%gs:4" to refer to proc. seginit sets up the 23 | // %gs segment register so that %gs refers to the memory 24 | // holding those two variables in the local cpu's struct cpu. 25 | // This is similar to how thread-local variables are implemented 26 | // in thread libraries such as Linux pthreads. 27 | extern struct cpu *cpu asm("%gs:0"); // &cpus[cpunum()] 28 | extern struct proc *proc asm("%gs:4"); // cpus[cpunum()].proc 29 | 30 | //PAGEBREAK: 17 31 | // Saved registers for kernel context switches. 32 | // Don't need to save all the segment registers (%cs, etc), 33 | // because they are constant across kernel contexts. 34 | // Don't need to save %eax, %ecx, %edx, because the 35 | // x86 convention is that the caller has saved them. 36 | // Contexts are stored at the bottom of the stack they 37 | // describe; the stack pointer is the address of the context. 38 | // The layout of the context matches the layout of the stack in swtch.S 39 | // at the "Switch stacks" comment. Switch doesn't save eip explicitly, 40 | // but it is on the stack and allocproc() manipulates it. 41 | struct context { 42 | uint edi; 43 | uint esi; 44 | uint ebx; 45 | uint ebp; 46 | uint eip; 47 | }; 48 | 49 | enum procstate { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE }; 50 | 51 | // Per-process state 52 | struct proc { 53 | uint sz; // Size of process memory (bytes) 54 | pde_t* pgdir; // Page table 55 | char *kstack; // Bottom of kernel stack for this process 56 | enum procstate state; // Process state 57 | int pid; // Process ID 58 | struct proc *parent; // Parent process 59 | struct trapframe *tf; // Trap frame for current syscall 60 | struct context *context; // swtch() here to run process 61 | void *chan; // If non-zero, sleeping on chan 62 | int killed; // If non-zero, have been killed 63 | struct file *ofile[NOFILE]; // Open files 64 | struct inode *cwd; // Current directory 65 | char name[16]; // Process name (debugging) 66 | }; 67 | 68 | // Process memory is laid out contiguously, low addresses first: 69 | // text 70 | // original data and bss 71 | // fixed-size stack 72 | // expandable heap 73 | -------------------------------------------------------------------------------- /2017-2018/sem15/epoll-server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | enum { PORTNUM = 11111 }; 14 | 15 | int main(void) 16 | { 17 | sigset_t ss; 18 | sigemptyset(&ss); 19 | sigaddset(&ss, SIGINT); 20 | sigprocmask(SIG_BLOCK, &ss, NULL); 21 | 22 | int sfd = signalfd(-1, &ss, 0); 23 | 24 | int fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 25 | if (fd < 0) { 26 | fprintf(stderr, "socket: %s\n", strerror(errno)); 27 | return 1; 28 | } 29 | 30 | int value = 1; 31 | setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value)); 32 | 33 | struct sockaddr_in s1; 34 | s1.sin_family = AF_INET; 35 | s1.sin_port = htons(PORTNUM); 36 | s1.sin_addr.s_addr = INADDR_ANY; 37 | int r = bind(fd, (struct sockaddr *) &s1, sizeof(s1)); 38 | if (r < 0) { 39 | fprintf(stderr, "bind: %s\n", strerror(errno)); 40 | return 1; 41 | } 42 | 43 | listen(fd, 5); 44 | 45 | fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); 46 | 47 | int efd = epoll_create1(0); 48 | 49 | epoll_ctl(efd, EPOLL_CTL_ADD, fd, &(struct epoll_event) { .events = EPOLLIN, .data.fd = fd }); 50 | epoll_ctl(efd, EPOLL_CTL_ADD, sfd, &(struct epoll_event) { .events = EPOLLIN, .data.fd = sfd }); 51 | 52 | while (1) { 53 | enum { EVENT_SIZE = 5 }; 54 | struct epoll_event events[EVENT_SIZE]; 55 | int r = epoll_pwait(efd, events, EVENT_SIZE, 1000, NULL); 56 | if (r < 0) { 57 | fprintf(stderr, "epoll: %s\n", strerror(errno)); 58 | return 1; 59 | } 60 | if (!r) { 61 | printf("timeout!\n"); 62 | continue; 63 | } 64 | 65 | for (int i = 0; i < r; ++i) { 66 | struct epoll_event *pe = &events[i]; 67 | 68 | if (pe->events == EPOLLIN && pe->data.fd == fd) { 69 | 70 | struct sockaddr_in s2; 71 | socklen_t slen = sizeof(s2); 72 | int afd = accept(fd, (struct sockaddr *) &s2, &slen); 73 | if (afd < 0) { 74 | fprintf(stderr, "accept: %s\n", strerror(errno)); 75 | return 1; 76 | } 77 | fcntl(afd, F_SETFL, fcntl(afd, F_GETFL) | O_NONBLOCK); 78 | epoll_ctl(efd, EPOLL_CTL_ADD, afd, &(struct epoll_event) { .events = EPOLLIN, .data.fd = afd }); 79 | } else if (pe->events == EPOLLIN && pe->data.fd == sfd) { 80 | struct signalfd_siginfo si; 81 | read(sfd, &si, sizeof(si)); 82 | printf("%d\n", si.ssi_signo); 83 | 84 | for (int f = 3; f < 250; ++f) { 85 | if (f != sfd && f != fd && f != efd) { 86 | if (fcntl(f, F_GETFL, 0) >= 0) { 87 | epoll_ctl(efd, EPOLL_CTL_DEL, f, NULL); 88 | close(f); 89 | } 90 | } 91 | } 92 | 93 | 94 | } else if (pe->events == EPOLLIN) { 95 | int afd = pe->data.fd; 96 | char c; 97 | r = read(afd, &c, sizeof(c)); 98 | if (r < 0) { 99 | fprintf(stderr, "read: %s\n", strerror(errno)); 100 | return 1; 101 | } else if (!r) { 102 | epoll_ctl(efd, EPOLL_CTL_DEL, afd, NULL); 103 | close(afd); 104 | } else { 105 | write(1, &c, sizeof(c)); 106 | if (isdigit(c)) 107 | ++c; 108 | write(afd, &c, sizeof(c)); 109 | } 110 | } 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /GithubIntegration.md: -------------------------------------------------------------------------------- 1 | # Интеграция ejudge и github 2 | 3 | В данном документе описывается, как подключить репозиторий на github к задаче в ejudge. 4 | При успешном подключении любой push в репозиторий приводит к автоматическому 5 | скачиванию новой версии программы в ejudge и её проверке на тестах. Результат 6 | проверки будет доступен в интерфейсе ejudge. 7 | 8 | Предполагается, что аккаунт на github уже создан, ключи для работы через git ssh настроены. 9 | 10 | ## Как это работает 11 | 12 | 1. Пользователь выполняет push в репозиторий. 13 | 2. github выполняет HTTP POST запрос по некоторому адресу, уведомляя стороннюю систему, в нашем случае ejudge, о том, что состояние репозитория изменилось. Этот механизм называется webhooks. 14 | 3. ejudge обрабатывает запрос, клонируя репозиторий на github в систему. Для доступа к репозиторию на чтение используется ssh-ключ, так называемый deploy key, причем у ejudge должна быть его приватная часть, а у github - публичная часть. 15 | 4. Из склонированного репозитория формируется архив, который отправляется на проверку от имени пользователя, настроившего интеграцию, и далее задача обрабатывается стандартным для ejudge способом. 16 | 17 | Если вам всё или многое понятно, то вы можете сразу приступить к настройке интеграции. 18 | 19 | ## Создание deploy key 20 | 21 | Для того чтобы ejudge мог клонировать репозиторий из github необходим ssh-ключ, причем 22 | у ejudge должна быть его приватная часть, а в github нужно поместить публичную часть. 23 | Не нужно отдавать в ejudge приватную часть какого-либо существующего ключа, а лучше всего сгенерировать новый ключ специально для ejudge. 24 | 25 | Если у вас уже есть сгенерированный ранее deploy key для ejudge, нет необходимости 26 | генерировать новый ключ для каждой задачи, можно использовать уже существующий. 27 | 28 | ``` 29 | ssh-keygen -t ed25519 -f ejudge-deploy 30 | ``` 31 | 32 | Поле "passphrase" оставьте пустым (два раза нажмите "Enter"). В результате должны 33 | быть созданы два файла: `ejudge-deploy` - это приватная часть ключа, и `ejudge-deploy.pub` - это публичная часть ключа. 34 | 35 | ## Добавление deploy key в проекте github 36 | 37 | На странице проекта выберите вкладку "Settings". 38 | 39 | ![settings](images/settings.png) 40 | 41 | Затем на странице настроек слева выберите "Deploy keys". 42 | 43 | ![menu_deploy_keys](images/menu_deploy_keys.png) 44 | 45 | На странице "Deploy keys" нажмите на "Add deploy key". 46 | 47 | ![add_deploy_key_btn](images/add_deploy_key_btn.png) 48 | 49 | Далее в поле ввода "Key" скопируйте содержимое файла `ejudge-deploy.pub` и нажмите "Add key". 50 | 51 | ![deploy_keys_form](images/deploy_keys_form.png) 52 | 53 | Возможно, после нажатия кнопки, github запросит подтверждение операции с помощью ввода OTP-фактора. 54 | 55 | Один и тот же deploy key можно использовать для разных интеграций, например, для сдачи разных задач. 56 | 57 | ## Добавление webhook в проект в github 58 | 59 | Теперь в ejudge перейдите на страницу с условием задачи и нажмите кнопку "Setup Version Control System Integration" под условием задачи. 60 | 61 | На вопрос о создании новой интеграции отвечайте "Ok". 62 | 63 | ![ejudge_new_integration](images/ejudge_new_integration.png) 64 | 65 | Сейчас нас интересуют поля "Git webhook" и "Git webhook token". 66 | 67 | ![ejudge_properties_1](images/ejudge_properties_1.png) 68 | 69 | Далее вернитесь на страницу github на страницу "Settings", и в меню слева выберите "Webhooks". 70 | 71 | ![github_webhooks_menu](images/github_webhooks_menu.png) 72 | 73 | Нажмите "Add webhook" 74 | 75 | ![github_add_webhook](images/github_add_webhook.png) 76 | 77 | В поле "Payload URL" скопируйте текст из поля "Git webhook" формы в ejudge. 78 | 79 | В поле "Content type" выберите "application/json". 80 | 81 | В поле "Secret" скопируйте текст из поля "Git webhook token". 82 | 83 | Остальное оставьте без изменений и нажмите кнопку "Add webhook". 84 | 85 | ![github_add_webhook_form](images/github_add_webhook_form.png) 86 | 87 | Чтобы убедиться, что webhook успешно добавился, из списка webhook 88 | откройте его по ссылке, затем откройте вкладку "Recent deliveries" 89 | и на ней перейдите по ссылке на "ping"-запросе. На вкладке "Response" 90 | вы должны увидеть в Body `{"ok":true}`. 91 | 92 | ![github_ping_ok](images/webhook_ping_ok.png) 93 | 94 | ## Настройка интеграции в ejudge 95 | 96 | Теперь вернитесь на страницу с условием задачи в ejudge, на которой должна 97 | быть открыта форма "Integration properties". 98 | 99 | В поле "Git type" выберите "github". 100 | 101 | В поле "Git SSH URL" скопируйте URL, по которому репозиторий клонируется из github. 102 | 103 | В поле "Language выберите нужный язык программирования". 104 | 105 | Поля "Repo subdirectory" и "Branch specification" оставьте пустыми. 106 | 107 | В поле "SSH private key (deploy key)" скопируйте содержимое файла `ejudge-deploy`. 108 | 109 | Нажмите "Ok". 110 | 111 | ![ejudge_integration_2](images/ejudge_integration_2.png) 112 | 113 | ## Успех! 114 | 115 | Если вы все сделали правильно, операция push в репозиторий git 116 | приведет к тому, что последняя версия кода будет скачана, скомпилирована 117 | и протестирована. 118 | 119 | При просмотре исходного кода в ejudge вы не увидите непосредственно код, 120 | но специальным образом подготовленный текстовый файл, который содержит 121 | заархивированный каталог с кодом. 122 | -------------------------------------------------------------------------------- /2020-2021/sem04/README.md: -------------------------------------------------------------------------------- 1 | # Файлы и каталоги 2 | 3 | ## Функции stat, fstat и lstat 4 | 5 | ```c 6 | #include 7 | #include 8 | 9 | int stat(const char *restrict pathname, struct stat *restrict buf); 10 | int fstat(int filedes, struct stat *buf); 11 | int lstat(const char *restrict pathname, struct stat *restrict buf); 12 | ``` 13 | Системный вызов `stat` возвращает структуру с информацией о файле, указанном в аргументе `pathname`. 14 | Функция `fstat` возвращает информацию об открытом файле, который определяется дескриптором `filedes`. 15 | Функция `lstat` похожа на функцию `stat`, но когда ей передается имя символической ссылки, она возвращает сведения о самой символической ссылке, а не о файле, на который она ссылается. 16 | Второй аргумент, `buf`, является указателем на структуру, которую функция будет заполнять информацией. Определение структуры может отличаться для разных реализаций, но основная ее часть выглядит следующим образом: 17 | 18 | ```c 19 | struct stat { 20 | mode_t st_mode; /* тип файла и режим (права доступа) */ 21 | ino_t st_ino; /* номер индексного узла */ 22 | dev_t st_dev; /* номер устройства (файловой системы) */ 23 | dev_t st_rdev; /* номер устройства для специальных файлов */ 24 | nlink_t st_nlink; /* количество ссылок */ 25 | uid_t st_uid; /* идентификатор пользователя владельца */ 26 | gid_t st_gid; /* идентификатор группы владельца */ 27 | off_t st_size; /* размер в байтах, для регулярных файлов */ 28 | time_t st_atime; /* время последнего обращения к файлу */ 29 | time_t st_mtime; /* время последнего изменения файла */ 30 | time_t st_ctime; /* время последнего изменения флагов состояния файла */ 31 | }; 32 | ``` 33 | ## Типы файлов 34 | 35 | 1. Регулярный файл – наиболее распространенный тип файлов, который хранит данные в том или ином виде. 36 | Ядро UNIX не делает различий между текстовыми и двоичными файлами. 37 | Любая интерпретация содержимого файла полностью возлагается на прикладную программу, 38 | обрабатывающую файл. 39 | 2. Файл каталога. Файлы этого типа содержат имена других файлов и ссылки на информацию о них. Любой процесс, обладающий правом на чтение 40 | каталога, может проверить его содержимое, но только ядро обладает правом на запись в файл каталога. Чтобы внести изменения в каталог, про 41 | цессы должны пользоваться функциями работы с каталогами. 42 | 3. Специальный файл блочного устройства. Этот тип файлов обеспечивает буферизованный ввод вывод для таких устройств, как дисковые устрой 43 | ства с фиксированным размером блока. 44 | 4. Специальный файл символьного устройства. Этот тип файлов обеспечивает небуферизованный ввод вывод для устройств с переменным размером 45 | блока. Все устройства в системе являются либо специальными файлами блочных устройств, либо специальными файлами символьных устройств. 46 | 5. FIFO, или именованный канал. Этот тип файлов используется для организации обмена информацией между процессами. 47 | 6. Сокет. Этот тип файлов используется для организации обмена между процессами. 48 | 7. Символическая ссылка. Файлы этого типа представляют собой ссылки на другие файлы. 49 | 50 | Тип файла хранится в поле st_mode структуры stat. Определить тип файла можно с помощью макроопределений, приведенных ниже 51 | (Макросы для определения типа файла из ``````) 52 | 53 | * `S_ISREG(st_mode)` Регулярный файл 54 | * `S_ISDIR(st_mode)` Каталог 55 | * `S_ISCHR(st_mode)` Специальный файл символьного устройства 56 | * `S_ISBLK(st_mode)` Специальный файл блочного устройства 57 | * `S_ISFIFO(st_mode)` Канал (именованный или неименованный) 58 | * `S_ISLNK(st_mode)` Символическая ссылка 59 | * `S_ISSOCK(st_mode)` Сокет 60 | 61 | ## Системный вызов access 62 | 63 | ```c 64 | #include 65 | 66 | int access(const char *pathname, int mode); 67 | ``` 68 | 69 | Проверяет, какие операции с файлом по данному пути процесс может выполнить. Симлинки разыменовываются. Что можно проверить (флаги в mode, можно комбинировать через побитовое или): 70 | 71 | * `F_OK` - просто факт существования 72 | * `R_OK` - файл можно читать 73 | * `W_OK` - в файл можно писать 74 | * `X_OK` - файл можно исполнить 75 | 76 | В случае успеха (всё, что спрашивалось, можно) вызов возвращает 0. В противном случае (в том числе, в случае ошибки) вызов возвращает -1 и выставляет errno в соответствии с причиной отказа. 77 | Функция `access` проверяет права доступа к файлу в соответствии с реальным, а не 78 | эффективным идентификатором пользователя, с правами которого 79 | выполняется процесс. Поэтому привилегированный процесс, то есть процесс, 80 | у которого эффективный идентификатор пользователя отличается от реального 81 | идентификатора пользователя, может использовать этот системный вызов 82 | для проверки возможности доступа к указанному файлу с точки 83 | зрения пользователя, запустившего данный процесс. 84 | 85 | # Привилегии процесса (традиционная модель) 86 | 87 | Идентификатор пользователя - это беззнаковое число, использующееся 88 | в ядре операционной системы для идентификации пользователя. 89 | Идентификатор пользователя используется для 90 | авторизации пользователя на выполнение различных действий. 91 | Отображение строковых идентификаторов в числовые 92 | можно найти в файле `/etc/passwrd`. Но кроме того 93 | это отображение может предоставляться различными системными сетевыми 94 | сервисами, подобными openldap. 95 | 96 | Идентификатор группы - это беззнаковое число, использующееся 97 | для идентификации группы, к которой относится пользователь. 98 | 99 | Пользователь с идентификатором 0 считается суперпользователем. 100 | Он может выполнить любую операцию, за исключением запуска файла без 101 | установленного бита `x`. 102 | 103 | Реальный идентификатор пользователя процесса - идентификатор 104 | пользователя, который запустил данный процесс. 105 | Эффективный идентификатор пользователя процесса - идентификатор 106 | пользователя, который используется при проверке прав доступа 107 | на выполненение различных операций. 108 | 109 | В обычной ситуации (непривилегированный процесс) реальный идентификатор 110 | пользователя совпадает с эффективным идентификатором пользователя. 111 | Это значит, что права исполняемого файла определяются правами 112 | пользователя, который его запустил. 113 | -------------------------------------------------------------------------------- /2021-2022/sem04/README.md: -------------------------------------------------------------------------------- 1 | # Файлы и каталоги 2 | 3 | ## Функции stat, fstat и lstat 4 | 5 | ```c 6 | #include 7 | #include 8 | 9 | int stat(const char *restrict pathname, struct stat *restrict buf); 10 | int fstat(int filedes, struct stat *buf); 11 | int lstat(const char *restrict pathname, struct stat *restrict buf); 12 | ``` 13 | Системный вызов `stat` возвращает структуру с информацией о файле, указанном в аргументе `pathname`. 14 | Функция `fstat` возвращает информацию об открытом файле, который определяется дескриптором `filedes`. 15 | Функция `lstat` похожа на функцию `stat`, но когда ей передается имя символической ссылки, она возвращает сведения о самой символической ссылке, а не о файле, на который она ссылается. 16 | Второй аргумент, `buf`, является указателем на структуру, которую функция будет заполнять информацией. Определение структуры может отличаться для разных реализаций, но основная ее часть выглядит следующим образом: 17 | 18 | ```c 19 | struct stat { 20 | mode_t st_mode; /* тип файла и режим (права доступа) */ 21 | ino_t st_ino; /* номер индексного узла */ 22 | dev_t st_dev; /* номер устройства (файловой системы) */ 23 | dev_t st_rdev; /* номер устройства для специальных файлов */ 24 | nlink_t st_nlink; /* количество ссылок */ 25 | uid_t st_uid; /* идентификатор пользователя владельца */ 26 | gid_t st_gid; /* идентификатор группы владельца */ 27 | off_t st_size; /* размер в байтах, для регулярных файлов */ 28 | time_t st_atime; /* время последнего обращения к файлу */ 29 | time_t st_mtime; /* время последнего изменения файла */ 30 | time_t st_ctime; /* время последнего изменения флагов состояния файла */ 31 | }; 32 | ``` 33 | ## Типы файлов 34 | 35 | 1. Регулярный файл – наиболее распространенный тип файлов, который хранит данные в том или ином виде. 36 | Ядро UNIX не делает различий между текстовыми и двоичными файлами. 37 | Любая интерпретация содержимого файла полностью возлагается на прикладную программу, 38 | обрабатывающую файл. 39 | 2. Файл каталога. Файлы этого типа содержат имена других файлов и ссылки на информацию о них. Любой процесс, обладающий правом на чтение 40 | каталога, может проверить его содержимое, но только ядро обладает правом на запись в файл каталога. Чтобы внести изменения в каталог, про 41 | цессы должны пользоваться функциями работы с каталогами. 42 | 3. Специальный файл блочного устройства. Этот тип файлов обеспечивает буферизованный ввод вывод для таких устройств, как дисковые устрой 43 | ства с фиксированным размером блока. 44 | 4. Специальный файл символьного устройства. Этот тип файлов обеспечивает небуферизованный ввод вывод для устройств с переменным размером 45 | блока. Все устройства в системе являются либо специальными файлами блочных устройств, либо специальными файлами символьных устройств. 46 | 5. FIFO, или именованный канал. Этот тип файлов используется для организации обмена информацией между процессами. 47 | 6. Сокет. Этот тип файлов используется для организации обмена между процессами. 48 | 7. Символическая ссылка. Файлы этого типа представляют собой ссылки на другие файлы. 49 | 50 | Тип файла хранится в поле st_mode структуры stat. Определить тип файла можно с помощью макроопределений, приведенных ниже 51 | (Макросы для определения типа файла из ``````) 52 | 53 | * `S_ISREG(st_mode)` Регулярный файл 54 | * `S_ISDIR(st_mode)` Каталог 55 | * `S_ISCHR(st_mode)` Специальный файл символьного устройства 56 | * `S_ISBLK(st_mode)` Специальный файл блочного устройства 57 | * `S_ISFIFO(st_mode)` Канал (именованный или неименованный) 58 | * `S_ISLNK(st_mode)` Символическая ссылка 59 | * `S_ISSOCK(st_mode)` Сокет 60 | 61 | ## Системный вызов access 62 | 63 | ```c 64 | #include 65 | 66 | int access(const char *pathname, int mode); 67 | ``` 68 | 69 | Проверяет, какие операции с файлом по данному пути процесс может выполнить. Симлинки разыменовываются. Что можно проверить (флаги в mode, можно комбинировать через побитовое или): 70 | 71 | * `F_OK` - просто факт существования 72 | * `R_OK` - файл можно читать 73 | * `W_OK` - в файл можно писать 74 | * `X_OK` - файл можно исполнить 75 | 76 | В случае успеха (всё, что спрашивалось, можно) вызов возвращает 0. В противном случае (в том числе, в случае ошибки) вызов возвращает -1 и выставляет errno в соответствии с причиной отказа. 77 | Функция `access` проверяет права доступа к файлу в соответствии с реальным, а не 78 | эффективным идентификатором пользователя, с правами которого 79 | выполняется процесс. Поэтому привилегированный процесс, то есть процесс, 80 | у которого эффективный идентификатор пользователя отличается от реального 81 | идентификатора пользователя, может использовать этот системный вызов 82 | для проверки возможности доступа к указанному файлу с точки 83 | зрения пользователя, запустившего данный процесс. 84 | 85 | # Привилегии процесса (традиционная модель) 86 | 87 | Идентификатор пользователя - это беззнаковое число, использующееся 88 | в ядре операционной системы для идентификации пользователя. 89 | Идентификатор пользователя используется для 90 | авторизации пользователя на выполнение различных действий. 91 | Отображение строковых идентификаторов в числовые 92 | можно найти в файле `/etc/passwrd`. Но кроме того 93 | это отображение может предоставляться различными системными сетевыми 94 | сервисами, подобными openldap. 95 | 96 | Идентификатор группы - это беззнаковое число, использующееся 97 | для идентификации группы, к которой относится пользователь. 98 | 99 | Пользователь с идентификатором 0 считается суперпользователем. 100 | Он может выполнить любую операцию, за исключением запуска файла без 101 | установленного бита `x`. 102 | 103 | Реальный идентификатор пользователя процесса - идентификатор 104 | пользователя, который запустил данный процесс. 105 | Эффективный идентификатор пользователя процесса - идентификатор 106 | пользователя, который используется при проверке прав доступа 107 | на выполненение различных операций. 108 | 109 | В обычной ситуации (непривилегированный процесс) реальный идентификатор 110 | пользователя совпадает с эффективным идентификатором пользователя. 111 | Это значит, что права исполняемого файла определяются правами 112 | пользователя, который его запустил. 113 | -------------------------------------------------------------------------------- /2017-2018/sem03/README.md: -------------------------------------------------------------------------------- 1 | # Файлы, часть 1 2 | 3 | Набор заголовочных файлов для использования POSIX API работы с файлами: 4 | ```c 5 | #include 6 | #include 7 | #include 8 | #include 9 | ``` 10 | 11 | ## Дескрипторы 12 | 13 | Все открытые файлы представлены в ядре файловыми дескрипторами. Файловый дескриптор – это неотрицательное целое число. Когда процесс открывает существующий файл или создает новый, ядро возвращает ему файловый дескриптор. Чтобы выполнить записьв файл или чтение из него, нужно 14 | передать функции read или write его файловый дескриптор, полученный 15 | в результате вызова функции open или creat. 16 | В соответствии с принятыми соглашениями командные оболочки UNIX ассоциируют файловый дескриптор 0 со стандартным устройством ввода процесса, 1 – со стандартным устройством вывода и 2 – со стандартным устройством 17 | вывода сообщений об ошибках. Это соглашение используется командными 18 | оболочками и большинством приложений, но не является особенностью ядра UNIX. Тем не менее многие приложения не смогли бы работать, если это соглашение было бы нарушено. 19 | 20 | ## Функция Open 21 | 22 | ```c 23 | #include 24 | int open(const char *pathname, int oflag, ... /* mode_t mode*/); 25 | ``` 26 | 27 | Возвращает дескриптор файла в случае успеха, –1 в случае ошибки. 28 | Третий аргумент обозначен многоточием (...), таким способом стандарт ISO 29 | C указывает, что количество остальных аргументов и их типы могут варьироваться. В этой функции третий аргумент используется только при создании нового файла. Этот аргумент приведен в прототипе функции как комментарий. Аргумент pathname представляет имя файла, который будет открыт или создан. Эта функция может принимать большое количество параметров, которые определяются аргументом oflag. Значение этого аргумента формируется 30 | объединением по ИЛИ (OR) одной или более констант, определяемых в заголовочном файле fcntl.h и перечисленных ниже: 31 | 32 | O_RDONLY Файл открывается только на чтение. 33 | 34 | O_WRONLY Файл открывается только на запись. 35 | 36 | O_RDWR Файл открывается как для чтения, так и для записи. 37 | 38 | В большинстве реализаций для сохранениясовместимости с устаревшим программным обеспечением константа O_RDONLY определяется значением 0, O_WRONLY – 1, O_RDWR – 2. 39 | Должна быть указана одна и только одна из этих трех констант. 40 | Cписок констант, присутствие которых в аргументе oflag необязательно: 41 | 42 | O_APPEND Запись производится в конец файла. 43 | 44 | O_CREAT Если файл не существует, он будет создан. Этот флаг требует наличия третьего аргумента функции open(mode), который определяет значения битов прав доступа к создаваемому файлу. 45 | 46 | O_EXCL Приводит к появлению ошибки, если файл уже существует и задан флаг O_CREAT. При такой комбинации флагов атомарно выполняется проверка существования файла и его создание, если файл не существует. 47 | 48 | O_TRUNC Если файл существует и успешно открывается на запись либо на чтение и запись, то его размер усекается до нуля. 49 | 50 | O_NOCTTY Если аргумент pathname ссылается на файл терминального устройства, то это устройство не назначается управляющим терминалом вызывающего процесса. 51 | 52 | O_NONBLOCK Если аргумент pathname ссылается на именованный канал (FIFO), специальный блочный файл или специальный символьный файл, этот флаг задает неблокирующий режим открытия файла и последующих операций 53 | ввода вывода. 54 | 55 | O_DSYNC Каждый вызов функции writeожидает завершения физической операции ввода вывода, но не ожидает, пока будут обновлены атрибуты файла, если они не влияют на возможность чтения только что записанных данных. 56 | 57 | O_RSYNC Каждый вызов функции readприостанавливается до тех пор, пока не будут закончены ожидающие завершения операции записи в ту же самую часть файла. 58 | 59 | O_SYNC Каждый вызов функции writeожидает завершения физической операции ввода вывода, включая операцию обновления атрибутов файла 60 | 61 | ## Функция Сreat 62 | 63 | ```c 64 | #include 65 | int creat(const char *pathname, mode_t mode); 66 | ``` 67 | 68 | В случае успеха возвращает файловый дескриптор, доступный только для записи, –1 в случае ошибки 69 | Эта функция эквивалентна open(pathname, O_WRONLY | O_CREAT | O_TRUNC, mode); 70 | 71 | У функции creatесть один недостаток: файл открывается только на запись. До появления обновленной версии функции open, чтобы создать временный файл, записать в него некоторые данные и потом прочитать их, требовалось вызывать creat, close и затем open. Гораздо удобнее использовать в таких случаях функцию openследующим образом: 72 | open(pathname, O_RDWR | O_CREAT | O_TRUNC, mode); 73 | 74 | ## Функция Close 75 | 76 | ```c 77 | #include 78 | int close(int filedes); 79 | ``` 80 | 81 | Возвращает 0 в случае успеха, –1 в случае ошибки. Закрытие файла также приводит к снятию любых блокировок, которые мог ли быть наложены процессом. При завершении процесса все открытые им файлы автоматически закрываются ядром. 82 | 83 | ## Функция Lseek 84 | 85 | С любым открытым файлом связано такое понятие, как текущая позиция файла. Как правило, это неотрицательное целое число, которым выражается количеством байт от начала файла. Обычно операции чтения и записи начинают выполняться с текущей позиции файла и увеличивают ее значение на количество байт, которое было прочитано или записано. По умолчанию при открытии файла текущая позиция инициализируется числом 0, если не был установлен флаг O_APPEND. Явное изменение текущей позиции файла выполняется с помощью функции lseek. 86 | 87 | ```c 88 | #include 89 | off_t lseek(int filedes, off_t offset, int whence); 90 | ``` 91 | 92 | Возвращает новую текущую позицию файла в случае успеха, –1 в случае ошибки 93 | 94 | Интерпретация аргумента offsetзависит от значения аргумента whence. 95 | 96 | Если аргумент whenceимеет значение SEEK_SET, то offset интерпретируется как смещение от начала файла. 97 | 98 | Если аргумент whenceимеет значение SEEK_CUR, то offset интерпретируется как смещение от текущей позиции файла. В этом случае offset может принимать как положительные, так и отрицательные значения. 99 | 100 | Если аргумент whence имеет значение SEEK_END, то offset интерпретируется как смещение от конца файла. В этом случае offset может принимать как положительные, так и отрицательные значения. 101 | 102 | Поскольку в случае успеха функция lseek возвращает новую текущую позицию файла, можно задать в аргументе offset значение 0, чтобы узнать текущую позицию: 103 | 104 | ```c 105 | off_t currpos; 106 | currpos = lseek(fd, 0, SEEK_CUR); 107 | ``` 108 | 109 | Можно воспользоваться этим приемом, чтобы определить, имеется ли возможность свободного перемещения текущей позиции файла. Если файловый дескриптор относится к именованному или неименованному каналу или к сокету, функция lseek вернет значение –1 и запишет в переменную errno код ошибки ESPIPE. 110 | 111 | Текущая позиция файла может превышать его текущий размер. В этом случае следующая операция записи увеличит размер файла. Это вполне допустимо и может рассматриваться как создание «пустоты» в файле. Байты, которые фактически не были записаны, считываются как нули. «Пустота» в файле не обязательно должна занимать место на диске. В некоторых файловых системах в случае переноса текущей позиции за пределы файла на диске могут быть выделены новые блоки для данных, но это совершенно необязательно. 112 | 113 | ## Функция Read 114 | 115 | ```c 116 | #include 117 | ssize_t read(int filedes, void *buf, size_t nbytes); 118 | ``` 119 | 120 | Возвращает количество прочитанных байт, 0 – если достигнут конец файла, –1 в случае ошибки. 121 | 122 | Существует несколько ситуаций, когда количество фактически прочитанных байт меньше, чем было запрошено: 123 | 124 | При чтении из обычного файла, когда конец файла встретился до того, как было прочитано требуемое количество байт. Например, если до конца файла осталось 30 байт, а запрошено было 100 байт, то функция read вернет число 30. При следующем вызове она вернет 0 (конец файла). 125 | 126 | При чтении с терминального устройства. Обычно за одно обращение читается одна строка 127 | 128 | При чтении данных из сети. Промежуточная буферизация в сети может стать причиной того, что будет получено меньшее количество байт, чем было запрошено. 129 | 130 | При чтении из именованных или неименованных каналов. Если в канале содержится меньше байт, чем было запрошено, функция read вернет только то, что ей будет доступно. 131 | 132 | При чтении c устройства, ориентированного на доступ к отдельным записям. Примером такого устройства является накопитель на магнитной ленте, который может вернуть только одну запись за одно обращение. 133 | 134 | При прерывании операции чтения сигналом в тот момент, когда часть данных уже была прочитана. 135 | 136 | Операция чтения начинается с текущей позиции файла. В случае успеха текущая позиция будет увеличена на число фактически прочитанных байт. 137 | 138 | ## Функция Write 139 | 140 | ```c 141 | include 142 | ssize_t write(int filedes, const void *buf, size_t nbytes); 143 | ``` 144 | 145 | Возвращает количество записанных байт в случае успеха, –1 в случае ошибки 146 | -------------------------------------------------------------------------------- /old/fork-exec/proc.c: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "defs.h" 3 | #include "param.h" 4 | #include "memlayout.h" 5 | #include "mmu.h" 6 | #include "x86.h" 7 | #include "proc.h" 8 | #include "spinlock.h" 9 | 10 | struct { 11 | struct spinlock lock; 12 | struct proc proc[NPROC]; 13 | } ptable; 14 | 15 | static struct proc *initproc; 16 | 17 | int nextpid = 1; 18 | extern void forkret(void); 19 | extern void trapret(void); 20 | 21 | static void wakeup1(void *chan); 22 | 23 | void 24 | pinit(void) 25 | { 26 | initlock(&ptable.lock, "ptable"); 27 | } 28 | 29 | //PAGEBREAK: 32 30 | // Look in the process table for an UNUSED proc. 31 | // If found, change state to EMBRYO and initialize 32 | // state required to run in the kernel. 33 | // Otherwise return 0. 34 | static struct proc* 35 | allocproc(void) 36 | { 37 | struct proc *p; 38 | char *sp; 39 | 40 | acquire(&ptable.lock); 41 | 42 | for(p = ptable.proc; p < &ptable.proc[NPROC]; p++) 43 | if(p->state == UNUSED) 44 | goto found; 45 | 46 | release(&ptable.lock); 47 | return 0; 48 | 49 | found: 50 | p->state = EMBRYO; 51 | p->pid = nextpid++; 52 | 53 | release(&ptable.lock); 54 | 55 | // Allocate kernel stack. 56 | if((p->kstack = kalloc()) == 0){ 57 | p->state = UNUSED; 58 | return 0; 59 | } 60 | sp = p->kstack + KSTACKSIZE; 61 | 62 | // Leave room for trap frame. 63 | sp -= sizeof *p->tf; 64 | p->tf = (struct trapframe*)sp; 65 | 66 | // Set up new context to start executing at forkret, 67 | // which returns to trapret. 68 | sp -= 4; 69 | *(uint*)sp = (uint)trapret; 70 | 71 | sp -= sizeof *p->context; 72 | p->context = (struct context*)sp; 73 | memset(p->context, 0, sizeof *p->context); 74 | p->context->eip = (uint)forkret; 75 | 76 | return p; 77 | } 78 | 79 | //PAGEBREAK: 32 80 | // Set up first user process. 81 | void 82 | userinit(void) 83 | { 84 | struct proc *p; 85 | extern char _binary_initcode_start[], _binary_initcode_size[]; 86 | 87 | p = allocproc(); 88 | 89 | initproc = p; 90 | if((p->pgdir = setupkvm()) == 0) 91 | panic("userinit: out of memory?"); 92 | inituvm(p->pgdir, _binary_initcode_start, (int)_binary_initcode_size); 93 | p->sz = PGSIZE; 94 | memset(p->tf, 0, sizeof(*p->tf)); 95 | p->tf->cs = (SEG_UCODE << 3) | DPL_USER; 96 | p->tf->ds = (SEG_UDATA << 3) | DPL_USER; 97 | p->tf->es = p->tf->ds; 98 | p->tf->ss = p->tf->ds; 99 | p->tf->eflags = FL_IF; 100 | p->tf->esp = PGSIZE; 101 | p->tf->eip = 0; // beginning of initcode.S 102 | 103 | safestrcpy(p->name, "initcode", sizeof(p->name)); 104 | p->cwd = namei("/"); 105 | 106 | // this assignment to p->state lets other cores 107 | // run this process. the acquire forces the above 108 | // writes to be visible, and the lock is also needed 109 | // because the assignment might not be atomic. 110 | acquire(&ptable.lock); 111 | 112 | p->state = RUNNABLE; 113 | 114 | release(&ptable.lock); 115 | } 116 | 117 | // Grow current process's memory by n bytes. 118 | // Return 0 on success, -1 on failure. 119 | int 120 | growproc(int n) 121 | { 122 | uint sz; 123 | 124 | sz = proc->sz; 125 | if(n > 0){ 126 | if((sz = allocuvm(proc->pgdir, sz, sz + n)) == 0) 127 | return -1; 128 | } else if(n < 0){ 129 | if((sz = deallocuvm(proc->pgdir, sz, sz + n)) == 0) 130 | return -1; 131 | } 132 | proc->sz = sz; 133 | switchuvm(proc); 134 | return 0; 135 | } 136 | 137 | // Create a new process copying p as the parent. 138 | // Sets up stack to return as if from system call. 139 | // Caller must set state of returned proc to RUNNABLE. 140 | int 141 | fork(void) 142 | { 143 | int i, pid; 144 | struct proc *np; 145 | 146 | // Allocate process. 147 | if((np = allocproc()) == 0){ 148 | return -1; 149 | } 150 | 151 | // Copy process state from p. 152 | if((np->pgdir = copyuvm(proc->pgdir, proc->sz)) == 0){ 153 | kfree(np->kstack); 154 | np->kstack = 0; 155 | np->state = UNUSED; 156 | return -1; 157 | } 158 | np->sz = proc->sz; 159 | np->parent = proc; 160 | *np->tf = *proc->tf; 161 | 162 | // Clear %eax so that fork returns 0 in the child. 163 | np->tf->eax = 0; 164 | 165 | for(i = 0; i < NOFILE; i++) 166 | if(proc->ofile[i]) 167 | np->ofile[i] = filedup(proc->ofile[i]); 168 | np->cwd = idup(proc->cwd); 169 | 170 | safestrcpy(np->name, proc->name, sizeof(proc->name)); 171 | 172 | pid = np->pid; 173 | 174 | acquire(&ptable.lock); 175 | 176 | np->state = RUNNABLE; 177 | 178 | release(&ptable.lock); 179 | 180 | return pid; 181 | } 182 | 183 | // Exit the current process. Does not return. 184 | // An exited process remains in the zombie state 185 | // until its parent calls wait() to find out it exited. 186 | void 187 | exit(void) 188 | { 189 | struct proc *p; 190 | int fd; 191 | 192 | if(proc == initproc) 193 | panic("init exiting"); 194 | 195 | // Close all open files. 196 | for(fd = 0; fd < NOFILE; fd++){ 197 | if(proc->ofile[fd]){ 198 | fileclose(proc->ofile[fd]); 199 | proc->ofile[fd] = 0; 200 | } 201 | } 202 | 203 | begin_op(); 204 | iput(proc->cwd); 205 | end_op(); 206 | proc->cwd = 0; 207 | 208 | acquire(&ptable.lock); 209 | 210 | // Parent might be sleeping in wait(). 211 | wakeup1(proc->parent); 212 | 213 | // Pass abandoned children to init. 214 | for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ 215 | if(p->parent == proc){ 216 | p->parent = initproc; 217 | if(p->state == ZOMBIE) 218 | wakeup1(initproc); 219 | } 220 | } 221 | 222 | // Jump into the scheduler, never to return. 223 | proc->state = ZOMBIE; 224 | sched(); 225 | panic("zombie exit"); 226 | } 227 | 228 | // Wait for a child process to exit and return its pid. 229 | // Return -1 if this process has no children. 230 | int 231 | wait(void) 232 | { 233 | struct proc *p; 234 | int havekids, pid; 235 | 236 | acquire(&ptable.lock); 237 | for(;;){ 238 | // Scan through table looking for exited children. 239 | havekids = 0; 240 | for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ 241 | if(p->parent != proc) 242 | continue; 243 | havekids = 1; 244 | if(p->state == ZOMBIE){ 245 | // Found one. 246 | pid = p->pid; 247 | kfree(p->kstack); 248 | p->kstack = 0; 249 | freevm(p->pgdir); 250 | p->pid = 0; 251 | p->parent = 0; 252 | p->name[0] = 0; 253 | p->killed = 0; 254 | p->state = UNUSED; 255 | release(&ptable.lock); 256 | return pid; 257 | } 258 | } 259 | 260 | // No point waiting if we don't have any children. 261 | if(!havekids || proc->killed){ 262 | release(&ptable.lock); 263 | return -1; 264 | } 265 | 266 | // Wait for children to exit. (See wakeup1 call in proc_exit.) 267 | sleep(proc, &ptable.lock); //DOC: wait-sleep 268 | } 269 | } 270 | 271 | //PAGEBREAK: 42 272 | // Per-CPU process scheduler. 273 | // Each CPU calls scheduler() after setting itself up. 274 | // Scheduler never returns. It loops, doing: 275 | // - choose a process to run 276 | // - swtch to start running that process 277 | // - eventually that process transfers control 278 | // via swtch back to the scheduler. 279 | void 280 | scheduler(void) 281 | { 282 | struct proc *p; 283 | 284 | for(;;){ 285 | // Enable interrupts on this processor. 286 | sti(); 287 | 288 | // Loop over process table looking for process to run. 289 | acquire(&ptable.lock); 290 | for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ 291 | if(p->state != RUNNABLE) 292 | continue; 293 | 294 | // Switch to chosen process. It is the process's job 295 | // to release ptable.lock and then reacquire it 296 | // before jumping back to us. 297 | proc = p; 298 | switchuvm(p); 299 | p->state = RUNNING; 300 | swtch(&cpu->scheduler, p->context); 301 | switchkvm(); 302 | 303 | // Process is done running for now. 304 | // It should have changed its p->state before coming back. 305 | proc = 0; 306 | } 307 | release(&ptable.lock); 308 | 309 | } 310 | } 311 | 312 | // Enter scheduler. Must hold only ptable.lock 313 | // and have changed proc->state. Saves and restores 314 | // intena because intena is a property of this 315 | // kernel thread, not this CPU. It should 316 | // be proc->intena and proc->ncli, but that would 317 | // break in the few places where a lock is held but 318 | // there's no process. 319 | void 320 | sched(void) 321 | { 322 | int intena; 323 | 324 | if(!holding(&ptable.lock)) 325 | panic("sched ptable.lock"); 326 | if(cpu->ncli != 1) 327 | panic("sched locks"); 328 | if(proc->state == RUNNING) 329 | panic("sched running"); 330 | if(readeflags()&FL_IF) 331 | panic("sched interruptible"); 332 | intena = cpu->intena; 333 | swtch(&proc->context, cpu->scheduler); 334 | cpu->intena = intena; 335 | } 336 | 337 | // Give up the CPU for one scheduling round. 338 | void 339 | yield(void) 340 | { 341 | acquire(&ptable.lock); //DOC: yieldlock 342 | proc->state = RUNNABLE; 343 | sched(); 344 | release(&ptable.lock); 345 | } 346 | 347 | // A fork child's very first scheduling by scheduler() 348 | // will swtch here. "Return" to user space. 349 | void 350 | forkret(void) 351 | { 352 | static int first = 1; 353 | // Still holding ptable.lock from scheduler. 354 | release(&ptable.lock); 355 | 356 | if (first) { 357 | // Some initialization functions must be run in the context 358 | // of a regular process (e.g., they call sleep), and thus cannot 359 | // be run from main(). 360 | first = 0; 361 | iinit(ROOTDEV); 362 | initlog(ROOTDEV); 363 | } 364 | 365 | // Return to "caller", actually trapret (see allocproc). 366 | } 367 | 368 | // Atomically release lock and sleep on chan. 369 | // Reacquires lock when awakened. 370 | void 371 | sleep(void *chan, struct spinlock *lk) 372 | { 373 | if(proc == 0) 374 | panic("sleep"); 375 | 376 | if(lk == 0) 377 | panic("sleep without lk"); 378 | 379 | // Must acquire ptable.lock in order to 380 | // change p->state and then call sched. 381 | // Once we hold ptable.lock, we can be 382 | // guaranteed that we won't miss any wakeup 383 | // (wakeup runs with ptable.lock locked), 384 | // so it's okay to release lk. 385 | if(lk != &ptable.lock){ //DOC: sleeplock0 386 | acquire(&ptable.lock); //DOC: sleeplock1 387 | release(lk); 388 | } 389 | 390 | // Go to sleep. 391 | proc->chan = chan; 392 | proc->state = SLEEPING; 393 | sched(); 394 | 395 | // Tidy up. 396 | proc->chan = 0; 397 | 398 | // Reacquire original lock. 399 | if(lk != &ptable.lock){ //DOC: sleeplock2 400 | release(&ptable.lock); 401 | acquire(lk); 402 | } 403 | } 404 | 405 | //PAGEBREAK! 406 | // Wake up all processes sleeping on chan. 407 | // The ptable lock must be held. 408 | static void 409 | wakeup1(void *chan) 410 | { 411 | struct proc *p; 412 | 413 | for(p = ptable.proc; p < &ptable.proc[NPROC]; p++) 414 | if(p->state == SLEEPING && p->chan == chan) 415 | p->state = RUNNABLE; 416 | } 417 | 418 | // Wake up all processes sleeping on chan. 419 | void 420 | wakeup(void *chan) 421 | { 422 | acquire(&ptable.lock); 423 | wakeup1(chan); 424 | release(&ptable.lock); 425 | } 426 | 427 | // Kill the process with the given pid. 428 | // Process won't exit until it returns 429 | // to user space (see trap in trap.c). 430 | int 431 | kill(int pid) 432 | { 433 | struct proc *p; 434 | 435 | acquire(&ptable.lock); 436 | for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ 437 | if(p->pid == pid){ 438 | p->killed = 1; 439 | // Wake process from sleep if necessary. 440 | if(p->state == SLEEPING) 441 | p->state = RUNNABLE; 442 | release(&ptable.lock); 443 | return 0; 444 | } 445 | } 446 | release(&ptable.lock); 447 | return -1; 448 | } 449 | 450 | //PAGEBREAK: 36 451 | // Print a process listing to console. For debugging. 452 | // Runs when user types ^P on console. 453 | // No lock to avoid wedging a stuck machine further. 454 | void 455 | procdump(void) 456 | { 457 | static char *states[] = { 458 | [UNUSED] "unused", 459 | [EMBRYO] "embryo", 460 | [SLEEPING] "sleep ", 461 | [RUNNABLE] "runble", 462 | [RUNNING] "run ", 463 | [ZOMBIE] "zombie" 464 | }; 465 | int i; 466 | struct proc *p; 467 | char *state; 468 | uint pc[10]; 469 | 470 | for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ 471 | if(p->state == UNUSED) 472 | continue; 473 | if(p->state >= 0 && p->state < NELEM(states) && states[p->state]) 474 | state = states[p->state]; 475 | else 476 | state = "???"; 477 | cprintf("%d %s %s", p->pid, state, p->name); 478 | if(p->state == SLEEPING){ 479 | getcallerpcs((uint*)p->context->ebp+2, pc); 480 | for(i=0; i<10 && pc[i] != 0; i++) 481 | cprintf(" %p", pc[i]); 482 | } 483 | cprintf("\n"); 484 | } 485 | } 486 | --------------------------------------------------------------------------------