├── 2017-2018 ├── sem02 │ ├── example.c │ └── sem02.pdf ├── sem03 │ ├── README.md │ ├── hello-syscalls-c.c │ ├── hello-syscalls-libc.S │ ├── hello-syscalls.S │ ├── lseek-example.c │ ├── open-example.c │ ├── read-from-stdin.c │ ├── redirect-example.c │ ├── stdio-buffered.c │ ├── stdio-unlocked.c │ └── syscalls-are-slow.c ├── sem04 │ ├── fs-1.pdf │ └── fs-2.pdf ├── sem05 │ ├── ex01-printmax.c │ ├── ex02-readdir.c │ ├── ex03-scandir-bad-1.c │ ├── ex04-scandir-bad-2.c │ ├── ex05-scandir-1.c │ ├── ex06-scandir-2.c │ ├── ex07-traverse-bad-1.c │ ├── ex08-traverse-bad-2.c │ ├── ex09-traverse-1.c │ └── ex10-time.c ├── sem06 │ ├── 19-mmap.pdf │ ├── 20-memmng.pdf │ ├── ex01-stdio.c │ ├── ex02-mmap1.c │ ├── ex03-mmap2.c │ ├── ex04-mmap3.c │ ├── ex05-mmap4.c │ ├── ex06-mmap5.c │ ├── ex07-mmap6.c │ ├── ex08-myso.c │ ├── ex08-useso.c │ └── ex09-useself.c ├── sem07 │ ├── 06-pointers.pdf │ ├── ex01-wchar.c │ ├── ex02-rand1.c │ ├── ex03-rand2.c │ └── ex04-rand-oop │ │ ├── prng.c │ │ ├── randint.h │ │ ├── randuse.c │ │ └── trng.c ├── sem08 │ ├── 02threads.pdf │ ├── ex01-create.c │ ├── ex02-data-race.c │ ├── ex03-create-10.c │ ├── ex04-create-with-cast.c │ ├── ex05-stress.c │ ├── ex06-thread-unsafe.c │ └── ex07-race-cond.c ├── sem09 │ ├── ex01-avalanche.c │ ├── ex02-buffering.c │ ├── ex03-_exit.c │ ├── ex04-fork-exec.c │ ├── ex05-syscall.c │ ├── ex06-forkbomb.c │ └── ex07-oom.c ├── sem10 │ ├── ex01-waitstatus.c │ ├── ex02-waitpid.c │ ├── ex03-arbitrary-argv0.c │ ├── ex04-shell-use.c │ ├── ex05-execve.c │ ├── ex06-redir.c │ ├── ex07-shebang.py │ ├── ex08-shellscript.sh │ ├── ex09-inter.c │ └── ex10-myinter.xx ├── sem11 │ ├── ex01-pipesize.c │ ├── ex02-pipesize-auto.c │ ├── ex03-pipe-buf.c │ ├── ex04-pipeline.c │ ├── ex05-pipeline-2.c │ ├── ex06-ping-pong.c │ └── fill.sh ├── sem12 │ ├── ex01-sig1.c │ ├── ex02-sig2.c │ ├── ex03-sig3.c │ ├── ex04-sig4.c │ ├── ex05-pingpong1.c │ ├── ex06-pingpong2.c │ ├── sem-signals.pdf │ ├── signal-1.pdf │ └── signal-2.pdf ├── sem13 │ ├── ex01-sem1.c │ ├── ex02-sem2.c │ ├── ex03-sem3.c │ ├── ex04-sem4.c │ ├── ex05-sem5.c │ └── ex06-msg.c ├── sem14 │ ├── .gitignore │ ├── Makefile │ ├── bitmap.c │ ├── client.c │ └── server.c └── sem15 │ └── epoll-server.c ├── 2018-2019 ├── sem02 │ ├── 01-sys1.c │ ├── 02-sys2.S │ ├── 03-sys3.S │ ├── 04-sys4.c │ ├── 05-_exit.c │ ├── 06-copy1.c │ ├── 07-copy2.c │ └── 08-copy3.c └── sem07 │ ├── 01-count-digits.c │ └── Makefile ├── 2019-2020 ├── 01-args │ └── 1-args.c ├── 02-syscalls │ ├── 1-int-overflow.c │ ├── 2-hello-world.s │ ├── 3-cat.S │ └── 4-cat.c ├── 03-file-syscalls │ ├── 1-open-read.c │ ├── 2-open-append.c │ ├── 3-lseek-negative.c │ └── 4-umask.c ├── 04-stat-time │ ├── 1-stat.c │ └── 2-mktime.c ├── 05-opendir │ ├── 1-snprintf.c │ └── 2-asprintf.c ├── 06-mmap │ ├── 1-count-digits.c │ ├── 2-count-digits-mmap.c │ ├── 3-generate.c │ └── 4-anon-mmap.c ├── 07-make │ ├── Makefile │ ├── m.c │ ├── r.c │ ├── r.h │ └── r2.c ├── 08-dlopen │ ├── Makefile │ ├── m.c │ ├── r.c │ ├── r.h │ └── r2.c ├── 09-fork │ └── 1-fork-wait.c ├── 10-exec │ ├── 1.c │ ├── 2.c │ ├── 3.sh │ ├── 4.c │ ├── 5.py │ ├── 6.c │ ├── 7.c │ ├── 8.x │ └── 9.c ├── 11-pipe │ ├── 1-pipesize.c │ ├── 2-runpipe.c │ ├── 3-runpipe2.c │ └── 4-pingpong.c ├── 12-signal │ ├── 01-bsd-signal-handling.c │ ├── 02-sysv-signal-handling.c │ ├── 03-sigaction.c │ ├── 04-async-signal-safe.c │ ├── 05-wait-for-signal-busy.c │ ├── 06-wait-for-signal-pause.c │ └── 07-wait-for-signal-usleep.c ├── 13-signal-safe │ ├── 01-ping-pong-basic.c │ ├── 02-ping-pong-siginfo.c │ ├── 03-ping-pong-sigprocmask.c │ ├── 04-ping-pong-sigsuspend.c │ ├── 05-ping-pong-async-safe.c │ └── 06-ping-pong-signalfd.c ├── 14-ipc │ ├── 01-ping-pong.c │ └── 02-philosophers.c └── shestimer │ ├── t.c │ └── t_2.c ├── 2020-2021 ├── sem03 │ └── README.md ├── sem04 │ ├── README.md │ ├── fs-1.pdf │ └── fs-2.pdf ├── sem05 │ └── README.md ├── sem06 │ ├── 19-mmap.pdf │ ├── 20-memmng.pdf │ └── README.md ├── sem07 │ ├── README.md │ └── sem07.pdf ├── sem08 │ ├── README.md │ └── sem08.pdf ├── sem09 │ ├── README.md │ ├── reading.pdf │ └── slides.pdf ├── sem10 │ └── README.md └── sem11 │ ├── README.md │ └── slides.pdf ├── 2021-2022 ├── sem01 │ ├── 1.c │ ├── 5.c │ ├── 6.c │ └── README.md ├── sem02 │ └── README.md ├── sem03 │ └── README.md ├── sem04 │ ├── README.md │ ├── fs-1.pdf │ └── fs-2.pdf ├── sem05 │ └── README.md ├── sem06 │ ├── 19-mmap.pdf │ ├── 20-memmng.pdf │ └── README.md ├── sem08 │ └── README.md ├── sem09 │ └── README.md ├── sem10 │ └── README.md └── sem11 │ └── README.md ├── CodeStyle.md └── old ├── 203 └── pipe │ ├── .gitignore │ ├── Makefile │ ├── pipe1.c │ ├── pipe2.c │ └── pipe3.c ├── Unix-Знакомство.pdf ├── fork-exec ├── exec.c ├── proc.c ├── proc.h └── test.c ├── oop └── random │ ├── lib.c │ └── main.c ├── philosophers └── philosophers.c ├── signals-2 └── README.md └── Каталоги. Время.pdf /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/sem02/sem02.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmc-prak/cmc-os/273e3360b7abe0b63ddd12b84514ea20c308a0d0/2017-2018/sem02/sem02.pdf -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /2017-2018/sem04/fs-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmc-prak/cmc-os/273e3360b7abe0b63ddd12b84514ea20c308a0d0/2017-2018/sem04/fs-1.pdf -------------------------------------------------------------------------------- /2017-2018/sem04/fs-2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmc-prak/cmc-os/273e3360b7abe0b63ddd12b84514ea20c308a0d0/2017-2018/sem04/fs-2.pdf -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /2017-2018/sem06/19-mmap.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmc-prak/cmc-os/273e3360b7abe0b63ddd12b84514ea20c308a0d0/2017-2018/sem06/19-mmap.pdf -------------------------------------------------------------------------------- /2017-2018/sem06/20-memmng.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmc-prak/cmc-os/273e3360b7abe0b63ddd12b84514ea20c308a0d0/2017-2018/sem06/20-memmng.pdf -------------------------------------------------------------------------------- /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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/sem07/06-pointers.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmc-prak/cmc-os/273e3360b7abe0b63ddd12b84514ea20c308a0d0/2017-2018/sem07/06-pointers.pdf -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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/sem08/02threads.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmc-prak/cmc-os/273e3360b7abe0b63ddd12b84514ea20c308a0d0/2017-2018/sem08/02threads.pdf -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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/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 | -------------------------------------------------------------------------------- /2017-2018/sem10/ex07-shebang.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python3 -E 2 | 3 | # в этом скрипте на питоне используется специальный комментарий #! 4 | # для указания пути к интерпретатору 5 | 6 | print(1 + 2 + 3); 7 | -------------------------------------------------------------------------------- /2017-2018/sem10/ex08-shellscript.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # скрипт для интерпретатора bash 4 | 5 | echo "Hello" 6 | -------------------------------------------------------------------------------- /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/sem10/ex10-myinter.xx: -------------------------------------------------------------------------------- 1 | #! /home/cher/cmc-os/2017-2018/sem10/ex09-inter -z 2 | 3 | # мой собственный интерпретатор 4 | 5 | aaa 6 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/sem11/fill.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cat /usr/share/dict/words 4 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/sem12/sem-signals.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmc-prak/cmc-os/273e3360b7abe0b63ddd12b84514ea20c308a0d0/2017-2018/sem12/sem-signals.pdf -------------------------------------------------------------------------------- /2017-2018/sem12/signal-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmc-prak/cmc-os/273e3360b7abe0b63ddd12b84514ea20c308a0d0/2017-2018/sem12/signal-1.pdf -------------------------------------------------------------------------------- /2017-2018/sem12/signal-2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmc-prak/cmc-os/273e3360b7abe0b63ddd12b84514ea20c308a0d0/2017-2018/sem12/signal-2.pdf -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/sem14/.gitignore: -------------------------------------------------------------------------------- 1 | client 2 | server 3 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /2018-2019/sem02/05-_exit.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | printf("abc\n"); 6 | _exit(1); 7 | } 8 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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/10-exec/3.sh: -------------------------------------------------------------------------------- 1 | echo 'hello' 2 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /2019-2020/10-exec/5.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python3 2 | 3 | print(int(input()) + int(input())) 4 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /2020-2021/sem04/fs-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmc-prak/cmc-os/273e3360b7abe0b63ddd12b84514ea20c308a0d0/2020-2021/sem04/fs-1.pdf -------------------------------------------------------------------------------- /2020-2021/sem04/fs-2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmc-prak/cmc-os/273e3360b7abe0b63ddd12b84514ea20c308a0d0/2020-2021/sem04/fs-2.pdf -------------------------------------------------------------------------------- /2020-2021/sem05/README.md: -------------------------------------------------------------------------------- 1 | # Работа со временем 2 | 3 | В операционных системах в дальнейшем мы будем различать два вида 4 | времени: астрономическое (календарное), согласованное с временем 5 | в физическом мире, и виртуальное, отсчитываемое независимо 6 | для каждого процесса. 7 | 8 | В операционных системах семейства 9 | [UNIX астрономическое (календарное) время](https://en.wikipedia.org/wiki/Unix_time) 10 | измеряется как число секунд, прошедших с некоторой точки отсчета, 11 | называемой "началом эпохи" (epoch). В Unix началом эпохи 12 | считается полночь 1 января 1970 года по всемирному 13 | координированному времени [(UTC)](https://en.wikipedia.org/wiki/Coordinated_Universal_Time). 14 | 15 | Для простоты отсчет времени игнорирует "високосные секунды" [(leap seconds)](https://en.wikipedia.org/wiki/Leap_second). 16 | Поэтому в каждых сутках всегда 86400 секунд. 17 | 18 | Для хранения времени во внутреннем формате предназначен тип `time_t`. 19 | Это — знаковый тип, с помощью него можно хранить и отметки времени ранее начала эпохи, 20 | которые будут представляться отрицательными числами. 21 | Значению −1 соответствует момент времени 23:59:59 31 декабря 1969 года, 22 | но некоторые функции используют значение −1 в качестве специального 23 | значения-признака ошибки, поэтому чтобы различить допустимый момент 24 | времени и специальное значение-признак ошибки потребуется проверить значение 25 | переменной `errno`. 26 | 27 | Часто на 32-битных версиях операционных систем семейства UNIX 28 | тип `time_t` является синонимом типа `long`, то есть 32-битным 29 | знаковым целым типом. Знаковые 32 бита для хранения счетчика секунд 30 | дают диапазон представимых дат от начала XX века до 2038 года. 31 | В 03:14:07 19 января 2038 32-битный счетчик секунд достигнет 32 | максимального значения (`INT_MAX`), что называется 33 | [проблемой 2038 года](https://en.wikipedia.org/wiki/Year_2038_problem). 34 | 35 | На 64-битных операционных системах проблема переполнения не актуальна, 36 | так как 64-битного счетчика секунд достаточно, чтобы покрыть 37 | все [предполагаемое время жизни Солнечной системы](https://en.wikipedia.org/wiki/Timeline_of_the_far_future). 38 | 39 | ## Получение астрономического времени 40 | 41 | Функция `time` возвращает текущее время и дату. 42 | 43 | ```c 44 | #include 45 | time_t time(time_t *calptr); 46 | ``` 47 | 48 | Функция возвращает текущее время. 49 | Если в качестве параметра `calptr` передается ненулевой указатель, 50 | то же самое значение текущего времени записывается по указателю. 51 | 52 | Функция `gettimeofday` позволяет получить текущее время с микросекундной точностью. 53 | 54 | ```c 55 | #include 56 | int gettimeofday(struct timeval *restrict tp, void *restrict tzp); 57 | ``` 58 | 59 | Функция всегда возвращает значение 0. Параметр `tzp` должен всегда 60 | передаваться как нулевой указатель. 61 | 62 | Функция `gettimeofday` сохраняет время, прошедшее от начала Эпохи до настоящего момента, 63 | по адресу `tp`. Это время представлено в виде структуры `timeval`, 64 | которая хранит секунды и микросекунды: 65 | 66 | ```c 67 | struct timeval 68 | { 69 | time_t tv_sec; /* секунды */ 70 | long tv_usec; /* микросекунды */ 71 | }; 72 | ``` 73 | 74 | ## Работа с календарем 75 | 76 | Стандартная библиотека Си и UNIX поддерживает только [Грегорианский календарь](https://en.wikipedia.org/wiki/Gregorian_calendar). 77 | Если требуется обработка календарной информации в других календарях, 78 | потребуются сторонние библиотеки. 79 | 80 | Для хранения момента времени в Грегорианском календаре 81 | используется структура `tm`, определенная следующим образом: 82 | 83 | ```c 84 | struct tm /* время, разбитое на составляющие */ 85 | { 86 | int tm_sec; /* секунды от начала минуты: [0 - 60] (note leap seconds) */ 87 | int tm_min; /* минуты от начала часа: [0 - 59] */ 88 | int tm_hour; /* часы от полуночи: [0 - 23] */ 89 | int tm_mday; /* дни от начала месяца: [1 - 31] */ 90 | int tm_mon; /* месяцы с января: [0 - 11] */ 91 | int tm_year; /* годы с 1900 года */ 92 | int tm_wday; /* дни с воскресенья: [0 - 6] */ 93 | int tm_yday; /* дни от начала года (1 января): [0 - 365] */ 94 | int tm_isdst; /* флаг перехода на летнее время: <0 - unknown, 0 - no daylight saving, >0 - daylight saving */ 95 | }; 96 | ``` 97 | 98 | Количество секунд может превышать 59, когда для коррекции времени вставляется дополнительная секунда. 99 | Обратите внимание, что отсчет всех компонентов, кроме дня месяца, начинается с 0. 100 | лаг перехода на летнее время представлен положительным числом, если действует летнее время, 101 | 0 – если нет и отрицательным числом, если данная информация недоступна или неизвестна. 102 | 103 | ### Функции `gmtime_r`, `localtime_r` 104 | 105 | Для получения календарной даты по значению типа `time_t` следует использовать 106 | функции `gmtime_r` или `localtime_r`. 107 | 108 | ```c 109 | #include 110 | struct tm *gmtime_r(const time_t *calptr, struct tm *result); 111 | struct tm *localtime_r(const time_t *calptr, struct tm *result); 112 | ``` 113 | 114 | Функция `gmtime_r` выдает календарную дату по UTC, а функция `localtime_r` 115 | выдает календарную дату в локальном часовом поясе. В качестве параметра `result` 116 | должен быть передан указатель на структуру, которая будет заполнена. 117 | Этот же указатель будет возвращен в качестве результата работы функций. 118 | 119 | Обратите внимание, что год в поле `tm_year` отсчитывается от 1900, а месяц - от 0. 120 | Поэтому, чтобы, например, вывести дату в формате YYYY-MM-DD потребуется 121 | прибавить соответствующие значения: 122 | ```c 123 | printf("%04d-%02d-%02d", r->tm_year + 1900, r->tm_mon + 1, r->tm_mday); 124 | ``` 125 | 126 | ### Функции `timegm`, `mktime` 127 | 128 | Обратное преобразование из календарной даты в тип `time_t` 129 | выполняют следующие функции: 130 | 131 | ```c 132 | #include 133 | time_t timegm(struct tm *tmptr); 134 | time_t mktime(struct tm *tmptr); 135 | ``` 136 | 137 | Первая функция предполагает, что календарная дата записана по UTC, 138 | а вторая, что в локальной временной зоне. 139 | 140 | В случае ошибки эти функции возвращают −1, что является и допустимым 141 | временем. Чтобы различить нормальный и ошибочный результат потребуется 142 | привлечь переменную `errno`. 143 | 144 | ```c 145 | errno = 0; 146 | time_t res = mktime(&val); 147 | if (res == -1 && errno) { /* conversion failed */ } 148 | ``` 149 | 150 | Перед вызовом функций `mktime` или `timegm` нужно заполнить 6 полей структуры `tm`, 151 | которые задают момент времени: `tm_year` (год), `tm_mon` (месяц), `tm_mday` (день месяца), 152 | `tm_hour` (час), `tm_min` (минуты), `tm_sec` (секунды). 153 | В поле `tm_isdst` обязательно нужно записать значение −1. 154 | 155 | В качестве побочного эффекта эти функции заполняют оставшиеся 156 | поля структуры `tm`, включая и поле `tm_isdst`, а кроме того, 157 | нормализуют переданные им значения основных полей времени. Так, 158 | время 25:11:04 33 декабря 2020 года будет преобразовано 159 | в 01:11:04 3 января 2021 года, и значения основных полей будут 160 | соответствующим образом изменены. 161 | 162 | ### Функция `strftime` 163 | 164 | Функция `strftime` выполняет форматное преобразование из структуры `tm` 165 | в строку. Форматное преобразование задается строкой, 166 | аналогичной форматной строке функций типа `printf`. 167 | 168 | ```c 169 | #include 170 | size_t strftime(char *buf, size_t maxsize, const char *format, const struct tm *tmptr); 171 | ``` 172 | 173 | Возвращает количество символов, записанных в массив, 174 | если в нем достаточно места, в противном случае возвращает 0 175 | 176 | Последний аргумент функции – указатель на структуру `tm`, содержащую время, 177 | которое должно быть представлено в виде отформатированной строки. 178 | Результат форматирования сохраняется в буфере `buf`, 179 | размер которого определяется аргументом `maxsize`. 180 | Аргумент `format` управляет форматированием значения времени. 181 | Как и в случае с функцией `printf`, спецификаторы формата начинаются с символа процента, 182 | за которым следуют служебные символы. 183 | Все остальные символы в строке `format` выводятся без изменений. 184 | Два символа процента, следующие друг за другом, будут отображаться как один символ процента. 185 | В отличие от функции `printf`, каждый спецификатор формата генерирует на выходе строки 186 | фиксированного размера – спецификаторы ширины поля вывода не предусмотрены. 187 | 188 | Если полученная в результате преобразования строка, включая завершающий нулевой символ, 189 | умещается в буфере, то функция возвращает длину полученной строки без завершающего нулевого символа. 190 | В противном случае возвращается 0. 191 | 192 | # Работа с каталогами. 193 | 194 | Создание каталогов производится с помощью функции `mkdir`, а удаление — с помощью функции `rmdir`. 195 | 196 | ```c 197 | #include 198 | 199 | int mkdir(const char *pathname, mode_t mode); 200 | ``` 201 | 202 | Возвращает 0 в случае успеха, –1 в случае ошибки. 203 | Если запись с таким именем уже существует, функция завершается с ошибкой. 204 | В случае успеха права на создаваемый каталог выставляются с учетом параметра `umask` 205 | процесса (то есть `mode & ~umask`). 206 | 207 | ```c 208 | #include 209 | 210 | int rmdir(const char *pathname); 211 | ``` 212 | 213 | ## Просмотр каталога 214 | 215 | Для просмотра каталога используются функции, определенные 216 | в заголовочном файле ``. 217 | 218 | В данном случае стандартный API предоставляет пользователям высокоуровневый 219 | интерфейс, аналогичный интерфейсу `FILE` стандартной библиотеки. 220 | Какие системные вызовы используются для реализации интерфейса `DIR` 221 | не специфицируется. 222 | 223 | ```c 224 | #include 225 | 226 | DIR *opendir(const char *pathname); 227 | struct dirent *readdir(DIR *dp); 228 | int closedir(DIR *dp); 229 | 230 | long telldir(DIR *dp); 231 | void seekdir(DIR *dp, long loc); 232 | ``` 233 | 234 | ### Функции `opendir`, `closedir` 235 | 236 | Функция `opendir` открывает каталог по заданному пути. 237 | В случае успеха возвращается указатель на структуру `DIR` 238 | хранящую состояние открытого каталога. В случае неудачи 239 | функция `opendir` возвращает нулевой указатель. 240 | 241 | Функция `closedir` закрывает открытый каталог и освобождает 242 | все ресурсы, связанные с открытым каталогом (это обычно 243 | один файловый дескриптор и одна область динамической памяти). 244 | 245 | ### Функция `readdir` 246 | 247 | Функция `readdir` возвращает очередную запись в открытом каталоге. 248 | 249 | Структура `dirent` определена в файле `` и зависит от конкретной реализации. 250 | Однако в любой версии UNIX эта структура содержит как минимум следующие два поля: 251 | 252 | ```c 253 | struct dirent 254 | { 255 | ino_t d_ino; /* номер индексного дескриптора */ 256 | char d_name[NAME_MAX + 1]; /* строка имени файла, завершающаяся нулевым символом */ 257 | } 258 | ``` 259 | 260 | Поле `d_ino` использовать нельзя, так как в точках монтирования оно содержит 261 | локальное для текущей файловой системы значение и не позволит связать 262 | файловые системы в единое дерево. Если нужен номер индексного дескриптора 263 | записи в каталоге, следует использовать системный вызов семейства `stat`. 264 | 265 | Поле `d_name` содержит имя очередной записи в каталоге. Значение константы 266 | `NAME_MAX` обычно равно 255, то есть API работы с каталогами UNIX не поддерживает 267 | работу с файлами, если длина имена файла в каком-либо каталоге превышает 268 | 255 байтов, даже если и файловая система сама по себе поддерживает 269 | более длинные имена. 270 | 271 | Функция `readdir` возвращает указатель куда-то вовнутрь состояния 272 | открытого каталога (структуры `DIR`). Значение этого указателя 273 | становится недействительным после следующего вызова `readdir`, 274 | или в результате вызова `closedir`. Поэтому, если значение поля `d_name` 275 | может потребоваться в дальнейшем, его нужно скопировать в другую область памяти. 276 | 277 | ### Функции `telldir`, `seekdir` 278 | 279 | Хотя в API определены функции `telldir` и `seekdir`, которые, по идее, 280 | позволяют запомнить текущее положение в каталоге и вернуться к нему позднее, 281 | например, после выхода из рекурсии, работоспособность такого подхода не гарантируется. 282 | Значение, возвращенное функцией `telldir`, становится недействительным, 283 | если каталог был закрыт. При повторном открытии каталога вызов `telldir` 284 | на той же самой позиции может вернуть другое значение. Поэтому 285 | функции `telldir` и `seekdir` нельзя применять для рекурсивного обхода 286 | файловой системы. 287 | 288 | Поэтому чтобы рекурсивно обойти файловую систему для каждого каталога в 289 | иерархии каталогов следует считать все его содержимое в память 290 | однократым проходом по каталогу с помощью `opendir`/`readdir`/`closedir`, 291 | после чего обработать список файлов, сохраненный в памяти, рекурсивно 292 | обрабатывая подкаталоги. 293 | 294 | ### Функции `chdir`, `fchdir` 295 | 296 | Для каждого процесса определен текущий рабочий каталог. 297 | относительно этого каталога вычисляются все относительные пути (то есть пути, которые не начинаются с символа слэша). 298 | Когда пользователь входит в систему, текущим рабочим каталогом обычно становится каталог, указанный в шестом поле записи из файла /etc/passwd, – домашний каталог пользователя. Текущий рабочий каталог – это атрибут процесса, домашний каталог – атрибут пользователя. 299 | Процесс может изменить текущий рабочий каталог с помощью функции `chdir` или `fchdir`. 300 | 301 | ```c 302 | #include 303 | 304 | int chdir(const char *pathname); 305 | int fchdir(int filedes); 306 | ``` 307 | 308 | Функции возвращают 0 в случае успеха, –1 в случае ошибки. 309 | 310 | Пример использования функции `chdir` 311 | 312 | ```c 313 | #include 314 | #include 315 | #include 316 | #include 317 | #include 318 | 319 | int main() 320 | { 321 | if (chdir("/tmp") < 0) { 322 | fprintf(stderr, "ошибка вызова функции chdir: %s\n", strerror(errno)); 323 | exit(1); 324 | } 325 | printf("каталог /tmp стал текущим рабочим каталогом\n"); 326 | exit(0); 327 | } 328 | ``` 329 | 330 | ### Функция `getcwd` 331 | 332 | Поскольку ядро хранит сведения о текущем рабочем каталоге, должен быть способ получить его текущее значение. К сожалению, ядро хранит не полный путь к каталогу, а некоторую иную информацию, такую как указатель 333 | на виртуальный узел (v-node) каталога. 334 | Чтобы определить абсолютный путь к текущему рабочему каталогу, нужна функция, которая будет перемещаться вверх по дереву каталогов, начиная с текущего («точка») и далее через специальные каталоги «точка - точка»,пока не достигнет корневого каталога. В каждом из промежуточных каталогов функция будет читать записи из файла каталога, пока не найдет название, которое соответствует индексному узлу предыдущего каталога. Повторяя эту процедуру до тех пор, пока небудет достигнут корневой каталог, мы в результате получим абсолютный путь к текущему рабочему каталогу. 335 | К счастью, такая функция уже существует. 336 | 337 | ```c 338 | #include 339 | 340 | char *getcwd(char *buf, size_t size); 341 | ``` 342 | 343 | Функция озвращает указатель на `buf` в случае успеха, `NULL` в случае ошибки. 344 | 345 | Пример использования функции `getcwd`. 346 | 347 | ```c 348 | #include 349 | #include 350 | #include 351 | #include 352 | #include 353 | 354 | int main(void) 355 | { 356 | char *ptr; 357 | size_t size = PATH_MAX; 358 | 359 | if (chdir("/usr/spool/uucppublic") < 0) { 360 | fprintf(stderr, "ошибка вызова функции chdir: %s\n", strerror(errno)); 361 | exit(1); 362 | } 363 | 364 | if (!(ptr = malloc(size))) { 365 | fprintf(stderr, "ошибка выделения памяти: %s\n", strerror(errno)); 366 | fflush(NULL); 367 | abort(); 368 | } 369 | 370 | if (getcwd(ptr, size) == NULL) { 371 | fprintf(stderr, "ошибка вызова функции getcwd: %s\n", strerror(errno)); 372 | exit(1); 373 | } 374 | 375 | printf("cwd = %s\n", ptr); 376 | exit(0); 377 | } 378 | ``` 379 | 380 | -------------------------------------------------------------------------------- /2020-2021/sem06/19-mmap.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmc-prak/cmc-os/273e3360b7abe0b63ddd12b84514ea20c308a0d0/2020-2021/sem06/19-mmap.pdf -------------------------------------------------------------------------------- /2020-2021/sem06/20-memmng.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmc-prak/cmc-os/273e3360b7abe0b63ddd12b84514ea20c308a0d0/2020-2021/sem06/20-memmng.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/sem07/sem07.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmc-prak/cmc-os/273e3360b7abe0b63ddd12b84514ea20c308a0d0/2020-2021/sem07/sem07.pdf -------------------------------------------------------------------------------- /2020-2021/sem08/README.md: -------------------------------------------------------------------------------- 1 | # Процессы (fork, wait, exit) 2 | 3 | [Запись занятия](https://www.youtube.com/watch?v=xkKRu5bU3uI) 4 | 5 | [Слайды](sem08.pdf) -------------------------------------------------------------------------------- /2020-2021/sem08/sem08.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmc-prak/cmc-os/273e3360b7abe0b63ddd12b84514ea20c308a0d0/2020-2021/sem08/sem08.pdf -------------------------------------------------------------------------------- /2020-2021/sem09/README.md: -------------------------------------------------------------------------------- 1 | # Каналы 2 | 3 | [Запись занятия](https://youtu.be/ZAJoH4iQn0M) 4 | 5 | [Слайды](slides.pdf) 6 | 7 | [Текст](reading.pdf) -------------------------------------------------------------------------------- /2020-2021/sem09/reading.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmc-prak/cmc-os/273e3360b7abe0b63ddd12b84514ea20c308a0d0/2020-2021/sem09/reading.pdf -------------------------------------------------------------------------------- /2020-2021/sem09/slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmc-prak/cmc-os/273e3360b7abe0b63ddd12b84514ea20c308a0d0/2020-2021/sem09/slides.pdf -------------------------------------------------------------------------------- /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` -------------------------------------------------------------------------------- /2020-2021/sem11/README.md: -------------------------------------------------------------------------------- 1 | # Сигналы 2 | 3 | [Запись занятия](https://youtu.be/We0Im0lWAYQ) 4 | 5 | [Слайды](slides.pdf) 6 | -------------------------------------------------------------------------------- /2020-2021/sem11/slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmc-prak/cmc-os/273e3360b7abe0b63ddd12b84514ea20c308a0d0/2020-2021/sem11/slides.pdf -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /2021-2022/sem04/fs-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmc-prak/cmc-os/273e3360b7abe0b63ddd12b84514ea20c308a0d0/2021-2022/sem04/fs-1.pdf -------------------------------------------------------------------------------- /2021-2022/sem04/fs-2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmc-prak/cmc-os/273e3360b7abe0b63ddd12b84514ea20c308a0d0/2021-2022/sem04/fs-2.pdf -------------------------------------------------------------------------------- /2021-2022/sem06/19-mmap.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmc-prak/cmc-os/273e3360b7abe0b63ddd12b84514ea20c308a0d0/2021-2022/sem06/19-mmap.pdf -------------------------------------------------------------------------------- /2021-2022/sem06/20-memmng.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmc-prak/cmc-os/273e3360b7abe0b63ddd12b84514ea20c308a0d0/2021-2022/sem06/20-memmng.pdf -------------------------------------------------------------------------------- /old/203/pipe/.gitignore: -------------------------------------------------------------------------------- 1 | pipe1 2 | pipe2 3 | pipe3 4 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /old/Unix-Знакомство.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmc-prak/cmc-os/273e3360b7abe0b63ddd12b84514ea20c308a0d0/old/Unix-Знакомство.pdf -------------------------------------------------------------------------------- /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.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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /old/Каталоги. Время.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmc-prak/cmc-os/273e3360b7abe0b63ddd12b84514ea20c308a0d0/old/Каталоги. Время.pdf --------------------------------------------------------------------------------