aboutsummaryrefslogtreecommitdiff
path: root/semestr-5/so/lista2
diff options
context:
space:
mode:
authorFranciszek Malinka <franciszek.malinka@gmail.com>2021-11-13 17:32:03 +0100
committerFranciszek Malinka <franciszek.malinka@gmail.com>2021-11-13 17:32:03 +0100
commitff0ac5bf2b3069200d2bb5a56bc3eef0b4bcb44a (patch)
tree6778fd6eb8fb48cff51564d4110ed3bd168a3b2e /semestr-5/so/lista2
parentfa505e1e8d7f990d608144ccd97e9f960c6b8b57 (diff)
update
Diffstat (limited to 'semestr-5/so/lista2')
-rw-r--r--semestr-5/so/lista2/buffer.c13
-rw-r--r--semestr-5/so/lista2/echo.c11
-rw-r--r--semestr-5/so/lista2/segv.c22
-rw-r--r--semestr-5/so/lista2/segv.s87
-rw-r--r--semestr-5/so/lista2/signals.c30
m---------semestr-5/so/lista2/sinit0
-rw-r--r--semestr-5/so/lista2/so21_lista_2/Makefile.include105
-rw-r--r--semestr-5/so/lista2/so21_lista_2/cycle.c57
-rw-r--r--semestr-5/so/lista2/so21_lista_2/demand.c83
-rw-r--r--semestr-5/so/lista2/so21_lista_2/include/bitstring.h138
-rw-r--r--semestr-5/so/lista2/so21_lista_2/include/csapp.h240
-rw-r--r--semestr-5/so/lista2/so21_lista_2/include/queue.h587
-rw-r--r--semestr-5/so/lista2/so21_lista_2/include/rio.h27
-rw-r--r--semestr-5/so/lista2/so21_lista_2/include/terminal.h27
-rw-r--r--semestr-5/so/lista2/so21_lista_2/include/tree.h735
-rw-r--r--semestr-5/so/lista2/so21_lista_2/reaper.c59
-rw-r--r--semestr-5/so/lista2/test.c33
17 files changed, 2254 insertions, 0 deletions
diff --git a/semestr-5/so/lista2/buffer.c b/semestr-5/so/lista2/buffer.c
new file mode 100644
index 0000000..8b549a1
--- /dev/null
+++ b/semestr-5/so/lista2/buffer.c
@@ -0,0 +1,13 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main()
+{
+ printf("hello world...");
+ // fflush(stdout);
+ fork();
+ fork();
+ fork();
+}
diff --git a/semestr-5/so/lista2/echo.c b/semestr-5/so/lista2/echo.c
new file mode 100644
index 0000000..1d26d6f
--- /dev/null
+++ b/semestr-5/so/lista2/echo.c
@@ -0,0 +1,11 @@
+#include <stdio.h>
+
+int main() {
+ char buffer[1000];
+ printf("Echo!\n");
+ while (1) {
+ scanf("%s", buffer);
+ printf("%s\n", buffer);
+ }
+ printf("What?");
+}
diff --git a/semestr-5/so/lista2/segv.c b/semestr-5/so/lista2/segv.c
new file mode 100644
index 0000000..6aca3ec
--- /dev/null
+++ b/semestr-5/so/lista2/segv.c
@@ -0,0 +1,22 @@
+#include <signal.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+volatile int *p = NULL;
+int x = 0;
+
+void segv_handler(int signum) {
+ char text[100];
+ sprintf(text, "Segv handler! p: %p\n", p);
+ if (p == NULL)
+ p = &x;
+ write(STDOUT_FILENO, text, strlen(text));
+}
+
+int main() {
+ signal(SIGSEGV, segv_handler);
+
+ *p = 1;
+}
diff --git a/semestr-5/so/lista2/segv.s b/semestr-5/so/lista2/segv.s
new file mode 100644
index 0000000..3545549
--- /dev/null
+++ b/semestr-5/so/lista2/segv.s
@@ -0,0 +1,87 @@
+ .file "segv.c"
+ .text
+ .globl p
+ .bss
+ .align 8
+ .type p, @object
+ .size p, 8
+p:
+ .zero 8
+ .section .rodata
+.LC0:
+ .string "Segv handler! p: %p\n"
+ .text
+ .globl segv_handler
+ .type segv_handler, @function
+segv_handler:
+.LFB6:
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ addq $-128, %rsp
+ movl %edi, -116(%rbp)
+ movq %fs:40, %rax
+ movq %rax, -8(%rbp)
+ xorl %eax, %eax
+ movq p(%rip), %rdx
+ leaq -112(%rbp), %rax
+ leaq .LC0(%rip), %rcx
+ movq %rcx, %rsi
+ movq %rax, %rdi
+ movl $0, %eax
+ call sprintf@PLT
+ movq p(%rip), %rax
+ testq %rax, %rax
+ jne .L2
+ movl $8, %edi
+ call malloc@PLT
+ movq %rax, p(%rip)
+.L2:
+ leaq -112(%rbp), %rax
+ movq %rax, %rdi
+ call strlen@PLT
+ movq %rax, %rdx
+ leaq -112(%rbp), %rax
+ movq %rax, %rsi
+ movl $1, %edi
+ call write@PLT
+ nop
+ movq -8(%rbp), %rax
+ subq %fs:40, %rax
+ je .L3
+ call __stack_chk_fail@PLT
+.L3:
+ leave
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE6:
+ .size segv_handler, .-segv_handler
+ .globl main
+ .type main, @function
+main:
+.LFB7:
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ leaq segv_handler(%rip), %rax
+ movq %rax, %rsi
+ movl $11, %edi
+ call signal@PLT
+ movq p(%rip), %rax
+ movb $1, (%rax)
+ movl $0, %eax
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE7:
+ .size main, .-main
+ .ident "GCC: (GNU) 11.1.0"
+ .section .note.GNU-stack,"",@progbits
diff --git a/semestr-5/so/lista2/signals.c b/semestr-5/so/lista2/signals.c
new file mode 100644
index 0000000..a7593bc
--- /dev/null
+++ b/semestr-5/so/lista2/signals.c
@@ -0,0 +1,30 @@
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <errno.h>
+
+void sig_handler(int signum) {
+ char text[100];
+ sprintf(text, "[%d] Hello, I'm a signal handler :)\n", getpid());
+ write(STDOUT_FILENO, text, strlen(text));
+}
+
+int main() {
+ signal(SIGUSR1, sig_handler);
+ printf("Parent: [%d]\n", getpid());
+ fflush(stdout);
+ if (fork() == 0) {
+ printf("Child: [%d]\n", getpid());
+ // while(1) {}
+ if (execl("./echo-my", "echo-my", NULL) < 0) {
+ fprintf(stderr, "Exec error: %s\n", strerror(errno));
+ exit(0);
+ }
+ }
+
+ int result;
+ wait(&result);
+}
diff --git a/semestr-5/so/lista2/sinit b/semestr-5/so/lista2/sinit
new file mode 160000
+Subproject 28c44b6b94a870f2942c37f9cfbae8b77059571
diff --git a/semestr-5/so/lista2/so21_lista_2/Makefile.include b/semestr-5/so/lista2/so21_lista_2/Makefile.include
new file mode 100644
index 0000000..3408d22
--- /dev/null
+++ b/semestr-5/so/lista2/so21_lista_2/Makefile.include
@@ -0,0 +1,105 @@
+CC = gcc -g
+CFLAGS = -Og -Wall -Wstrict-prototypes
+AS = as -g
+ASFLAGS =
+CPPFLAGS = -Iinclude
+LDLIBS = -Llibcsapp -lcsapp
+SED = sed
+
+# Recognize operating system
+ifeq ($(shell uname -s), Darwin)
+CPPFLAGS += -DMACOS
+SED = gsed
+endif
+
+ifeq ($(shell uname -s), Linux)
+CPPFLAGS += -DLINUX
+endif
+
+ifeq ($(shell uname -s), FreeBSD)
+CPPFLAGS += -DFREEBSD
+endif
+
+# Pass "VERBOSE=1" at command line to display command being invoked by GNU Make
+ifneq ($(VERBOSE), 1)
+.SILENT:
+endif
+
+LIBSRC_C = $(wildcard libcsapp/*.c)
+LIBSRC_S = $(wildcard libcsapp/*.s)
+LIBSRC_H = $(wildcard include/*.h)
+LIBSRCS = $(LIBSRC_C) $(LIBSRC_S) $(LIBSRC_H)
+LIBOBJS = $(LIBSRC_C:%.c=%.o)
+ifneq ($(shell uname -s), Darwin)
+LIBOBJS += $(LIBSRC_S:%.s=%.o)
+endif
+LIB = libcsapp/libcsapp.a
+
+SRC_C = $(wildcard *.c)
+SRC_S = $(wildcard *.s)
+SRC_H = $(wildcard *.h)
+SRCS = $(SRC_C) $(SRC_S)
+OBJS = $(SRC_C:%.c=%.o)
+
+SOURCES = $(SRCS) $(LIBSRCS)
+OBJECTS = $(OBJS) $(LIBOBJS)
+DEPFILES = $(foreach f,$(SRC_C) $(LIBSRC_C),\
+ $(dir $(f))$(patsubst %.c,.%.d,$(notdir $(f))))
+
+ARCHIVE = so$(shell date +'%y')_$(shell basename $(PWD))
+FILES = Makefile Makefile.include $(EXTRA-FILES)
+
+all: $(DEPFILES) $(LIB) $(PROGS)
+
+$(LIB): $(LIBOBJS)
+
+# Generate dependencies automatically
+ifeq ($(words $(findstring $(MAKECMDGOALS), archive clean)), 0)
+ -include $(DEPFILES)
+endif
+
+# Disable all built-in recipes and define our own
+.SUFFIXES:
+
+.%.d: %.c
+ $(CC) $(CPPFLAGS) -MM -MG -o $@ $<
+
+%.o: %.c .%.d
+ @echo "[CC] $@ <- $<"
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
+
+%.o: %.s
+ @echo "[AS] $@ <- $<"
+ $(AS) $(ASFLAGS) -c -o $@ $<
+
+%.a:
+ @echo "[AR] $@ <- $^"
+ $(AR) rc $@ $^
+
+%: %.o $(LIB)
+ @echo "[LD] $@ <- $^"
+ $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
+
+clean:
+ rm -vf $(PROGS) $(OBJECTS) $(DEPFILES) $(LIB)
+ rm -vf $(shell find -L . -iname '*~')
+ rm -vf $(ARCHIVE).tar.gz
+ rm -vrf $(EXTRA-CLEAN) *.dSYM
+
+format:
+ clang-format --style=file -i $(LIBSRC_C) $(LIBSRC_H) $(SRC_C) $(SRC_H)
+
+archive: clean
+ mkdir -p $(ARCHIVE) $(ARCHIVE)/libcsapp $(ARCHIVE)/include
+ cp -L $(SRCS) $(SRC_H) $(FILES) $(ARCHIVE)/
+ cp -L $(LIBSRCS) $(ARCHIVE)/libcsapp/
+ cp -L $(LIBSRC_H) $(ARCHIVE)/include/
+ for f in $(SRCS:%=$(ARCHIVE)/%); do \
+ $(SED) --in-place='' -e '/^#if.*STUDENT/,/^#endif.*STUDENT/d' $$f; \
+ done
+ tar cvzhf $(ARCHIVE).tar.gz $(ARCHIVE)
+ rm -rf $(ARCHIVE)
+
+.PHONY: all clean format archive
+
+# vim: ts=8 sw=8 noet
diff --git a/semestr-5/so/lista2/so21_lista_2/cycle.c b/semestr-5/so/lista2/so21_lista_2/cycle.c
new file mode 100644
index 0000000..7daf754
--- /dev/null
+++ b/semestr-5/so/lista2/so21_lista_2/cycle.c
@@ -0,0 +1,57 @@
+#include "csapp.h"
+
+static void signal_handler(int signum, siginfo_t *info, void *data) {
+ if (signum == SIGINT) {
+ safe_printf("(%d) Screw you guys... I'm going home!\n", getpid());
+ _exit(0);
+ }
+}
+
+static void play(pid_t next, const sigset_t *set) {
+ for (;;) {
+ printf("(%d) Waiting for a ball!\n", getpid());
+ /* TODO: Something is missing here! */
+ sigset_t mask;
+ sigfillset(&mask);
+ sigdelset(&mask, SIGUSR1);
+ sigdelset(&mask, SIGINT);
+ Sigsuspend(&mask);
+ usleep((300 + random() % 400) * 1000);
+ Kill(next, SIGUSR1);
+ printf("(%d) Passing ball to (%d)!\n", getpid(), next);
+ }
+}
+
+int main(int argc, char *argv[]) {
+ if (argc != 2)
+ app_error("Usage: %s [CHILDREN]", argv[0]);
+
+ int children = atoi(argv[1]);
+
+ if (children < 4 || children > 20)
+ app_error("Give number of children in range from 4 to 20!");
+
+ /* Register signal handler for SIGUSR1 */
+ struct sigaction action = {.sa_sigaction = signal_handler};
+ Sigaction(SIGINT, &action, NULL);
+ Sigaction(SIGUSR1, &action, NULL);
+
+ /* TODO: Start all processes and make them wait for the ball! */
+ sigset_t mask;
+ sigfillset(&mask);
+ sigprocmask(SIG_BLOCK, &mask, NULL);
+
+ pid_t prev_pid = getpid();
+
+ for (int i = 1; i <= children; i++) {
+ int pid = Fork();
+ if (pid == 0) {
+ play(prev_pid, NULL);
+ }
+ prev_pid = pid;
+ }
+
+ Kill(prev_pid, SIGUSR1);
+ play(prev_pid, NULL);
+ return EXIT_SUCCESS;
+}
diff --git a/semestr-5/so/lista2/so21_lista_2/demand.c b/semestr-5/so/lista2/so21_lista_2/demand.c
new file mode 100644
index 0000000..d4ae715
--- /dev/null
+++ b/semestr-5/so/lista2/so21_lista_2/demand.c
@@ -0,0 +1,83 @@
+#include "csapp.h"
+
+/* First address of handled region. */
+#define ADDR_START ((void *)0x10000000)
+/* Last address of handled region (not inclusive). */
+#define ADDR_END ((void *)0x10010000)
+
+static size_t pagesize;
+
+/* Maps anonymouse page with `prot` access permissions at `addr` address. */
+static void mmap_page(void *addr, int prot) {
+ Mmap(addr, pagesize, prot, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
+}
+
+/* Changes protection bits to `prot` for page at `addr` address. */
+static void mprotect_page(void *addr, int prot) {
+ Mprotect(addr, pagesize, prot);
+}
+
+static void sigsegv_handler(int signum, siginfo_t *info, void *data) {
+ ucontext_t *uc = data;
+ // intptr_t rip;
+
+ /* TODO: You need to get value of instruction pointer register from `uc`.
+ * Print all useful data from `info` and quit in such a way that a shell
+ * reports program has been terminated with SIGSEGV. */
+
+ #define REG_RIP 16
+
+ intptr_t fault_instr = uc->uc_mcontext.gregs[REG_RIP];
+ intptr_t fault_address = (intptr_t)info->si_addr;
+ intptr_t fault_page = fault_address / pagesize * pagesize;
+
+ safe_printf("Fault at rip=%lx, accessing %lx! ", fault_instr, fault_address);
+ if ((void *)fault_address < ADDR_START || (void *)fault_address >= ADDR_END) {
+ safe_printf("Address not mapped - terminating!\n");
+ _exit(128 + SIGSEGV);
+ }
+
+ switch(info->si_code) {
+ case SEGV_MAPERR:
+ safe_printf("Map missing page at %lx.\n", fault_page);
+ mmap_page((void *)fault_page, PROT_READ);
+ break;
+
+ case SEGV_ACCERR:
+ safe_printf("Make page at %lx writable.\n", fault_page);
+ mprotect_page((void *)fault_page, PROT_READ | PROT_WRITE);
+ break;
+
+ default:
+ safe_printf("Uknkonw code: %d.\n", info->si_code);
+ _exit(128 + SIGSEGV);
+ }
+}
+
+int main(int argc, char **argv) {
+ pagesize = sysconf(_SC_PAGESIZE);
+
+ /* Register signal handler for SIGSEGV */
+ struct sigaction action = {.sa_sigaction = sigsegv_handler,
+ .sa_flags = SA_SIGINFO};
+ sigaction(SIGSEGV, &action, NULL);
+
+ /* Initially all pages in the range are either not mapped or readonly! */
+ for (void *addr = ADDR_START; addr < ADDR_END; addr += pagesize)
+ if (random() % 2)
+ mmap_page(addr, PROT_READ);
+
+ /* Generate lots of writes to the region. */
+ volatile long *array = ADDR_START;
+ long nelems = (ADDR_END - ADDR_START) / sizeof(long);
+
+ for (long i = 0; i < nelems * 2; i++) {
+ long index = random() % nelems;
+ array[index] = (long)&array[index];
+ }
+
+ /* Perform off by one access - triggering a real fault! */
+ array[nelems] = 0xDEADC0DE;
+
+ return EXIT_SUCCESS;
+}
diff --git a/semestr-5/so/lista2/so21_lista_2/include/bitstring.h b/semestr-5/so/lista2/so21_lista_2/include/bitstring.h
new file mode 100644
index 0000000..66503f0
--- /dev/null
+++ b/semestr-5/so/lista2/so21_lista_2/include/bitstring.h
@@ -0,0 +1,138 @@
+/* $NetBSD: bitstring.h,v 1.14 2016/03/17 02:25:32 christos Exp $ */
+
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Vixie.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)bitstring.h 8.1 (Berkeley) 7/19/93
+ */
+
+#ifndef _BITSTRING_H_
+#define _BITSTRING_H_
+
+/* modified for SV/AT and bitstring bugfix by M.R.Murphy, 11oct91
+ * bitstr_size changed gratuitously, but shorter
+ * bit_alloc spelling error fixed
+ * the following were efficient, but didn't work, they've been made to
+ * work, but are no longer as efficient :-)
+ * bit_nclear, bit_nset, bit_ffc, bit_ffs
+ */
+/*
+ * The comment above may or may not bear any resemblance to reality.
+ * This code has been maintained in a confusing way, with little
+ * information available on the provenance of much of it. "At least it
+ * works."
+ * /s/ Perry E. Metzger, 2 Feb 98
+ */
+typedef unsigned char bitstr_t;
+
+/* internal macros */
+/* byte of the bitstring bit is in */
+#define _bit_byte(bit) (uint32_t)((bit) >> 3)
+
+/* mask for the bit within its byte */
+#define _bit_mask(bit) (uint32_t)((1 << (uint32_t)((bit)&0x7)))
+
+/* external macros */
+/* bytes in a bitstring of nbits bits */
+#define bitstr_size(nbits) (size_t)((uint32_t)((nbits) + 7) >> 3)
+
+/* allocate a bitstring */
+#define bit_alloc(nbits) calloc(bitstr_size(nbits), sizeof(bitstr_t))
+
+/* allocate a bitstring on the stack */
+#define bit_decl(name, nbits) ((name)[bitstr_size(nbits)])
+
+/* is bit N of bitstring name set? */
+#define bit_test(name, bit) \
+ /*LINTED bitwise on signed*/ ((name)[_bit_byte(bit)] & _bit_mask(bit))
+
+/* set bit N of bitstring name */
+#define bit_set(name, bit) \
+ /*LINTED bitwise on signed*/ \
+ ((name)[_bit_byte(bit)] = \
+ (unsigned char)(_bit_mask(bit) | (name)[_bit_byte(bit)]))
+
+/* clear bit N of bitstring name */
+#define bit_clear(name, bit) \
+ /*LINTED bitwise on signed*/ \
+ ((name)[_bit_byte(bit)] &= (unsigned char)~_bit_mask(bit))
+
+/* clear bits start ... stop in bitstring */
+#define bit_nclear(name, start, stop) \
+ do { \
+ bitstr_t *_name = name; \
+ size_t _start = start, _stop = stop; \
+ while (_start <= _stop) { \
+ bit_clear(_name, _start); \
+ _start++; \
+ } \
+ } while (/*CONSTCOND*/ 0)
+
+/* set bits start ... stop in bitstring */
+#define bit_nset(name, start, stop) \
+ do { \
+ bitstr_t *_name = name; \
+ size_t _start = start, _stop = stop; \
+ while (_start <= _stop) { \
+ bit_set(_name, _start); \
+ _start++; \
+ } \
+ } while (/*CONSTCOND*/ 0)
+
+/* find first bit clear in name */
+#define bit_ffc(name, nbits, value) \
+ do { \
+ const bitstr_t *_name = name; \
+ size_t _bit, _nbits = nbits; \
+ int _value = -1; \
+ for (_bit = 0; _bit < _nbits; ++_bit) \
+ if (!bit_test(_name, _bit)) { \
+ _value = _bit; \
+ break; \
+ } \
+ *(value) = _value; \
+ } while (/*CONSTCOND*/ 0)
+
+/* find first bit set in name */
+#define bit_ffs(name, nbits, value) \
+ do { \
+ const bitstr_t *_name = name; \
+ size_t _bit, _nbits = nbits; \
+ int _value = -1; \
+ for (_bit = 0; _bit < _nbits; ++_bit) \
+ if (bit_test(_name, _bit)) { \
+ _value = _bit; \
+ break; \
+ } \
+ *(value) = _value; \
+ } while (/*CONSTCOND*/ 0)
+
+#endif /* !_BITSTRING_H_ */
diff --git a/semestr-5/so/lista2/so21_lista_2/include/csapp.h b/semestr-5/so/lista2/so21_lista_2/include/csapp.h
new file mode 100644
index 0000000..dabdf77
--- /dev/null
+++ b/semestr-5/so/lista2/so21_lista_2/include/csapp.h
@@ -0,0 +1,240 @@
+#ifndef __CSAPP_H__
+#define __CSAPP_H__
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#ifdef LINUX
+#include <sys/sysmacros.h>
+#include <sys/prctl.h>
+#endif
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+#include <arpa/inet.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <limits.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <poll.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <semaphore.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdnoreturn.h>
+#include <string.h>
+#include <termios.h>
+#include <time.h>
+#include <unistd.h>
+
+#define _CONCAT(x, y) x##y
+#define CONCAT(x, y) _CONCAT(x, y)
+
+#define min(a, b) \
+ ({ \
+ typeof(a) _a = (a); \
+ typeof(b) _b = (b); \
+ _a < _b ? _a : _b; \
+ })
+
+#define max(a, b) \
+ ({ \
+ typeof(a) _a = (a); \
+ typeof(b) _b = (b); \
+ _a > _b ? _a : _b; \
+ })
+
+#ifndef powerof2
+#define powerof2(x) (((x) & ((x)-1)) == 0)
+#endif
+
+#ifndef __unused
+#define __unused __attribute__((unused))
+#endif
+
+extern char **environ;
+
+/* Useful constants. */
+#define MAXLINE 4096
+
+/* Our own error-handling functions */
+noreturn void unix_error(const char *fmt, ...)
+ __attribute__((format(printf, 1, 2)));
+noreturn void posix_error(int code, const char *fmt, ...)
+ __attribute__((format(printf, 2, 3)));
+noreturn void app_error(const char *fmt, ...)
+ __attribute__((format(printf, 1, 2)));
+noreturn void gai_error(int code, const char *fmt, ...)
+ __attribute__((format(printf, 2, 3)));
+
+/* Signal safe I/O functions */
+void safe_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
+void safe_error(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
+
+/* Decent hashing function. */
+#define HASHINIT 5381
+
+uint32_t jenkins_hash(const void *key, size_t length, uint32_t initval);
+
+/* Memory allocation wrappers */
+void *Malloc(size_t size);
+void *Realloc(void *ptr, size_t size);
+void *Calloc(size_t nmemb, size_t size);
+
+/* Process control wrappers */
+pid_t Fork(void);
+pid_t Waitpid(pid_t pid, int *iptr, int options);
+#define Wait(iptr) Waitpid(-1, iptr, 0)
+void Prctl(int option, long arg);
+
+/* Process environment */
+char *Getcwd(char *buf, size_t buflen);
+
+/* Signal control wrappers */
+void (*Signal(int sig, void (*func)(int)))(int);
+void Kill(pid_t pid, int sig);
+void Sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
+void Sigaction(int signum, const struct sigaction *act,
+ struct sigaction *oldact);
+void Sigsuspend(const sigset_t *mask);
+
+/* Process group control wrappers */
+void Setpgid(pid_t pid, pid_t pgid);
+
+/* Stdio wrappers */
+char *Fgets(char *ptr, int n, FILE *stream);
+void Fputs(const char *ptr, FILE *stream);
+
+/* Unix I/O wrappers */
+int Open(const char *pathname, int flags, mode_t mode);
+size_t Read(int fd, void *buf, size_t count);
+size_t Write(int fd, const void *buf, size_t count);
+size_t Writev(int fd, const struct iovec *iov, int iovcnt);
+off_t Lseek(int fildes, off_t offset, int whence);
+void Close(int fd);
+void Ftruncate(int fd, off_t length);
+int Dup(int fd);
+int Dup2(int oldfd, int newfd);
+void Pipe(int fds[2]);
+void Socketpair(int domain, int type, int protocol, int sv[2]);
+int Select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+ struct timeval *timeout);
+int Poll(struct pollfd *fds, nfds_t nfds, int timeout);
+
+/* Directory access (Linux specific) */
+struct linux_dirent {
+ unsigned long d_ino; /* Inode number */
+ unsigned long d_off; /* Offset to next linux_dirent */
+ unsigned short d_reclen; /* Length of this linux_dirent */
+ char d_name[]; /* Filename (null-terminated) */
+};
+
+int Getdents(int fd, struct linux_dirent *dirp, unsigned count);
+
+/* Directory operations */
+void Rename(const char *oldpath, const char *newpath);
+void Unlink(const char *pathname);
+
+/* File metadata access wrapper */
+void Fstat(int fd, struct stat *statbuf);
+void Fstatat(int dirfd, const char *pathname, struct stat *statbuf, int flags);
+size_t Readlink(const char *pathname, char *buf, size_t bufsiz);
+size_t Readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz);
+
+/* Memory mapped files & anonymous memory */
+void *Mmap(void *addr, size_t length, int prot, int flags, int fd,
+ off_t offset);
+void Mprotect(void *addr, size_t len, int prot);
+void Munmap(void *addr, size_t len);
+void Madvise(void *addr, size_t length, int advice);
+
+/* Terminal control */
+void Tcsetpgrp(int fd, pid_t pgrp);
+pid_t Tcgetpgrp(int fd);
+void Tcsetattr(int fd, int action, const struct termios *termios_p);
+void Tcgetattr(int fd, struct termios *termios_p);
+
+/* Setjmp & longjmp implementation without sigprocmask */
+typedef struct {
+ long rbx;
+ long rbp;
+ long r12;
+ long r13;
+ long r14;
+ long r15;
+ void *rsp;
+ void *rip;
+} Jmpbuf[1];
+
+int Setjmp(Jmpbuf env);
+noreturn void Longjmp(Jmpbuf env, int val);
+
+/* Socket interface wrappers. */
+typedef struct sockaddr SA;
+int Socket(int domain, int type, int protocol);
+void Setsockopt(int s, int level, int optname, const void *optval, int optlen);
+void Bind(int sockfd, struct sockaddr *my_addr, int addrlen);
+void Listen(int s, int backlog);
+int Accept(int s, struct sockaddr *addr, socklen_t *addrlen);
+void Connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
+
+/* Protocol-independent wrappers. */
+void Getaddrinfo(const char *node, const char *service,
+ const struct addrinfo *hints, struct addrinfo **res);
+void Getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host,
+ size_t hostlen, char *serv, size_t servlen, int flags);
+int open_clientfd(char *hostname, char *port);
+int Open_clientfd(char *hostname, char *port);
+int open_listenfd(char *port, int backlog);
+int Open_listenfd(char *port, int backlog);
+
+/* POSIX thread control wrappers. */
+
+void Pthread_create(pthread_t *tidp, pthread_attr_t *attrp,
+ void *(*routine)(void *), void *argp);
+void Pthread_cancel(pthread_t tid);
+void Pthread_join(pthread_t tid, void **thread_return);
+void Pthread_detach(pthread_t tid);
+
+/* POSIX semaphore wrappers. */
+void Sem_init(sem_t *sem, int pshared, unsigned value);
+void Sem_destroy(sem_t *sem);
+void Sem_wait(sem_t *sem);
+void Sem_getvalue(sem_t *sem, int *sval);
+void Sem_post(sem_t *sem);
+
+/* POSIX mutex wrappers. */
+void Pthread_mutex_init(pthread_mutex_t *mutex,
+ const pthread_mutexattr_t *mutexattr);
+void Pthread_mutex_destroy(pthread_mutex_t *mutex);
+void Pthread_mutex_lock(pthread_mutex_t *mutex);
+void Pthread_mutex_unlock(pthread_mutex_t *mutex);
+
+/* POSIX conditional variable wrappers. */
+void Pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
+void Pthread_cond_destroy(pthread_cond_t *cond);
+void Pthread_cond_signal(pthread_cond_t *cond);
+void Pthread_cond_broadcast(pthread_cond_t *cond);
+void Pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
+
+/* POSIX reader-writer lock wrappers. */
+void Pthread_rwlock_init(pthread_rwlock_t *rwlock,
+ const pthread_rwlockattr_t *rwlockattr);
+void Pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
+void Pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
+void Pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
+void Pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
+
+#endif /* __CSAPP_H__ */
diff --git a/semestr-5/so/lista2/so21_lista_2/include/queue.h b/semestr-5/so/lista2/so21_lista_2/include/queue.h
new file mode 100644
index 0000000..de4ddc9
--- /dev/null
+++ b/semestr-5/so/lista2/so21_lista_2/include/queue.h
@@ -0,0 +1,587 @@
+/* $NetBSD: queue.h,v 1.74 2019/03/23 12:01:18 maxv Exp $ */
+
+/*
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef _QUEUE_H_
+#define _QUEUE_H_
+
+/*
+ * This file defines five types of data structures: singly-linked lists,
+ * lists, simple queues, tail queues, and circular queues.
+ *
+ * A singly-linked list is headed by a single forward pointer. The
+ * elements are singly linked for minimum space and pointer manipulation
+ * overhead at the expense of O(n) removal for arbitrary elements. New
+ * elements can be added to the list after an existing element or at the
+ * head of the list. Elements being removed from the head of the list
+ * should use the explicit macro for this purpose for optimum
+ * efficiency. A singly-linked list may only be traversed in the forward
+ * direction. Singly-linked lists are ideal for applications with large
+ * datasets and few or no removals or for implementing a LIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A simple queue is headed by a pair of pointers, one the head of the
+ * list and the other to the tail of the list. The elements are singly
+ * linked to save space, so elements can only be removed from the
+ * head of the list. New elements can be added to the list after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A simple queue may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+/*
+ * Include the definition of NULL only on NetBSD because sys/null.h
+ * is not available elsewhere. This conditional makes the header
+ * portable and it can simply be dropped verbatim into any system.
+ * The caveat is that on other systems some other header
+ * must provide NULL before the macros can be used.
+ */
+
+/*
+ * Singly-linked List definitions.
+ */
+#define SLIST_HEAD(name, type) \
+ struct name { \
+ struct type *slh_first; /* first element */ \
+ }
+
+#define SLIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define SLIST_ENTRY(type) \
+ struct { \
+ struct type *sle_next; /* next element */ \
+ }
+
+/*
+ * Singly-linked List access methods.
+ */
+#define SLIST_FIRST(head) ((head)->slh_first)
+#define SLIST_END(head) NULL
+#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
+#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
+
+#define SLIST_FOREACH(var, head, field) \
+ for ((var) = (head)->slh_first; (var) != SLIST_END(head); \
+ (var) = (var)->field.sle_next)
+
+#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = SLIST_FIRST((head)); \
+ (var) != SLIST_END(head) && ((tvar) = SLIST_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+/*
+ * Singly-linked List functions.
+ */
+#define SLIST_INIT(head) \
+ do { \
+ (head)->slh_first = SLIST_END(head); \
+ } while (/*CONSTCOND*/ 0)
+
+#define SLIST_INSERT_AFTER(slistelm, elm, field) \
+ do { \
+ (elm)->field.sle_next = (slistelm)->field.sle_next; \
+ (slistelm)->field.sle_next = (elm); \
+ } while (/*CONSTCOND*/ 0)
+
+#define SLIST_INSERT_HEAD(head, elm, field) \
+ do { \
+ (elm)->field.sle_next = (head)->slh_first; \
+ (head)->slh_first = (elm); \
+ } while (/*CONSTCOND*/ 0)
+
+#define SLIST_REMOVE_AFTER(slistelm, field) \
+ do { \
+ (slistelm)->field.sle_next = \
+ SLIST_NEXT(SLIST_NEXT((slistelm), field), field); \
+ } while (/*CONSTCOND*/ 0)
+
+#define SLIST_REMOVE_HEAD(head, field) \
+ do { \
+ (head)->slh_first = (head)->slh_first->field.sle_next; \
+ } while (/*CONSTCOND*/ 0)
+
+#define SLIST_REMOVE(head, elm, type, field) \
+ do { \
+ if ((head)->slh_first == (elm)) { \
+ SLIST_REMOVE_HEAD((head), field); \
+ } else { \
+ struct type *curelm = (head)->slh_first; \
+ while (curelm->field.sle_next != (elm)) \
+ curelm = curelm->field.sle_next; \
+ curelm->field.sle_next = curelm->field.sle_next->field.sle_next; \
+ } \
+ } while (/*CONSTCOND*/ 0)
+
+/*
+ * List definitions.
+ */
+#define LIST_HEAD(name, type) \
+ struct name { \
+ struct type *lh_first; /* first element */ \
+ }
+
+#define LIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define LIST_ENTRY(type) \
+ struct { \
+ struct type *le_next; /* next element */ \
+ struct type **le_prev; /* address of previous next element */ \
+ }
+
+/*
+ * List access methods.
+ */
+#define LIST_FIRST(head) ((head)->lh_first)
+#define LIST_END(head) NULL
+#define LIST_EMPTY(head) ((head)->lh_first == LIST_END(head))
+#define LIST_NEXT(elm, field) ((elm)->field.le_next)
+
+#define LIST_FOREACH(var, head, field) \
+ for ((var) = ((head)->lh_first); (var) != LIST_END(head); \
+ (var) = ((var)->field.le_next))
+
+#define LIST_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = LIST_FIRST((head)); \
+ (var) != LIST_END(head) && ((tvar) = LIST_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+#define LIST_MOVE(head1, head2, field) \
+ do { \
+ LIST_INIT((head2)); \
+ if (!LIST_EMPTY((head1))) { \
+ (head2)->lh_first = (head1)->lh_first; \
+ (head2)->lh_first->field.le_prev = &(head2)->lh_first; \
+ LIST_INIT((head1)); \
+ } \
+ } while (/*CONSTCOND*/ 0)
+
+/*
+ * List functions.
+ */
+#define LIST_INIT(head) \
+ do { \
+ (head)->lh_first = LIST_END(head); \
+ } while (/*CONSTCOND*/ 0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) \
+ do { \
+ if (((elm)->field.le_next = (listelm)->field.le_next) != LIST_END(head)) \
+ (listelm)->field.le_next->field.le_prev = &(elm)->field.le_next; \
+ (listelm)->field.le_next = (elm); \
+ (elm)->field.le_prev = &(listelm)->field.le_next; \
+ } while (/*CONSTCOND*/ 0)
+
+#define LIST_INSERT_BEFORE(listelm, elm, field) \
+ do { \
+ (elm)->field.le_prev = (listelm)->field.le_prev; \
+ (elm)->field.le_next = (listelm); \
+ *(listelm)->field.le_prev = (elm); \
+ (listelm)->field.le_prev = &(elm)->field.le_next; \
+ } while (/*CONSTCOND*/ 0)
+
+#define LIST_INSERT_HEAD(head, elm, field) \
+ do { \
+ if (((elm)->field.le_next = (head)->lh_first) != LIST_END(head)) \
+ (head)->lh_first->field.le_prev = &(elm)->field.le_next; \
+ (head)->lh_first = (elm); \
+ (elm)->field.le_prev = &(head)->lh_first; \
+ } while (/*CONSTCOND*/ 0)
+
+#define LIST_REMOVE(elm, field) \
+ do { \
+ if ((elm)->field.le_next != NULL) \
+ (elm)->field.le_next->field.le_prev = (elm)->field.le_prev; \
+ *(elm)->field.le_prev = (elm)->field.le_next; \
+ } while (/*CONSTCOND*/ 0)
+
+#define LIST_REPLACE(elm, elm2, field) \
+ do { \
+ if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
+ (elm2)->field.le_next->field.le_prev = &(elm2)->field.le_next; \
+ (elm2)->field.le_prev = (elm)->field.le_prev; \
+ *(elm2)->field.le_prev = (elm2); \
+ } while (/*CONSTCOND*/ 0)
+
+/*
+ * Simple queue definitions.
+ */
+#define SIMPLEQ_HEAD(name, type) \
+ struct name { \
+ struct type *sqh_first; /* first element */ \
+ struct type **sqh_last; /* addr of last next element */ \
+ }
+
+#define SIMPLEQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).sqh_first }
+
+#define SIMPLEQ_ENTRY(type) \
+ struct { \
+ struct type *sqe_next; /* next element */ \
+ }
+
+/*
+ * Simple queue access methods.
+ */
+#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
+#define SIMPLEQ_END(head) NULL
+#define SIMPLEQ_EMPTY(head) ((head)->sqh_first == SIMPLEQ_END(head))
+#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
+
+#define SIMPLEQ_FOREACH(var, head, field) \
+ for ((var) = ((head)->sqh_first); (var) != SIMPLEQ_END(head); \
+ (var) = ((var)->field.sqe_next))
+
+#define SIMPLEQ_FOREACH_SAFE(var, head, field, next) \
+ for ((var) = ((head)->sqh_first); \
+ (var) != SIMPLEQ_END(head) && ((next = ((var)->field.sqe_next)), 1); \
+ (var) = (next))
+
+/*
+ * Simple queue functions.
+ */
+#define SIMPLEQ_INIT(head) \
+ do { \
+ (head)->sqh_first = NULL; \
+ (head)->sqh_last = &(head)->sqh_first; \
+ } while (/*CONSTCOND*/ 0)
+
+#define SIMPLEQ_INSERT_HEAD(head, elm, field) \
+ do { \
+ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (head)->sqh_first = (elm); \
+ } while (/*CONSTCOND*/ 0)
+
+#define SIMPLEQ_INSERT_TAIL(head, elm, field) \
+ do { \
+ (elm)->field.sqe_next = NULL; \
+ *(head)->sqh_last = (elm); \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ } while (/*CONSTCOND*/ 0)
+
+#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) \
+ do { \
+ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL) \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (listelm)->field.sqe_next = (elm); \
+ } while (/*CONSTCOND*/ 0)
+
+#define SIMPLEQ_REMOVE_HEAD(head, field) \
+ do { \
+ if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
+ (head)->sqh_last = &(head)->sqh_first; \
+ } while (/*CONSTCOND*/ 0)
+
+#define SIMPLEQ_REMOVE_AFTER(head, elm, field) \
+ do { \
+ if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) == \
+ NULL) \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ } while (/*CONSTCOND*/ 0)
+
+#define SIMPLEQ_REMOVE(head, elm, type, field) \
+ do { \
+ if ((head)->sqh_first == (elm)) { \
+ SIMPLEQ_REMOVE_HEAD((head), field); \
+ } else { \
+ struct type *curelm = (head)->sqh_first; \
+ while (curelm->field.sqe_next != (elm)) \
+ curelm = curelm->field.sqe_next; \
+ if ((curelm->field.sqe_next = curelm->field.sqe_next->field.sqe_next) == \
+ NULL) \
+ (head)->sqh_last = &(curelm)->field.sqe_next; \
+ } \
+ } while (/*CONSTCOND*/ 0)
+
+#define SIMPLEQ_CONCAT(head1, head2) \
+ do { \
+ if (!SIMPLEQ_EMPTY((head2))) { \
+ *(head1)->sqh_last = (head2)->sqh_first; \
+ (head1)->sqh_last = (head2)->sqh_last; \
+ SIMPLEQ_INIT((head2)); \
+ } \
+ } while (/*CONSTCOND*/ 0)
+
+#define SIMPLEQ_LAST(head, type, field) \
+ (SIMPLEQ_EMPTY((head)) \
+ ? NULL \
+ : ((struct type *)(void *)((char *)((head)->sqh_last) - \
+ offsetof(struct type, field))))
+
+/*
+ * Tail queue definitions.
+ */
+#define _TAILQ_HEAD(name, type, qual) \
+ struct name { \
+ qual type *tqh_first; /* first element */ \
+ qual type *qual *tqh_last; /* addr of last next element */ \
+ }
+#define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type, )
+
+#define TAILQ_HEAD_INITIALIZER(head) \
+ { TAILQ_END(head), &(head).tqh_first }
+
+#define _TAILQ_ENTRY(type, qual) \
+ struct { \
+ qual type *tqe_next; /* next element */ \
+ qual type *qual *tqe_prev; /* address of previous next element */ \
+ }
+#define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type, )
+
+/*
+ * Tail queue access methods.
+ */
+#define TAILQ_FIRST(head) ((head)->tqh_first)
+#define TAILQ_END(head) (NULL)
+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+#define TAILQ_LAST(head, headname) \
+ (*(((struct headname *)(void *)((head)->tqh_last))->tqh_last))
+#define TAILQ_PREV(elm, headname, field) \
+ (*(((struct headname *)(void *)((elm)->field.tqe_prev))->tqh_last))
+#define TAILQ_EMPTY(head) (TAILQ_FIRST(head) == TAILQ_END(head))
+
+#define TAILQ_FOREACH(var, head, field) \
+ for ((var) = ((head)->tqh_first); (var) != TAILQ_END(head); \
+ (var) = ((var)->field.tqe_next))
+
+#define TAILQ_FOREACH_SAFE(var, head, field, next) \
+ for ((var) = ((head)->tqh_first); \
+ (var) != TAILQ_END(head) && ((next) = TAILQ_NEXT(var, field), 1); \
+ (var) = (next))
+
+#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
+ for ((var) = TAILQ_LAST((head), headname); (var) != TAILQ_END(head); \
+ (var) = TAILQ_PREV((var), headname, field))
+
+#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, prev) \
+ for ((var) = TAILQ_LAST((head), headname); \
+ (var) != TAILQ_END(head) && \
+ ((prev) = TAILQ_PREV((var), headname, field), 1); \
+ (var) = (prev))
+
+/*
+ * Tail queue functions.
+ */
+#define TAILQ_INIT(head) \
+ do { \
+ (head)->tqh_first = TAILQ_END(head); \
+ (head)->tqh_last = &(head)->tqh_first; \
+ } while (/*CONSTCOND*/ 0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) \
+ do { \
+ if (((elm)->field.tqe_next = (head)->tqh_first) != TAILQ_END(head)) \
+ (head)->tqh_first->field.tqe_prev = &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (head)->tqh_first = (elm); \
+ (elm)->field.tqe_prev = &(head)->tqh_first; \
+ } while (/*CONSTCOND*/ 0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) \
+ do { \
+ (elm)->field.tqe_next = TAILQ_END(head); \
+ (elm)->field.tqe_prev = (head)->tqh_last; \
+ *(head)->tqh_last = (elm); \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ } while (/*CONSTCOND*/ 0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) \
+ do { \
+ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != \
+ TAILQ_END(head)) \
+ (elm)->field.tqe_next->field.tqe_prev = &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (listelm)->field.tqe_next = (elm); \
+ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
+ } while (/*CONSTCOND*/ 0)
+
+#define TAILQ_INSERT_BEFORE(listelm, elm, field) \
+ do { \
+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
+ (elm)->field.tqe_next = (listelm); \
+ *(listelm)->field.tqe_prev = (elm); \
+ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
+ } while (/*CONSTCOND*/ 0)
+
+#define TAILQ_REMOVE(head, elm, field) \
+ do { \
+ if (((elm)->field.tqe_next) != TAILQ_END(head)) \
+ (elm)->field.tqe_next->field.tqe_prev = (elm)->field.tqe_prev; \
+ else \
+ (head)->tqh_last = (elm)->field.tqe_prev; \
+ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
+ } while (/*CONSTCOND*/ 0)
+
+#define TAILQ_REPLACE(head, elm, elm2, field) \
+ do { \
+ if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != TAILQ_END(head)) \
+ (elm2)->field.tqe_next->field.tqe_prev = &(elm2)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm2)->field.tqe_next; \
+ (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
+ *(elm2)->field.tqe_prev = (elm2); \
+ } while (/*CONSTCOND*/ 0)
+
+#define TAILQ_CONCAT(head1, head2, field) \
+ do { \
+ if (!TAILQ_EMPTY(head2)) { \
+ *(head1)->tqh_last = (head2)->tqh_first; \
+ (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
+ (head1)->tqh_last = (head2)->tqh_last; \
+ TAILQ_INIT((head2)); \
+ } \
+ } while (/*CONSTCOND*/ 0)
+
+/*
+ * Singly-linked Tail queue declarations.
+ */
+#define STAILQ_HEAD(name, type) \
+ struct name { \
+ struct type *stqh_first; /* first element */ \
+ struct type **stqh_last; /* addr of last next element */ \
+ }
+
+#define STAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).stqh_first }
+
+#define STAILQ_ENTRY(type) \
+ struct { \
+ struct type *stqe_next; /* next element */ \
+ }
+
+/*
+ * Singly-linked Tail queue access methods.
+ */
+#define STAILQ_FIRST(head) ((head)->stqh_first)
+#define STAILQ_END(head) NULL
+#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
+#define STAILQ_EMPTY(head) (STAILQ_FIRST(head) == STAILQ_END(head))
+
+/*
+ * Singly-linked Tail queue functions.
+ */
+#define STAILQ_INIT(head) \
+ do { \
+ (head)->stqh_first = NULL; \
+ (head)->stqh_last = &(head)->stqh_first; \
+ } while (/*CONSTCOND*/ 0)
+
+#define STAILQ_INSERT_HEAD(head, elm, field) \
+ do { \
+ if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \
+ (head)->stqh_last = &(elm)->field.stqe_next; \
+ (head)->stqh_first = (elm); \
+ } while (/*CONSTCOND*/ 0)
+
+#define STAILQ_INSERT_TAIL(head, elm, field) \
+ do { \
+ (elm)->field.stqe_next = NULL; \
+ *(head)->stqh_last = (elm); \
+ (head)->stqh_last = &(elm)->field.stqe_next; \
+ } while (/*CONSTCOND*/ 0)
+
+#define STAILQ_INSERT_AFTER(head, listelm, elm, field) \
+ do { \
+ if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL) \
+ (head)->stqh_last = &(elm)->field.stqe_next; \
+ (listelm)->field.stqe_next = (elm); \
+ } while (/*CONSTCOND*/ 0)
+
+#define STAILQ_REMOVE_HEAD(head, field) \
+ do { \
+ if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \
+ (head)->stqh_last = &(head)->stqh_first; \
+ } while (/*CONSTCOND*/ 0)
+
+#define STAILQ_REMOVE(head, elm, type, field) \
+ do { \
+ if ((head)->stqh_first == (elm)) { \
+ STAILQ_REMOVE_HEAD((head), field); \
+ } else { \
+ struct type *curelm = (head)->stqh_first; \
+ while (curelm->field.stqe_next != (elm)) \
+ curelm = curelm->field.stqe_next; \
+ if ((curelm->field.stqe_next = \
+ curelm->field.stqe_next->field.stqe_next) == NULL) \
+ (head)->stqh_last = &(curelm)->field.stqe_next; \
+ } \
+ } while (/*CONSTCOND*/ 0)
+
+#define STAILQ_FOREACH(var, head, field) \
+ for ((var) = ((head)->stqh_first); (var); (var) = ((var)->field.stqe_next))
+
+#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = STAILQ_FIRST((head)); \
+ (var) && ((tvar) = STAILQ_NEXT((var), field), 1); (var) = (tvar))
+
+#define STAILQ_CONCAT(head1, head2) \
+ do { \
+ if (!STAILQ_EMPTY((head2))) { \
+ *(head1)->stqh_last = (head2)->stqh_first; \
+ (head1)->stqh_last = (head2)->stqh_last; \
+ STAILQ_INIT((head2)); \
+ } \
+ } while (/*CONSTCOND*/ 0)
+
+#define STAILQ_LAST(head, type, field) \
+ (STAILQ_EMPTY((head)) \
+ ? NULL \
+ : ((struct type *)(void *)((char *)((head)->stqh_last) - \
+ offsetof(struct type, field))))
+
+#endif /* !_QUEUE_H_ */
diff --git a/semestr-5/so/lista2/so21_lista_2/include/rio.h b/semestr-5/so/lista2/so21_lista_2/include/rio.h
new file mode 100644
index 0000000..bd62723
--- /dev/null
+++ b/semestr-5/so/lista2/so21_lista_2/include/rio.h
@@ -0,0 +1,27 @@
+#ifndef _RIO_H_
+#define _RIO_H_
+
+/* Persistent state for the robust I/O (Rio) package */
+#define RIO_BUFSIZE 8192
+
+typedef struct {
+ int rio_fd; /* Descriptor for this internal buf */
+ int rio_cnt; /* Unread bytes in internal buf */
+ char *rio_bufptr; /* Next unread byte in internal buf */
+ char rio_buf[RIO_BUFSIZE]; /* Internal buffer */
+} rio_t;
+
+/* Rio (Robust I/O) package */
+ssize_t rio_readn(int fd, void *usrbuf, size_t n);
+ssize_t rio_writen(int fd, const void *usrbuf, size_t n);
+void rio_readinitb(rio_t *rp, int fd);
+ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n);
+ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen);
+
+/* Wrappers that exit on failure */
+ssize_t Rio_readn(int fd, void *ptr, size_t nbytes);
+void Rio_writen(int fd, const void *usrbuf, size_t n);
+ssize_t Rio_readnb(rio_t *rp, void *usrbuf, size_t n);
+ssize_t Rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen);
+
+#endif /* !_RIO_H_ */
diff --git a/semestr-5/so/lista2/so21_lista_2/include/terminal.h b/semestr-5/so/lista2/so21_lista_2/include/terminal.h
new file mode 100644
index 0000000..832358e
--- /dev/null
+++ b/semestr-5/so/lista2/so21_lista_2/include/terminal.h
@@ -0,0 +1,27 @@
+#ifndef _TERMINAL_H_
+#define _TERMINAL_H_
+
+int tty_open(void);
+void tty_curpos(int fd, int *x, int *y);
+
+/* https://en.wikipedia.org/wiki/ANSI_escape_code#Terminal_output_sequences */
+
+#define ESC "\033"
+#define CSI ESC "["
+
+#define CUU(n) CSI #n "A" /* Cursor Up */
+#define CUD(n) CSI #n "B" /* Cursor Down */
+#define CUF(n) CSI #n "C" /* Cursor Forward */
+#define CUB(n) CSI #n "D" /* Cursor Back */
+#define CNL(n) CSI #n "E" /* Cursor Next Line */
+#define CPL(n) CSI #n "F" /* Cursor Previous Line */
+#define CHA(n) CSI #n "G" /* Cursor Horizontal Absolute */
+#define CUP(n, m) CSI #n ";" #m "H" /* Cursor Position */
+#define ED(n) CSI #n "J" /* Erase in Display */
+#define EL(n) CSI #n "K" /* Erase in Line */
+#define SU(n) CSI #n "S" /* Scroll Up Scroll */
+#define SD(n) CSI #n "T" /* Scroll Down Scroll */
+#define CPR() CSI "6n" /* Cursor Position Report */
+#define SGR(x) CSI x "m"
+
+#endif /* !_ANSICODES_H_ */
diff --git a/semestr-5/so/lista2/so21_lista_2/include/tree.h b/semestr-5/so/lista2/so21_lista_2/include/tree.h
new file mode 100644
index 0000000..3355bad
--- /dev/null
+++ b/semestr-5/so/lista2/so21_lista_2/include/tree.h
@@ -0,0 +1,735 @@
+/* $NetBSD: tree.h,v 1.20 2013/09/14 13:20:45 joerg Exp $ */
+/* $OpenBSD: tree.h,v 1.13 2011/07/09 00:19:45 pirofti Exp $ */
+/*
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TREE_H_
+#define _TREE_H_
+
+/*
+ * This file defines data structures for different types of trees:
+ * splay trees and red-black trees.
+ *
+ * A splay tree is a self-organizing data structure. Every operation
+ * on the tree causes a splay to happen. The splay moves the requested
+ * node to the root of the tree and partly rebalances it.
+ *
+ * This has the benefit that request locality causes faster lookups as
+ * the requested nodes move to the top of the tree. On the other hand,
+ * every lookup causes memory writes.
+ *
+ * The Balance Theorem bounds the total access time for m operations
+ * and n inserts on an initially empty tree as O((m + n)lg n). The
+ * amortized cost for a sequence of m accesses to a splay tree is O(lg n);
+ *
+ * A red-black tree is a binary search tree with the node color as an
+ * extra attribute. It fulfills a set of conditions:
+ * - every search path from the root to a leaf consists of the
+ * same number of black nodes,
+ * - each red node (except for the root) has a black parent,
+ * - each leaf node is black.
+ *
+ * Every operation on a red-black tree is bounded as O(lg n).
+ * The maximum height of a red-black tree is 2lg (n+1).
+ */
+
+#define SPLAY_HEAD(name, type) \
+ struct name { \
+ struct type *sph_root; /* root of the tree */ \
+ }
+
+#define SPLAY_INITIALIZER(root) \
+ { NULL }
+
+#define SPLAY_INIT(root) \
+ do { \
+ (root)->sph_root = NULL; \
+ } while (/*CONSTCOND*/ 0)
+
+#define SPLAY_ENTRY(type) \
+ struct { \
+ struct type *spe_left; /* left element */ \
+ struct type *spe_right; /* right element */ \
+ }
+
+#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
+#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
+#define SPLAY_ROOT(head) (head)->sph_root
+#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
+
+/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
+#define SPLAY_ROTATE_RIGHT(head, tmp, field) \
+ do { \
+ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
+ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
+ (head)->sph_root = tmp; \
+ } while (/*CONSTCOND*/ 0)
+
+#define SPLAY_ROTATE_LEFT(head, tmp, field) \
+ do { \
+ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
+ SPLAY_LEFT(tmp, field) = (head)->sph_root; \
+ (head)->sph_root = tmp; \
+ } while (/*CONSTCOND*/ 0)
+
+#define SPLAY_LINKLEFT(head, tmp, field) \
+ do { \
+ SPLAY_LEFT(tmp, field) = (head)->sph_root; \
+ tmp = (head)->sph_root; \
+ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
+ } while (/*CONSTCOND*/ 0)
+
+#define SPLAY_LINKRIGHT(head, tmp, field) \
+ do { \
+ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
+ tmp = (head)->sph_root; \
+ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
+ } while (/*CONSTCOND*/ 0)
+
+#define SPLAY_ASSEMBLE(head, node, left, right, field) \
+ do { \
+ SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
+ SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field); \
+ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
+ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
+ } while (/*CONSTCOND*/ 0)
+
+/* Generates prototypes and inline functions */
+
+#define SPLAY_PROTOTYPE(name, type, field, cmp) \
+ void name##_SPLAY(struct name *, struct type *); \
+ void name##_SPLAY_MINMAX(struct name *, int); \
+ struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
+ struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
+ \
+ /* Finds the node with the same key as elm */ \
+ static __inline struct type *name##_SPLAY_FIND(struct name *head, \
+ struct type *elm) { \
+ if (SPLAY_EMPTY(head)) \
+ return (NULL); \
+ name##_SPLAY(head, elm); \
+ if ((cmp)(elm, (head)->sph_root) == 0) \
+ return (head->sph_root); \
+ return (NULL); \
+ } \
+ \
+ static __inline __unused struct type *name##_SPLAY_NEXT(struct name *head, \
+ struct type *elm) { \
+ name##_SPLAY(head, elm); \
+ if (SPLAY_RIGHT(elm, field) != NULL) { \
+ elm = SPLAY_RIGHT(elm, field); \
+ while (SPLAY_LEFT(elm, field) != NULL) { \
+ elm = SPLAY_LEFT(elm, field); \
+ } \
+ } else \
+ elm = NULL; \
+ return (elm); \
+ } \
+ \
+ static __unused __inline struct type *name##_SPLAY_MIN_MAX( \
+ struct name *head, int val) { \
+ name##_SPLAY_MINMAX(head, val); \
+ return (SPLAY_ROOT(head)); \
+ }
+
+/* Main splay operation.
+ * Moves node close to the key of elm to top
+ */
+#define SPLAY_GENERATE(name, type, field, cmp) \
+ struct type *name##_SPLAY_INSERT(struct name *head, struct type *elm) { \
+ if (SPLAY_EMPTY(head)) { \
+ SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
+ } else { \
+ int __comp; \
+ name##_SPLAY(head, elm); \
+ __comp = (cmp)(elm, (head)->sph_root); \
+ if (__comp < 0) { \
+ SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field); \
+ SPLAY_RIGHT(elm, field) = (head)->sph_root; \
+ SPLAY_LEFT((head)->sph_root, field) = NULL; \
+ } else if (__comp > 0) { \
+ SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field); \
+ SPLAY_LEFT(elm, field) = (head)->sph_root; \
+ SPLAY_RIGHT((head)->sph_root, field) = NULL; \
+ } else \
+ return ((head)->sph_root); \
+ } \
+ (head)->sph_root = (elm); \
+ return (NULL); \
+ } \
+ \
+ struct type *name##_SPLAY_REMOVE(struct name *head, struct type *elm) { \
+ struct type *__tmp; \
+ if (SPLAY_EMPTY(head)) \
+ return (NULL); \
+ name##_SPLAY(head, elm); \
+ if ((cmp)(elm, (head)->sph_root) == 0) { \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
+ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
+ } else { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
+ name##_SPLAY(head, elm); \
+ SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
+ } \
+ return (elm); \
+ } \
+ return (NULL); \
+ } \
+ \
+ void name##_SPLAY(struct name *head, struct type *elm) { \
+ struct type __node, *__left, *__right, *__tmp; \
+ int __comp; \
+ \
+ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \
+ __left = __right = &__node; \
+ \
+ while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \
+ if (__comp < 0) { \
+ __tmp = SPLAY_LEFT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if ((cmp)(elm, __tmp) < 0) { \
+ SPLAY_ROTATE_RIGHT(head, __tmp, field); \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL) \
+ break; \
+ } \
+ SPLAY_LINKLEFT(head, __right, field); \
+ } else if (__comp > 0) { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if ((cmp)(elm, __tmp) > 0) { \
+ SPLAY_ROTATE_LEFT(head, __tmp, field); \
+ if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \
+ break; \
+ } \
+ SPLAY_LINKRIGHT(head, __left, field); \
+ } \
+ } \
+ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
+ } \
+ \
+ /* Splay with either the minimum or the maximum element \
+ * Used to find minimum or maximum element in tree. \
+ */ \
+ void name##_SPLAY_MINMAX(struct name *head, int __comp) { \
+ struct type __node, *__left, *__right, *__tmp; \
+ \
+ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \
+ __left = __right = &__node; \
+ \
+ while (1) { \
+ if (__comp < 0) { \
+ __tmp = SPLAY_LEFT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if (__comp < 0) { \
+ SPLAY_ROTATE_RIGHT(head, __tmp, field); \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL) \
+ break; \
+ } \
+ SPLAY_LINKLEFT(head, __right, field); \
+ } else if (__comp > 0) { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if (__comp > 0) { \
+ SPLAY_ROTATE_LEFT(head, __tmp, field); \
+ if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \
+ break; \
+ } \
+ SPLAY_LINKRIGHT(head, __left, field); \
+ } \
+ } \
+ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
+ }
+
+#define SPLAY_NEGINF -1
+#define SPLAY_INF 1
+
+#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
+#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
+#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
+#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
+#define SPLAY_MIN(name, x) \
+ (SPLAY_EMPTY(x) ? NULL : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
+#define SPLAY_MAX(name, x) \
+ (SPLAY_EMPTY(x) ? NULL : name##_SPLAY_MIN_MAX(x, SPLAY_INF))
+
+#define SPLAY_FOREACH(x, name, head) \
+ for ((x) = SPLAY_MIN(name, head); (x) != NULL; \
+ (x) = SPLAY_NEXT(name, head, x))
+
+/* Macros that define a red-black tree */
+#define RB_HEAD(name, type) \
+ struct name { \
+ struct type *rbh_root; /* root of the tree */ \
+ }
+
+#define RB_INITIALIZER(root) \
+ { NULL }
+
+#define RB_INIT(root) \
+ do { \
+ (root)->rbh_root = NULL; \
+ } while (/*CONSTCOND*/ 0)
+
+#define RB_BLACK 0
+#define RB_RED 1
+#define RB_ENTRY(type) \
+ struct { \
+ struct type *rbe_left; /* left element */ \
+ struct type *rbe_right; /* right element */ \
+ struct type *rbe_parent; /* parent element */ \
+ int rbe_color; /* node color */ \
+ }
+
+#define RB_LEFT(elm, field) (elm)->field.rbe_left
+#define RB_RIGHT(elm, field) (elm)->field.rbe_right
+#define RB_PARENT(elm, field) (elm)->field.rbe_parent
+#define RB_COLOR(elm, field) (elm)->field.rbe_color
+#define RB_ROOT(head) (head)->rbh_root
+#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
+
+#define RB_SET(elm, parent, field) \
+ do { \
+ RB_PARENT(elm, field) = parent; \
+ RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
+ RB_COLOR(elm, field) = RB_RED; \
+ } while (/*CONSTCOND*/ 0)
+
+#define RB_SET_BLACKRED(black, red, field) \
+ do { \
+ RB_COLOR(black, field) = RB_BLACK; \
+ RB_COLOR(red, field) = RB_RED; \
+ } while (/*CONSTCOND*/ 0)
+
+#ifndef RB_AUGMENT
+#define RB_AUGMENT(x) \
+ do { \
+ } while (/*CONSTCOND*/ 0)
+#endif
+
+#define RB_ROTATE_LEFT(head, elm, tmp, field) \
+ do { \
+ (tmp) = RB_RIGHT(elm, field); \
+ if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \
+ RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
+ } \
+ RB_AUGMENT(elm); \
+ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
+ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
+ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
+ else \
+ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
+ } else \
+ (head)->rbh_root = (tmp); \
+ RB_LEFT(tmp, field) = (elm); \
+ RB_PARENT(elm, field) = (tmp); \
+ RB_AUGMENT(tmp); \
+ if ((RB_PARENT(tmp, field))) \
+ RB_AUGMENT(RB_PARENT(tmp, field)); \
+ } while (/*CONSTCOND*/ 0)
+
+#define RB_ROTATE_RIGHT(head, elm, tmp, field) \
+ do { \
+ (tmp) = RB_LEFT(elm, field); \
+ if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \
+ RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
+ } \
+ RB_AUGMENT(elm); \
+ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
+ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
+ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
+ else \
+ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
+ } else \
+ (head)->rbh_root = (tmp); \
+ RB_RIGHT(tmp, field) = (elm); \
+ RB_PARENT(elm, field) = (tmp); \
+ RB_AUGMENT(tmp); \
+ if ((RB_PARENT(tmp, field))) \
+ RB_AUGMENT(RB_PARENT(tmp, field)); \
+ } while (/*CONSTCOND*/ 0)
+
+/* Generates prototypes and inline functions */
+#define RB_PROTOTYPE(name, type, field, cmp) \
+ RB_PROTOTYPE_INTERNAL(name, type, field, cmp, )
+#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \
+ RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static)
+#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \
+ attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \
+ attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, \
+ struct type *); \
+ attr struct type *name##_RB_REMOVE(struct name *, struct type *); \
+ attr struct type *name##_RB_INSERT(struct name *, struct type *); \
+ attr struct type *name##_RB_FIND(struct name *, struct type *); \
+ attr struct type *name##_RB_NFIND(struct name *, struct type *); \
+ attr struct type *name##_RB_NEXT(struct type *); \
+ attr struct type *name##_RB_PREV(struct type *); \
+ attr struct type *name##_RB_MINMAX(struct name *, int);
+
+/* Main rb operation.
+ * Moves node close to the key of elm to top
+ */
+#define RB_GENERATE(name, type, field, cmp) \
+ RB_GENERATE_INTERNAL(name, type, field, cmp, )
+#define RB_GENERATE_STATIC(name, type, field, cmp) \
+ RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static)
+#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
+ attr void name##_RB_INSERT_COLOR(struct name *head, struct type *elm) { \
+ struct type *parent, *gparent, *tmp; \
+ while ((parent = RB_PARENT(elm, field)) != NULL && \
+ RB_COLOR(parent, field) == RB_RED) { \
+ gparent = RB_PARENT(parent, field); \
+ if (parent == RB_LEFT(gparent, field)) { \
+ tmp = RB_RIGHT(gparent, field); \
+ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
+ RB_COLOR(tmp, field) = RB_BLACK; \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ elm = gparent; \
+ continue; \
+ } \
+ if (RB_RIGHT(parent, field) == elm) { \
+ RB_ROTATE_LEFT(head, parent, tmp, field); \
+ tmp = parent; \
+ parent = elm; \
+ elm = tmp; \
+ } \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ RB_ROTATE_RIGHT(head, gparent, tmp, field); \
+ } else { \
+ tmp = RB_LEFT(gparent, field); \
+ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
+ RB_COLOR(tmp, field) = RB_BLACK; \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ elm = gparent; \
+ continue; \
+ } \
+ if (RB_LEFT(parent, field) == elm) { \
+ RB_ROTATE_RIGHT(head, parent, tmp, field); \
+ tmp = parent; \
+ parent = elm; \
+ elm = tmp; \
+ } \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ RB_ROTATE_LEFT(head, gparent, tmp, field); \
+ } \
+ } \
+ RB_COLOR(head->rbh_root, field) = RB_BLACK; \
+ } \
+ \
+ attr void name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, \
+ struct type *elm) { \
+ struct type *tmp; \
+ while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
+ elm != RB_ROOT(head)) { \
+ if (RB_LEFT(parent, field) == elm) { \
+ tmp = RB_RIGHT(parent, field); \
+ if (RB_COLOR(tmp, field) == RB_RED) { \
+ RB_SET_BLACKRED(tmp, parent, field); \
+ RB_ROTATE_LEFT(head, parent, tmp, field); \
+ tmp = RB_RIGHT(parent, field); \
+ } \
+ if ((RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \
+ (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) { \
+ RB_COLOR(tmp, field) = RB_RED; \
+ elm = parent; \
+ parent = RB_PARENT(elm, field); \
+ } else { \
+ if (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) { \
+ struct type *oleft; \
+ if ((oleft = RB_LEFT(tmp, field)) != NULL) \
+ RB_COLOR(oleft, field) = RB_BLACK; \
+ RB_COLOR(tmp, field) = RB_RED; \
+ RB_ROTATE_RIGHT(head, tmp, oleft, field); \
+ tmp = RB_RIGHT(parent, field); \
+ } \
+ RB_COLOR(tmp, field) = RB_COLOR(parent, field); \
+ RB_COLOR(parent, field) = RB_BLACK; \
+ if (RB_RIGHT(tmp, field)) \
+ RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK; \
+ RB_ROTATE_LEFT(head, parent, tmp, field); \
+ elm = RB_ROOT(head); \
+ break; \
+ } \
+ } else { \
+ tmp = RB_LEFT(parent, field); \
+ if (RB_COLOR(tmp, field) == RB_RED) { \
+ RB_SET_BLACKRED(tmp, parent, field); \
+ RB_ROTATE_RIGHT(head, parent, tmp, field); \
+ tmp = RB_LEFT(parent, field); \
+ } \
+ if ((RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \
+ (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) { \
+ RB_COLOR(tmp, field) = RB_RED; \
+ elm = parent; \
+ parent = RB_PARENT(elm, field); \
+ } else { \
+ if (RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) { \
+ struct type *oright; \
+ if ((oright = RB_RIGHT(tmp, field)) != NULL) \
+ RB_COLOR(oright, field) = RB_BLACK; \
+ RB_COLOR(tmp, field) = RB_RED; \
+ RB_ROTATE_LEFT(head, tmp, oright, field); \
+ tmp = RB_LEFT(parent, field); \
+ } \
+ RB_COLOR(tmp, field) = RB_COLOR(parent, field); \
+ RB_COLOR(parent, field) = RB_BLACK; \
+ if (RB_LEFT(tmp, field)) \
+ RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK; \
+ RB_ROTATE_RIGHT(head, parent, tmp, field); \
+ elm = RB_ROOT(head); \
+ break; \
+ } \
+ } \
+ } \
+ if (elm) \
+ RB_COLOR(elm, field) = RB_BLACK; \
+ } \
+ \
+ attr struct type *name##_RB_REMOVE(struct name *head, struct type *elm) { \
+ struct type *child, *parent, *old = elm; \
+ int color; \
+ if (RB_LEFT(elm, field) == NULL) \
+ child = RB_RIGHT(elm, field); \
+ else if (RB_RIGHT(elm, field) == NULL) \
+ child = RB_LEFT(elm, field); \
+ else { \
+ struct type *left; \
+ elm = RB_RIGHT(elm, field); \
+ while ((left = RB_LEFT(elm, field)) != NULL) \
+ elm = left; \
+ child = RB_RIGHT(elm, field); \
+ parent = RB_PARENT(elm, field); \
+ color = RB_COLOR(elm, field); \
+ if (child) \
+ RB_PARENT(child, field) = parent; \
+ if (parent) { \
+ if (RB_LEFT(parent, field) == elm) \
+ RB_LEFT(parent, field) = child; \
+ else \
+ RB_RIGHT(parent, field) = child; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = child; \
+ if (RB_PARENT(elm, field) == old) \
+ parent = elm; \
+ (elm)->field = (old)->field; \
+ if (RB_PARENT(old, field)) { \
+ if (RB_LEFT(RB_PARENT(old, field), field) == old) \
+ RB_LEFT(RB_PARENT(old, field), field) = elm; \
+ else \
+ RB_RIGHT(RB_PARENT(old, field), field) = elm; \
+ RB_AUGMENT(RB_PARENT(old, field)); \
+ } else \
+ RB_ROOT(head) = elm; \
+ RB_PARENT(RB_LEFT(old, field), field) = elm; \
+ if (RB_RIGHT(old, field)) \
+ RB_PARENT(RB_RIGHT(old, field), field) = elm; \
+ if (parent) { \
+ left = parent; \
+ do { \
+ RB_AUGMENT(left); \
+ } while ((left = RB_PARENT(left, field)) != NULL); \
+ } \
+ goto color; \
+ } \
+ parent = RB_PARENT(elm, field); \
+ color = RB_COLOR(elm, field); \
+ if (child) \
+ RB_PARENT(child, field) = parent; \
+ if (parent) { \
+ if (RB_LEFT(parent, field) == elm) \
+ RB_LEFT(parent, field) = child; \
+ else \
+ RB_RIGHT(parent, field) = child; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = child; \
+ color: \
+ if (color == RB_BLACK) \
+ name##_RB_REMOVE_COLOR(head, parent, child); \
+ return (old); \
+ } \
+ \
+ /* Inserts a node into the RB tree */ \
+ attr struct type *name##_RB_INSERT(struct name *head, struct type *elm) { \
+ struct type *tmp; \
+ struct type *parent = NULL; \
+ int comp = 0; \
+ tmp = RB_ROOT(head); \
+ while (tmp) { \
+ parent = tmp; \
+ comp = (cmp)(elm, parent); \
+ if (comp < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ RB_SET(elm, parent, field); \
+ if (parent != NULL) { \
+ if (comp < 0) \
+ RB_LEFT(parent, field) = elm; \
+ else \
+ RB_RIGHT(parent, field) = elm; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = elm; \
+ name##_RB_INSERT_COLOR(head, elm); \
+ return (NULL); \
+ } \
+ \
+ /* Finds the node with the same key as elm */ \
+ attr struct type *name##_RB_FIND(struct name *head, struct type *elm) { \
+ struct type *tmp = RB_ROOT(head); \
+ int comp; \
+ while (tmp) { \
+ comp = cmp(elm, tmp); \
+ if (comp < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ return (NULL); \
+ } \
+ \
+ /* Finds the first node greater than or equal to the search key */ \
+ attr struct type *name##_RB_NFIND(struct name *head, struct type *elm) { \
+ struct type *tmp = RB_ROOT(head); \
+ struct type *res = NULL; \
+ int comp; \
+ while (tmp) { \
+ comp = cmp(elm, tmp); \
+ if (comp < 0) { \
+ res = tmp; \
+ tmp = RB_LEFT(tmp, field); \
+ } else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ return (res); \
+ } \
+ \
+ /* ARGSUSED */ \
+ attr struct type *name##_RB_NEXT(struct type *elm) { \
+ if (RB_RIGHT(elm, field)) { \
+ elm = RB_RIGHT(elm, field); \
+ while (RB_LEFT(elm, field)) \
+ elm = RB_LEFT(elm, field); \
+ } else { \
+ if (RB_PARENT(elm, field) && \
+ (elm == RB_LEFT(RB_PARENT(elm, field), field))) \
+ elm = RB_PARENT(elm, field); \
+ else { \
+ while (RB_PARENT(elm, field) && \
+ (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
+ elm = RB_PARENT(elm, field); \
+ elm = RB_PARENT(elm, field); \
+ } \
+ } \
+ return (elm); \
+ } \
+ \
+ /* ARGSUSED */ \
+ attr struct type *name##_RB_PREV(struct type *elm) { \
+ if (RB_LEFT(elm, field)) { \
+ elm = RB_LEFT(elm, field); \
+ while (RB_RIGHT(elm, field)) \
+ elm = RB_RIGHT(elm, field); \
+ } else { \
+ if (RB_PARENT(elm, field) && \
+ (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
+ elm = RB_PARENT(elm, field); \
+ else { \
+ while (RB_PARENT(elm, field) && \
+ (elm == RB_LEFT(RB_PARENT(elm, field), field))) \
+ elm = RB_PARENT(elm, field); \
+ elm = RB_PARENT(elm, field); \
+ } \
+ } \
+ return (elm); \
+ } \
+ \
+ attr struct type *name##_RB_MINMAX(struct name *head, int val) { \
+ struct type *tmp = RB_ROOT(head); \
+ struct type *parent = NULL; \
+ while (tmp) { \
+ parent = tmp; \
+ if (val < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else \
+ tmp = RB_RIGHT(tmp, field); \
+ } \
+ return (parent); \
+ }
+
+#define RB_NEGINF -1
+#define RB_INF 1
+
+#define RB_INSERT(name, x, y) CONCAT(name,_RB_INSERT(x, y))
+#define RB_REMOVE(name, x, y) CONCAT(name,_RB_REMOVE(x, y))
+#define RB_FIND(name, x, y) CONCAT(name,_RB_FIND(x, y))
+#define RB_NFIND(name, x, y) CONCAT(name,_RB_NFIND(x, y))
+#define RB_NEXT(name, x, y) CONCAT(name,_RB_NEXT(y))
+#define RB_PREV(name, x, y) CONCAT(name,_RB_PREV(y))
+#define RB_MIN(name, x) CONCAT(name,_RB_MINMAX(x, RB_NEGINF))
+#define RB_MAX(name, x) CONCAT(name,_RB_MINMAX(x, RB_INF))
+
+#define RB_FOREACH(x, name, head) \
+ for ((x) = RB_MIN(name, head); (x) != NULL; (x) = name##_RB_NEXT(x))
+
+#define RB_FOREACH_FROM(x, name, y) \
+ for ((x) = (y); ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
+ (x) = (y))
+
+#define RB_FOREACH_SAFE(x, name, head, y) \
+ for ((x) = RB_MIN(name, head); \
+ ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); (x) = (y))
+
+#define RB_FOREACH_REVERSE(x, name, head) \
+ for ((x) = RB_MAX(name, head); (x) != NULL; (x) = name##_RB_PREV(x))
+
+#define RB_FOREACH_REVERSE_FROM(x, name, y) \
+ for ((x) = (y); ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
+ (x) = (y))
+
+#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \
+ for ((x) = RB_MAX(name, head); \
+ ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); (x) = (y))
+
+#endif /* !_TREE_H_ */
diff --git a/semestr-5/so/lista2/so21_lista_2/reaper.c b/semestr-5/so/lista2/so21_lista_2/reaper.c
new file mode 100644
index 0000000..da43a2f
--- /dev/null
+++ b/semestr-5/so/lista2/so21_lista_2/reaper.c
@@ -0,0 +1,59 @@
+#include "csapp.h"
+
+static pid_t spawn(void (*fn)(void)) {
+ pid_t pid = Fork();
+ if (pid == 0) {
+ fn();
+ printf("(%d) I'm done!\n", getpid());
+ exit(EXIT_SUCCESS);
+ }
+ return pid;
+}
+
+static void grandchild(void) {
+ printf("(%d) Waiting for signal!\n", getpid());
+ pause();
+ printf("(%d) Got the signal!\n", getpid());
+}
+
+static void child(void) {
+ pid_t pid;
+ setpgid(0, 0);
+ pid = spawn(grandchild);
+ printf("(%d) Grandchild (%d) spawned!\n", getpid(), pid);
+}
+
+/* Runs command "ps -o pid,ppid,pgrp,stat,cmd" using execve(2). */
+static void ps(void) {
+ pid_t pid = Fork();
+ if (pid == 0) {
+ if (execlp("ps", "ps", "-o", "pid,ppid,pgrp,stat,cmd", NULL) < 0) {
+ fprintf(stderr, "Exec error: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ }
+ waitpid(pid, NULL, 0);
+}
+
+int main(void) {
+ /* TODO: Make yourself a reaper. */
+#ifdef LINUX
+ Prctl(PR_SET_CHILD_SUBREAPER, 1);
+#endif
+ printf("(%d) I'm a reaper now!\n", getpid());
+
+ pid_t pid, pgrp;
+ int status;
+
+ /* TODO: Start child and grandchild, then kill child!
+ * Remember that you need to kill all subprocesses before quit. */
+ pid = spawn(child);
+ pgrp = pid;
+ waitpid(pid, &status, 0);
+ ps();
+
+ Kill(-pgrp, SIGINT);
+ pid = wait(&status);
+ printf("Reaped the grandchild (%d), exit code: %d\n", pid, status);
+ return EXIT_SUCCESS;
+}
diff --git a/semestr-5/so/lista2/test.c b/semestr-5/so/lista2/test.c
new file mode 100644
index 0000000..64e4166
--- /dev/null
+++ b/semestr-5/so/lista2/test.c
@@ -0,0 +1,33 @@
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+static void signal_handler(int signum) {
+ if (signum == SIGINT) {
+ write(STDOUT_FILENO, "XD\n", 3);
+ _exit(0);
+ }
+}
+
+
+int main() {
+ signal(SIGINT, signal_handler);
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGINT);
+ // sigfillset(&mask);
+ // sigdelset(&mask, SIGINT);
+ // sigprocmask(SIG_BLOCK, &mask, NULL);
+ // // int *p = NULL;
+ // // sleep(10);
+ // // *p = 1;
+ // // pause();
+ // // abort();
+ // _exit(0);
+ // printf("Lmao\n");
+ // while(1) {}
+ int sig;
+ sigwait(&mask, &sig);
+ printf("sig: %d\n", sig);
+} \ No newline at end of file