---
# System prepended metadata

title: Lista 1
tags: [SO2022]

---


# 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
![](https://i.imgur.com/OHAO232.png)
//:::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
    ![](https://i.imgur.com/QstHjwM.png)
    - **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
![](https://i.imgur.com/P8Euudy.png)
//:::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
![](https://i.imgur.com/dOjxYkt.png)
//:::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
![](https://i.imgur.com/rMcu2O3.png)
//:::spoiler
* #### Znajdź pid procesu `X-serwera`
    `ps -e | grep tty`
    
    ![](https://i.imgur.com/yiCwIcI.png)
    
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
            ![](https://i.imgur.com/0bBXG5g.png)
        * `pamięć anonimowa` (jest nią również stos i sterta)
            ![](https://i.imgur.com/uRVF6rM.png)
        * `segmenty programu` - na samej górze
            ![](https://i.imgur.com/rzejcj6.png)
        * `pliki odwzorowane w pamięć`
            ![](https://i.imgur.com/EZ28l11.png)

    * `pmap PID -X | less`
        * `sterta` - na górze
            ![](https://i.imgur.com/GDkZo2r.png)
//:::

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
![](https://i.imgur.com/mN1tnRA.png)

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
![](https://i.imgur.com/Hgj6bjY.png)

//:::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
![](https://i.imgur.com/LV9hHNX.png)
//:::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
![](https://i.imgur.com/Cs0lDuo.png)
```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;
}
```
