# Lista 1
###### tags: `SO2022`
## Deklaracja
:::spoiler
| Zadanie | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|-----------|---|---|---|---|---|---|---|---|
| Deklaracja|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:| :heavy_check_mark:| :( |:heavy_check_mark:|:white_check_mark:| :heavy_check_mark:|
:::
## Zadanie 1

//:::spoiler
* `ps -eo user,pid,ppid,pgid,tid,pri,stat,wchan,cmd | less`
* #### Na wydruku zidentyfikuj identyfikator procesu, identyfikator grupy procesów, identyfikator rodzica oraz właściciela procesu

- **ID procesu** - `pid` (unikalna liczba, dzięki której łatwiej jest zidentyfikować każdy proces)
- **ID rodzica** - `ppid` (identyfikator procesu, który za pomocą `form()` utworył procesy dzieci)
- **ID grupy procesów** - `pgid` (zbiór jednego lub większej ilości procesów, które mogą razem otrzymywać sygnały)
- **Właściciel** - `user` (użytkownik, który uruchomił proces i posiada pełne uprawnienia do kontrolowania ich, np. zatrzymania lub zabijania)
* #### Kto jest rodzicem procesu init?
**PPID 0** - placeholder, oznaczane nim są procesy nieposiadające rodzica
* #### Wskaż, które z wyświetlonych zadań są wątkami jądra.
**Wątkami jądra** (czyli wątki wykonujące kod jądra, nie sa one powiązane z procesami z przestrzeni użytkownika, nie używają również pamięci) są te których `PPID=2` czyli wskazuje na `kthreadd`
Dzieje się tak dlatego, że wątki jądra mogą zostać uruchomione przed wszystkim procesami z przestrzeniu użytkownika
Dodatkowo ich nazwa jest opatrzona `[]`
* #### Jakie jest znaczenie poszczególnych znaków w kolumnie STAT?
```
**PROCESS STATE CODES**
Here are the different values that the s, stat and state output specifiers (header "STAT" or
"S") will display to describe the state of a process:
D uninterruptible sleep (usually IO)
I Idle kernel thread
R running or runnable (on run queue)
S interruptible sleep (waiting for an event to complete)
T stopped by job control signal
t stopped by debugger during the tracing
W paging (not valid since the 2.6.xx kernel)
X dead (should never be seen)
Z defunct ("zombie") process, terminated but not reaped by its parent
For BSD formats and when the stat keyword is used, additional characters may be displayed:
< high-priority (not nice to other users)
N low-priority (nice to other users)
L has pages locked into memory (for real-time and custom IO)
s is a session leader
l is multi-threaded (using CLONE_THREAD, like NPTL pthreads do)
+ is in the foreground process group
```
* #### Wyświetl drzewiastą reprezentację hierarchii procesów poleceniem `pstree | less` – które z zadań są wątkami?
```
init-+- {abc} - wątek abc
|- x * [{abc}] - x wątków abc
|- xyz - proces xyz
`- x * [xyz] - x procesów xyz
```
//:::
## Zadanie 2

//:::spoiler
* #### Jak jądro systemu reaguje na sytuację kiedy proces staje się sierotą?
```
When we die, we re-parent all our children, and try to:
1. give them to another thread in our thread group, if such a member exists
2. give it to the first ancestor process which prctl'd itself as a child_subreaper for its children (like a service manager)
3. give it to the init process (PID 1) in our pid namespace
Staramy się przekazać proces do dziadka a jesli się nie uda to przekazujem do init
```
* #### W jaki sposób pogrzebać proces, który wszedł w stan zombie?
Jeśli rodzic nie pogrzebie dziecka będzie ono w systemie aż do chwili kiedy rodzic umrze. Wtedy też wykona się ponowne przypisanie rodzica
W momencie kiedy **Init** stanie się rodzicem proces zostanie po pewnym czasie zakończony, ponieważ **Init** co pewien czas wykonuje wywołanie systemowe `wait()` czyszcząc w ten sposób system z zombie
* #### Czemu proces nie może sam siebie pogrzebać?
Proces po zakończeniu zwraca status zakonczenia dziłania, jakiś proces musi go przejąć i zwolnić to miejsce w pamięci
* #### Zauważ, że proces może, przy pomocy `waitpid(2)`, czekać na zmianę stanu wyłącznie swoich dzieci. Co złego mogłoby się stać, gdyby znieść to ograniczenie?
* ##### Dziecko może czekać na zmianę stanu swojego rodzica:
* Rodzic i dziecko mogą czekać na siebie nawzajem przez co nigdy by się nie wykonały bo powstałby deadlock
* ##### Wiele procesów oczekuje na zmianę stanu jednego procesu:
* Przy zakończeniu procesu każdy rodzic próbuje grzebać syna, przez co większość otrzymuje błąd
//:::
## Zadanie 3

//:::spoiler
* #### Do czego służy system plików `proc(5)` w systemie Linux?
Pseudosystem plików podający informacje o zasobach systemowych, procesach, hardware itp., udostępnia interfejs do struktur danych kernela, montowany zazwyczaj automatycznie przez system w katalogu `/proc`
przykłady danych:
* **/proc/[pid]** - informacje o procesie o danym pid
* **/proc/[tid]** - jw. tylko info o wątku o danym tid
* **/proc/self** - link symboliczny do własnego /proc/[pid] procesu
* **/proc/thread-self** - link symboliczny do własnego /proc/self/task/tid wątku
* #### Dla wybranego przez siebie procesuo identyfikatorze pid wydrukuj zawartość katalogu `/proc/pid`. Wyświetl plik zawierający *argumenty programu* (parametry przekazane do programu w momencie jego wywołania - argc, argv[] z pliku **/proc/[pid]/cmdline**) oraz *zmienne środowiskowe (dane postaci klucz=wartość zarządzane przez powłokę systemową, każdy proces posiada swój zestaw, który dziedziczy po rodzicu, są w pliku **/proc/[pid]/environ **)*.
```=
sudo ls /proc/1
sudo cat /proc/1/cmdline
sudo cat /proc/1/environ
```
* #### Podaj znaczenie następujących pól pliku `status`:
* `man proc`
* `Uid`: (rzeczywisty, efektywny) ID użytkownika w systemie
* `Gid`: jw. tylko ID grupy
* `Groups`: lista grup uzupełniających dziedziczonych po rodzicu, mówią jakie uprawnienia ma proces
* `VmPeak`: Maksymalny rozmiar zajętej pamieci wirtualnej
* `VmSize`: Aktualny rozmiar zajętej pamięci wirtualnej
* `VmRSS`: (vitual memory resident set size) Rozmiar zbioru roboczego (pamięci wirtualnej używanej przez proces)
* `Threads`: Liczba wątków w procesie zawierającym ten wątek
* `voluntary_ctxt_switches`: Liczba dobrowolnych przełączeń kontekstu
* `nonvoluntary_ctxt_switches`: Liczba przymusowych przełączeń kontekstu
//:::
## Zadanie 4

//:::spoiler
* #### Znajdź pid procesu `X-serwera`
`ps -e | grep tty`

Bardziej szczegółowa dokumentacja **pmap**:
https://docs.oracle.com/cd/E86824_01/html/E54763/pmap-1.html
https://man.netbsd.org/pmap.1
* #### Używając polecenia `pmap` wyświetl zawartość jego przestrzeni adresowej. Zidentyfikuj w niej poszczególne zasoby pamięciowe – tj. stos, stertę, segmenty programu, pamięć anonimową, pliki odwzorowane w pamięć.
* `pmap PID | less`
* `stos` - na samym dole

* `pamięć anonimowa` (jest nią również stos i sterta)

* `segmenty programu` - na samej górze

* `pliki odwzorowane w pamięć`

* `pmap PID -X | less`
* `sterta` - na górze

//:::
Stos [stack] oraz Sterte [heap] znajdują się na dole lecz zobaczymy tam tylko adres początku, możemy jednak wywołać sudo `less /proc/[pid]/maps` aby uzyskac dokladne przedzialy
Poszczególne kolumny wydruku pmap oznaczają:
- Address - adres początku
- Kbytes - rozmiar
- Mode - uprawnienia rwx (czytanie, pisanie, wykonywanie)
- Mapping - plik na jaki zmapowana jest pamięć lub [anon]/[stack]
## Zadanie 5

lsof -p PID przegladarki
Kolumna Type definiuje typy plików:
- REG - pliki regularne
- DIR - katalogi
- IPv4, IPv6 - sockety sieciowe
- sock - socket nieznanej domeny
- unix, ax25 - socket unixowy
- Potoki to te pliki które w name mają type=STREAM
- Urządzenia - kolumna device zawiera numer urządzenia ale według dokumentacji może to oprócz numeru oznaczać kilka różnych rzeczy więc z tym trzeba uważać (można jeszcze spróbować strzelić że urządzenia to te pliki które mają w nazwie /dev/...)
* **diff -u before.txt after.txt | grep +** - linijki zaczynające się od + to te które pojawiły się w after, żeby znaleźć nowe połączenia trzeba znaleźć te linijki które są socketami sieciowymi
## Zadanie 6

//:::spoiler
**real** - czas (prawdziwy) w sekundach od staru do końca
**user** - czas w CPU-sekundach, które proces spędził w user modzie
**sys** - czas w CPU-sekundach, które proces spędził w kernel modzie
usr i sys mogą być dla wielu wątków zatem może być powielony
```
time find /usr
ulimit -t 1
ulimit -t 1 -S
ulimit -t 5 -H
./zad6
```
The default format string is:
%Uuser %Ssystem %Eelapsed %PCPU (%Xtext+%Ddata %Mmax)k
%Iinputs+%Ooutputs (%Fmajor+%Rminor)pagefaults %Wswaps
When the -p option is given, the (portable) output format is used:
real %e
user %U
sys %S
`gcc zad6.c -o zad6`
```c=
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
void sig_handler(int signo)
{
if (signo == SIGXCPU)
printf("received SIGXCPU\n");
}
void sig_handler1(int signo)
{
if (signo == SIGINT)
printf("received SIGINT\n");
}
void sig_handler3(int signo)
{
if (signo == SIGTERM)
printf("received SIGTERM\n");
}
int main(void)
{
if (signal(SIGXCPU, sig_handler) == SIG_ERR)
printf("\ncan't catch SIGXCPU\n");
if (signal(SIGINT, sig_handler1) == SIG_ERR)
printf("\ncan't catch SIGINT\n");
if (signal(SIGTERM, sig_handler3) == SIG_ERR)
printf("\ncan't catch SIGTERM\n");
// A long long wait so that we can easily issue a signal to this process
int i = 0;
while(1) {
}
return 0;
}
```
//:::
## Zadanie 7

//:::spoiler
```c=
#include "csapp.h"
static char buf[256];
#define LINE1 49
#define LINE2 33
#define LINE3 78
static void do_read(int fd)
{
/* TODO: Spawn a child. Read from the file descriptor in both parent and
* child. Check how file cursor value has changed in both processes. */
pid_t child = Fork();
if (child == 0)
{ // child (new process)
int before =(int)Lseek(fd,0,SEEK_CUR);
Read(fd, buf, LINE1);
int after =(int)Lseek(fd,0,SEEK_CUR);
printf("Child (pid:%d) (lseek before:%d after: %d)\n %s\n\n", (int)getpid(), before, after, buf);
}
else
{
Wait(NULL);
int before =(int)Lseek(fd,0,SEEK_CUR);
Read(fd, buf, LINE2);
int after =(int)Lseek(fd,0,SEEK_CUR);
printf("Parent of %d (pid:%d) (lseek before:%d after: %d)\n %s\n\n", child,(int)getpid(), before, after, buf);
}
exit(0);
}
static void do_close(int fd)
{
/* TODO: In the child close file descriptor, in the parent wait for child to
* die and check if the file descriptor is still accessible. */
pid_t child = Fork();
if (child == 0)
{ // child (new process)
Read(fd, buf, LINE1);
printf("Child (pid:%d)\n %s\n\n", (int)getpid(), buf);
// Close(fd);
}
else
{
// int rc_wait = Wait(NULL);
Read(fd, buf, LINE2);
printf("Parent of %d (pid:%d)\n %s\n\n", child, (int)getpid(), buf);
Close(fd);
}
exit(0);
}
int main(int argc, char **argv)
{
if (argc != 2)
app_error("Usage: %s [read|close]", argv[0]);
int fd = Open("test.txt", O_RDONLY, 0);
if (!strcmp(argv[1], "read"))
do_read(fd);
if (!strcmp(argv[1], "close"))
do_close(fd);
app_error("Unknown variant '%s'", argv[1]);
}
```
//:::
## Zadanie 8

```c=
#include "libcsapp/csapp.h"
static int ndselect(int n) { // return multiple times -> 0..n-1
/* TODO: A loop is missing here that spawns processes and waits for them! */
/* ---------------------------------- impl ---------------------------------- */
pid_t children[n];
for (int i = 0; i < n; i++) {
children[i] = fork();
if (children[i] == 0) { //child code
return i;
} else { //parent code
waitpid(children[i], NULL, 0);
}
}
/* --------------------------------- endimpl -------------------------------- */
exit(0);
}
static int conflict(int x1, int y1, int x2, int y2) {
return x1 == x2
|| y1 == y2
|| x1 + y1 == x2 + y2
|| x1 - y1 == x2 - y2;
}
static void print_line_sep(int size) {
for (int i = 0; i < size; ++i)
printf("+---");
printf("+\n");
}
static void print_board(int size, int board[size]) {
for (int i = 0; i < size; ++i) {
print_line_sep(size);
for (int j = 0; j < size; ++j)
printf("|%s", board[i] == j ? " Q " : " ");
printf("|\n");
}
print_line_sep(size);
printf("\n");
}
int main(int argc, char **argv) {
if (argc != 2)
app_error("Usage: %s [SIZE]", argv[0]);
int size = atoi(argv[1]);
if (size < 3 || size > 9)
app_error("Give board size in range from 4 to 9!");
int board[size];
/* TODO: A loop is missing here that initializes recursive algorithm. */
/* ---------------------------------- impl ---------------------------------- */
for (int i = 0; i < size; i++) {
board[i] = ndselect(size);
if (board[i] < 0)
exit(0);
for (int k = 0; k < i; k++) {
if (conflict(i, board[i], k, board[k]))
exit(0);
}
}
/* --------------------------------- endimpl -------------------------------- */
print_board(size, board);
return 0;
}
```