# Ćwiczenia 1, grupa cz. 10-12, 13 października 2022
###### tags: `SO22` `ćwiczenia` `pwit`
## Deklaracje
Gotowość rozwiązania zadania należy wyrazić poprzez postawienie X w odpowiedniej kolumnie! Jeśli pożądasz zreferować dane zadanie (co najwyżej jedno!) w trakcie dyskusji oznacz je znakiem ==X== na żółtym tle.
**UWAGA: Tabelkę wolno edytować tylko wtedy, gdy jest na zielonym tle!**
:::danger
| | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
| ----------------------:| ----- | --- | --- | --- | --- | --- | --- | --- |
Miriam Bouhajeb | X | | X | X | X | X | X | |
Kacper Chmielewski | X | X | X | X | X | X | | |
Jakub Kaczmarek | | | | | | | | |
Jarosław Kadecki | X | X | X | X | | X | X | |
Zuzanna Kania | X | | | | X | X | X | X |
Julia Konefał | X | | X | X | | X | | |
Daniel Sarniak | X | | X | X | X | X | X | X |
Paweł Tkocz | X | | X | X | X | X | | |
Adrian Walczak | | | | | | | | |
Miłosz Urbanik | X | X | | | | X | X | |
Tomasz Wołczański | X | X | X | X | | X | | |
Radosław Śliwiński | X | X | X | X | X |==X==| | |
:::
:::info
**Uwaga:** Po rozwiązaniu zadania należy zmienić kolor nagłówka na zielony.
:::
## Zadanie 1
:::success
Autor: Miriam Bouhajeb
:::
Rodzic-dziecko
Relacja wyglądająca tak, że proces, który tworzy nowy proces
(poprzez inwokowanie funkcji fork() ) nazywamy rodzicem, a stworzony proces nazywany dzieckiem.
PID - indentyfikator procesu; unikalna liczba służąca do rozróżniania procesu
PGID - identyfikator grupy procesów; zbiór procesów który służy między innymi do sterowania dystrybucją sygnału który jest kierowany do każdego z procesów z tej grupy
PPID - identyfikator rodzica; identyfikator procesu który za pomocą fork() stworzył konkretny proces
Właściciel procesu - użytkownik który utworzył proces i posiada do niego pełne uprawnienia
Wątki jądra - wątki wykonujące kod kernela, całkowicie odrębnione od przestrzeni użykowników, nie mają w niej zaalokowanej pamięci, dlatego w outpucie -ps mają 0 KiB. Także w kolumnie cmd mają nawiasy kwadratowe gdyż nie jest znana nazwa komendy która je utworzyła
Znaczenie poszczególnych znaków w kolumnie STAT możemy poznać, przez użycie `man ps`

Proces init() rozpoznamy przez to, że PID jego rodzica = 0, czyli jego PPID = 0. Jest to PID kernela.

Procesy które są wątkami jądra nie używają pamięci użytkownika, więc można je rozpoznać po tym, że gdy dodamy vsz do polecenia ps, to wartości w kolumnie VSZ będą równe 0.

pstree:

## Zadanie 2
:::success
Autor: Miłosz Urbanik

:::
* **sierota** - proces, którego proces-rodzic został zakończony.
* Gdy proces zostanie osierocony jądro wykonuje reparenting i jako *PPID* procesu wpisuje 1 - proces init.
* **zombie** - proces, który zakończył się, ale jego wpis w tablicy procesów nie został jeszcze usunięty przez jego rodzica.
* W celu pogrzebania procesu jego rodzic używa systemcall `wait()`.
* Proces nie może sam siebie pogrzebać, bo nie może zwolnić swojego stosu jądra (robi to rodzic), a usunięcie wpisu tablicy procesów spowodowałoby utracenie informacji o przebiegu wykonania procesu
* Gdyby dzieci mogły czekać na rodzica, to mógłby utworzyć się cykl blokujących wywołań `wait()` - dochodzi do zakleszczenia i blokowania zasobów. Co więcej `wait(int *wstatus)` pozwala na dostęp informacji o procesie, czyli kernel musiałby utrzymywać tę informację, do czasu, aż ostatnie z dzieci jej nie odbierze.
* Gdyby proces mógł czekać na dowolny inny, to kończący się proces musiałby mieć informację o wszystkich procesach, które na niego czekają, aby wysłać odpowiedni sygnał i na dodatek mieć do tego uprawnienia. Znów mamy tu problem, który z czekających procesów jest tym ostatnim, który odbierze informację o statusie.
## Zadanie 3
:::success
Autor: Paweł Tkocz

System plików proc jest wirtualnym systemem plików i interfejsem pewnych struktur danych jądra systemu operacyjnego. Zawiera informacje o obecnie istniejących procesach. Większość plików w proc jest tylko do odczytu, ale niektóre jego części można zmieniać (np. niektóre zmienne), wpływając w ten sposób na zachowanie niektórych części jądra systemu.
Zawartość katalogu /proc/66:

Plik zawierający argumenty programu:

Plik zawierający zmienne środowiskowe:

Znaczenie pól pliku status:
Uid – Identyfikator użytkownika
Gid – Identyfikator grupy użytkowników
Groups – lista grup procesów, które należą do tego procesu
VmPeak – największe zarejestrowane użycie pamięci wirtualnej przez proces
VmSize – rozmiar pamięci wirtualnej procesu
VmRSS – rozmiar zbioru rezydentnego (resident set size)
Threads – liczba wątków w procesie
Voluntary_ctxt_switches – liczba dobrowolnych zmian kontekstu (proces nie ma nic do roboty, bo np. oczekuje na dane albo ukończenie operacji I/O i z tego powodu dobrowolnie zwalnia procesor)
Nonvoluntary_ctxt_switches – liczba niedobrowolnych zmian kontekstu (skończył się kawałek czasu, który procesor przydzielił procesowi i z tego powodu następuje zamiana kontekstu – kolejny w kolejce proces trafia do procesora)
:::
## Zadanie 4
:::success
Autor: Jarosław Kadecki

:::
ps -e | grep X
szukamy Xorg
sudo pmap [PID Xorga]
elementy sekcji można znaleźć w /proc/PID/maps



55a7fd838000-55a7fd875000 r--p 00000000 103:03 12191696 /usr/lib/xorg/Xorg - RODATA
55a7fd875000-55a7fda07000 r-xp 0003d000 103:03 12191696 /usr/lib/xorg/Xorg - TEXT
55a7fda07000-55a7fda80000 r--p 001cf000 103:03 12191696 /usr/lib/xorg/Xorg - RODATA
55a7fda80000-55a7fda84000 r--p 00247000 103:03 12191696 /usr/lib/xorg/Xorg - RODATA
Segmenty programu – bloki pamięci o takim samych uprawnieniach i podobnym przeznaczeniu. Jeden segment może zawierać wiele sekcji.
Segment kodu to obszar pamięci zawierający kod maszynowy programu. Segmenty programu są zmapowane do Xorg.
Pamięć anonimowa to pamięć niebędąca powiązana z żadnym plikiem ani obiektem. Powszechnym anonimowym mapowaniem jest stos i sterta wspomniane powyżej. Jest ona oznaczona jako [anon]
Pliki odwzorowane w pamięć (ang. memory-mapped file) to segment pamięci wirtualnej mający bezpośrednie mapowanie co do bajta z jakimś plikiem lub zasobem. Dzięki temu unika się stosowania funkcji systemowych na plikach takich jak read() lub write(), gdyż proces adresuje plik bezpośrednio. Plik może być traktowany jak ciągły obszar w pamięci procesu, dostępny poprzez bezpośrednie operacje pobrania i podstawienia wartości. W pmapie można je znaleść po rozszerzeniu .so.
Kolumny wydruku:
adress – adres początkowy
Kbytes – rozmiar
Mode – uprawnienia rwx
Mapping – plik na jaki zmapowana jest pamięć lub [anon] / [stack]
## Zadanie 5
:::success
Autor: Kacper Chmielewski

1. Na początku szukamy pid firefoxa
```
ps -eo user,pid,ppid,pgid,tid,pri,stat,wchan | grep firefox
```
2. Następnie wywołujemy lsof ze znalezionym pid
```
lsof -p [pid]
```
Oznaczenia w pliku lsof:
- plik zwykły - REG
- katalogi - DIR
- gniazda - np IPv4
- potoki - FIFO
Kolumna FD:
- cwd - current working directory;
- Lnn - library references (AIX);
- err - FD information error (see NAME column);
- jld - jail directory (FreeBSD);
- ltx - shared library text (code and data);
- Mxx - hex memory-mapped type number xx.
- m86 - DOS Merge mapped file;
- mem - memory-mapped file;
- mmap - memory-mapped device;
- pd - parent directory;
- rtd - root directory;
- tr - kernel trace file (OpenBSD);
- txt - program text (code and data);
- v86 - VP/ix mapped file;
:::
## Zadanie 6
:::success
Autor: Radosław Śliwiński

`czas wykonania`: czas spedzony na wykonaniu zadania
`ograniczenie czasu wykonania`: limit nalozony na czas wykonania
Wydruk polecenia `time find /usr`: 0.34s user 0.72s system 84% cpu 1.249 total
Zauwazmy, ze `0.34 + 0.72 != 1.249`. Zeby dowiedziec sie dlaczego tak sie dzieje, warto wiedziec co oznacza `user`, `system` i `total`.
`user`: czas przeznaczony w trybie uzytkownika na wykonanie procesu w poleceniu `time`
`system`: czas przeznaczony na wykonywanie roznych `syscall` wywolanych przez proces bedacy argumentem `time`
`total`: rzeczywisty czas od rozpoczecia do zakonczenia procesu
Teraz jak juz wiemy, co oznacza wydruk, mozemy dojsc do pewnych wnioskow. Czas `total` jest wiekszy niz suma `user` i `system` poniewaz w `total` wlicza sie czas uzyty przez inne procesy, oraz czas w ktorym proces ktorego czas wykonania miezymy jest zablokowany (np przez czekanie na I/O). Moze tez dojsc do sytuacji w ktorej czas `user` jest wiekszy od `total`. Moze sie tak stac, gdy aplikacja uzywa wielu watkow procesora, a dla kazdego watku, czas `user` jest liczony osobno, i na koniec sumowany.
Po nalozeniu limitu wykonania, proces jest zabijany sygnalem `SIGXCPU`
:::
## Zadanie 7
:::success
Autor: Zuzanna Kania


Offset jest przechowywany bezpośrednio przy otwartym pliku, a file descriptory procesów pokrewnych wskazują na tę samą instancję otwartego pliku zatem offset mają "wspólny". Funkcja close natomiast zwalnia tylko file descriptor konkretnego procesu, a instancję otwartego pliku usuwa tylko wtedy, gdy zamykany file descriptor jest ostatnim wskazującym na tę instancję.
Kod funkcji:
```lang=c
static void do_read(int fd)
{
pid_t pid;
size_t to_read;
pid = Fork();
if (pid == 0)
to_read = LINE2;
else
to_read = LINE1;
printf("In process of pid: %d | Current position: %ld\n", getpid(), lseek(fd, 0, SEEK_CUR));
Read(fd, buf, to_read);
printf("Read text: %s\n", buf);
exit(0);
}
static void do_close(int fd)
{
Fork();
if (fcntl(fd, F_GETFD) != -1)
{
close(fd);
printf("In process of pid: %d | File was open, now closed\n", getpid());
}
else
{
printf("In process of pid: %d | File already closed\n", getpid());
}
exit(0);
}
```
:::
## Zadanie 8
:::success
Autor: Daniel Sarniak

```lang=c
#include "csapp.h"
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");
}
static int ndselect(int n) {
/* TODO: A loop is missing here that spawns processes and waits for them! */
if (n == 0)
{
return 0;
}
pid_t pid;
pid = fork();
if (pid < 0)
{
app_error("%d: fork error", pid);
}
else if(pid != 0) /*parent*/
{
Waitpid(pid, NULL, 0);
return n;
}
else
{
return ndselect(n-1); /*child*/
}
}
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. */
for (int i = 0; i < size; i++)
{
board[i] = ndselect(size-1);
for (int j = 0; j < i; j++)
{
if (conflict(i, board[i], j, board[j]))
{
exit(0);
}
}
}
printf("\n[%d]: \n", getpid());
print_board(size, board);
return 0;
}
```

Na powyższym obrazku, w czerwonych okręgach widać proces budowania następującego ułożenia hetmanów.


:::