# SO Lista 2
### Zadanie 1 <!-- Gut -->

 <!-- 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 -->

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

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

#### A)

#### B)

#### 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)



### Zadanie 4 <!-- Gut -->

<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

cat /proc/pid/status
kill -s SIGINT 2792
Wykona się ten który ma najmniejszy numer (u nas SIGHUP bo ma 1)
### Zadanie 5

#### 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


### Zadanie 6 <!-- gut -->

```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

```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

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