---
# System prepended metadata

title: SO Lista 2

---

# SO Lista 2

### Zadanie 1 <!-- Gut -->
![](https://i.imgur.com/PwvO6VN.png)
![](https://i.imgur.com/PhFXRzT.png) <!-- Radek gigachad -->

<b>Możliwe stany procesu:</b>
<ul>
<li><b>Stoppped -></b> wstrzymany, może zostać wznowiony (np. przez syscall)</li> 
<li><b>Zombie -></b> proces który się zakończył, ale dalej pobiera zasoby i czeka na ogarnięcie</li>
<li><b>Running (który się dzieli):</b></li>
<ul>
    <li><b>Ready -></b> załadowany do pamięci czeka na na wykonanie</li>
    <li><b>Executing -></b> proces który obecnie jest wykonywany</li>
</ul>
<li><b>Uninterruptible (sen nieprzerywalny) -></b> proces jest zablokowany i nie reaguje na żadne sygnały</li>
<li><b>Interruptible (sen przerywalny)-></b> proces jest zablokowany, ale może oczekiwać na koniec jakiejś operacji, albo na jakiś sygnał</li>
</ul>

<b>Podaj akcje albo zdarzenia wyzwalające zmianę stanu && czyje działania mogą wywołać </b>

<table>
    <thead><tr>
        <th>Stan początkowy</th>
        <th>Stan końcowy</th>
        <th>Akcja i czyje działania</th>
    </tr></thead>
    <tbody>
        <tr>
            <th>Ready</th>
            <th>Executing</th>
            <th>Wykonanie procesu które było wcześniej zaplanowane, działanie jądra</th>
        </tr>
        <tr>
            <th>Executing</th>
            <th>Zombie</th>
            <th>Dobrowolne , user</th>
        </tr>
        <tr>
            <th>Executing</th>
            <th>(Un)interruptible</th>
            <th>Wybudzenie przez jądro interruptable przez otrzymanie I/O</th>
        </tr>
        <tr>
            <th>Stopped</th>
            <th>Ready</th>
            <th>otrzymanie sygnału SIGSTOP lub SIGCONT (czyli użytkownik)</th>
        </tr>
        <tr>
            <th>(Un)interruptible</th>
            <th>Ready</th>
            <th>?</th>
        </tr>
    </tbody>
</table>

<b>Czy proces może zablokować lub zignorować sygnał SIGKILL lub SIGSEGV?</b>

<b>Zablokowanie sygnału -></b> niedostarczenie sygnału do procesu aż do momentu odblokowania go przez SO. Dzięki temu nie tracimy informacji o sygnale, a jednocześnie nie musimy na niego reagować w niewygodnym dla nas momencie.
<b>Zignorowanie sygnału -></b> sytuacja kiedy proces nie ma zdefiniowanego zachowania dla danego sygnału

Sygnału SIGKILL nie da się zablokować. Ignorowanie kończy się zabiciem procesu 
### Zadanie 2 <!-- Gut -->
![](https://i.imgur.com/aWzjpUf.png)
<b>Linux</b>
W systemie Linux proces jest tworzony tylko przy pomocy fork()
<li>Deskryptor nowego procesu i userpace są tworzone i uzupełnione w większości od rodzica</li>
<li>Proces otrymuje PID i mapę pamięci. Ma dostęp do współdzielonych plików z rodzicem
<li>Ustawiane są rejestry i proces jest gotowy do działania</li>


<b>WinNT</b>
W systemie WinNT proces towrzy się wywołując procedurę CreateProcess(której argumentem jest .exe). To wywołanie wzywa procedurę w user-mode w kernel32.dll która woła NtCreateUserProcess w jądrze. Cała procedura tworzy nowy proces (nie forkuje jak Linux). Dziecko w przeciwieństwie do procesu w Linuxie nie otrzymuje kopii pamięci rodzica 

<b>Obsługa frok() i execve() poniżej na rysunku</b>
![](https://i.imgur.com/sj7hF67.png)

<b> Dlaczego w takim przypadku mielibyśmy problemy z dodaniem do powłoki obsługi przekierowania standardowego wejścia/wyjścia odpowiednio z/do pliku albo łączenia dowolnych procesów potokami?</b>
Pipe zdecydowanie ułatwia komunikację między procesami, dlatego  spawn leci w chuja

### Zadanie 3 <!-- Gut -->
![](https://i.imgur.com/z4pblqF.png)

#### A)
![](https://i.imgur.com/IRD6osx.png)

#### B)
![](https://i.imgur.com/fSd1u8w.png)

#### Czemu trzeba wyczyścić bufor?

Proces dziecko odziedzicza deskryptory otwartych plików (w tym stdout) i bufor z nim związany. 
(po prostu żeby nie wypisywać kilka razy tego samego)

#### Obsługa sygnałów

Resetuje je do defaultowaych  ustawień  (man exe)
![](https://i.imgur.com/uey5yEH.png)


![](https://i.imgur.com/UgJ5JhM.jpg)
![](https://i.imgur.com/yv9VCUO.jpg)


### Zadanie 4  <!-- Gut -->
![](https://i.imgur.com/pCYNuoI.png)

<b>Co robią poszczególne polecenia</b>

<ul>
<li><b>Kill (pid)</b> -> domyślnie wysyła sygnał TERM </li>
<li><b>Pkill (process name)</b> ->domyślnie wysyła SIGTERM to lażdego procesu </li> 
<li><b>Xkill (okno z procesem)</b> -> will display a special cursor as a prompt for the user to select a window to be killed. This command does not provide any warranty that the application whose connection to the X server is closed will abort nicely, or  even
       abort  at all.</li> 
</ul>

<b>Sygnały oczekujące -> </b> to sygnały, których dostarczenie jest wstrzymane do momentu wyjścia przez proces z nieprzerywalnego snu

![](https://i.imgur.com/UT9PrU0.png)


cat /proc/pid/status
kill -s SIGINT 2792

Wykona się ten który ma najmniejszy numer (u nas SIGHUP bo ma 1)

### Zadanie 5
![](https://i.imgur.com/dtgbTRF.png)

#### Co robi sinit 

Startuje init, blokuje wszystkie sygnały, czeka na eventy, które ma zdefiniowane i odpala odpowiednie handlery 

### Jakie akcje wykonuje
<ul>
    <li>reboot -> sigreboot</li>
    <li>shutdown -> sigpoweroff</li>
    <li>grzebanie dzieci -> sigreap</li>
</ul>

### Do czego służą procedury
<ul>
    <li>Sigprocmask ->  manipuluje blokowanymi sygnałami</li>
    <li>Sigwait -> czeka na sygnał i daje info o nim w 2arg podanym do niego</li>
</ul>

### Jak grzebie dzieci?
Waitpid dopóki nie pogrzebie wszystkich dzieci które powstały jak dostał sygnał SIGCHCD
![](https://i.imgur.com/ywVPdmu.jpg)
![](https://i.imgur.com/g91SJJU.jpg)

### Zadanie 6 <!-- gut -->
![](https://i.imgur.com/9s5309q.png)

```c
#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());
  /* TODO: Something is missing here! */
  pause();
  printf("(%d) Got the signal!\n", getpid());
}

static void child(void) {
  pid_t pid;
  /* TODO: Spawn a child! */
  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) {
  /* TODO: Something is missing here! */
  pid_t pid;
  if((pid = fork()) == -1)
    app_error("fork failed");
  else if(pid == 0){
    /* child */
    char *args[] = {"/bin/ps","-o","pid,ppid,pgrp,stat,cmd",NULL};
    fflush(stdout);
    execve("/bin/ps",args,NULL);
    exit(0);
  }
  else
    /* parent */
    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;
  int status;

  /* TODO: Start child and grandchild, then kill child!
   * Remember that you need to kill all subprocesses before quit. */
  pid = spawn(child);
  setpgid(pid,pid);
  //teoretycznie wyzej jest napisane ze trzeba zabic dzieciaka
  //ale w zadaniu jest napisane o zakonczeniu działania syna
  //poza tym kill na dziecko troche komplikuje sprawe z sychnronizacją
  //ale dziecko i tak samo z siebie robi exit() wiec nie wiem po co 
  //go zabijac
  waitpid(pid,NULL,0);
  ps();
  kill(-pid,SIGINT);
  wait(&status);
  if(WIFSIGNALED(status))
    printf("Grandchild signal code: %d\n",WTERMSIG(status));

  return EXIT_SUCCESS;
}

```
### Zadanie 7
![](https://i.imgur.com/hikxndW.png)
```c
#include "csapp.h"

bool notified = false;

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);
  }
  else if (signum==SIGUSR1 && !notified)
    notified = true;
}

static void play(pid_t next, const sigset_t *set) {
  for (;;) {
    printf("(%d) Waiting for a ball!\n", getpid());
    /* TODO: Something is missing here! */
    Sigsuspend(set); 
    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]);

  pid_t pid=1,prev_pid = getpid();
  int children = atoi(argv[1]);
  //siginfo_t info;

  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! */
  sigfillset(&action.sa_mask);
  sigdelset(&action.sa_mask,SIGINT);
  sigdelset(&action.sa_mask,SIGUSR1);
  Sigprocmask(SIG_BLOCK, &action.sa_mask,NULL);

  for (int i = 0; i < children; i++){
    pid = Fork();
    if (pid == 0) /* child */
      play(prev_pid,&action.sa_mask);
    else
      prev_pid = pid;
  }

  /* Stary zaczyna gre podając piłke do najmłodszego */
  /* teraz działa samo z siebie ale na trytytkach, wcześniej było: 
      Kill(pid, SIGUSR1);
      play(pid,&action.sa_mask);
  */
  while(!notified)
    Kill(pid, SIGUSR1);
  play(pid,&action.sa_mask);

  return EXIT_SUCCESS;
}
```
### Zadanie 8
![](https://i.imgur.com/xe47tyX.png)
```c
#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)
#define REG_RIP 16
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 = uc->uc_mcontext.gregs[REG_RIP];
  void * page_ptr = (void *)((unsigned long)info->si_addr & ~(pagesize - 1));

  /* 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. */
  /* [Q] Dlaczego safe_printf() jest bezpieczny ?
   * bo uzywa niebuforowanego I/O (czyli tylko write())
   * przez co nie zmienia globalnych struktur itd (nie to co printf()),\
   * a formaty parsuje sam w pliku (patrz libcsapp/safe_printf.c)
   */
  if(info->si_addr < ADDR_START || info->si_addr >= ADDR_END){
    safe_printf("Fault at rip=%lx accessing %lx! Address not mapped - terminating\n",rip,(long)info->si_addr);
    _exit(139);
  }
  else if(info->si_code==SEGV_MAPERR){
    safe_printf("Fault at rip=%lx ",rip);
    safe_printf("accessing %lx! ",(long)info->si_addr);
    safe_printf("Map missing page at %lx\n",(long)page_ptr);
    mmap_page(page_ptr,PROT_WRITE);
  }
  else if(info->si_code==SEGV_ACCERR){
    safe_printf("Fault at rip=%lx ",rip);
    safe_printf("accessing %lx! ",(long)info->si_addr);
    safe_printf("Make page at %lx writable\n",(long)page_ptr);
    mprotect_page(page_ptr,PROT_WRITE);
  }
}

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;
}

```