# Lista 2 ###### tags: `SO` ### Zadanie 1 ![](https://i.imgur.com/FYHZHfh.png) **Running** - proces jest wykonywany lub gotowy do wykonywania **Interruptible** - proces czeka na zdarzenie, np. koniec operacji I/O, dostępność zasobów, sygnał z innego procesu **Uninterruptible** - różnica między tym a powyższym stanem polega na tym, że proces nieprzerywalny czeka z powodów sprzętowych i nie może obsłużyć przychodzących sygnałów **Stopped** - proces zatrzymany, który czeka na znak od innego procesu, aby wznowić działanie **Zombie** - proces został zakończony, ale nadal pobiera zasoby, nie został pogrzebany Jądro systemu może wprowadzać w stany: - running (w szczególności w ready i executing) Kod sterowników może wprowadzać w stany: - interruptible Proces użytkownika może wprowadzać w stany: - stopped (debugger) - zombie (sam siebie) - interruptible (czekając na dane sieciowe) `SIGKILL` nie może być zablokowany ani zignorowany. `SIGSEGV` może być zablokowany oraz obsłużony, a więc także zignorowany. ### Zadanie 2 ### Zadanie 3 **Fork:** a) dziedziczy z rodzica: - deskryptory otwartych plików - replika całej przestrzeni pamięci - procedury obsługi sygnałów - ID grupy procesów - obecny katalog roboczy b) przekazywane: - ID nowego procesu **Execve:** a) dziedziczy z rodzica: - ID grupy procesów - czas pozostały do alarmu - obecny katalog roboczy - blokady na plikach b) przekazywane: - lista argumentów - środowisko **Czemu przed wywołaniem fork należy opróżnić bufory biblioteki stdio(3)?** Ponieważ buffor jest dziedziczony przez dziecko. **Co jądro robi w trakcie wywołania `execve` z konfiguracją zainstalowanych procedur obsługi sygnałów?** Nadpisuje na domyślne. https://stackoverflow.com/questions/43760094/what-happens-to-pending-signals-and-signal-masks-on-an-exec ### Zadanie 4 Domyślny jest `SIGTERM`. Elementy pliku `status` dotyczące sygnałów: - `SigQ` - liczba aktualnie oczekujących sygnałów/liczba możliwych oczekujących sygnałów - `SigPnd`, `ShdPnd` - maska oczekujących sygnałów - `SigBlk`, `SigIgn`, `SigCgt` - maski sygnałów zablokowanych, ignorowanych i złapanych Sygnały są odkładane na kolejkę. ### Zadanie 5 **jakie zadania pełni minimalny program rozruchowy sinit?** Jest to minimalny init, robi tylko to co init musi. Potrafi wyłączyć system, zrestartować go i grzebać dzieci. **SIGUSR1** - wyłącza maszynę **SIGCHLD** - grzebie dziecko **SIGALRM** - grzebie dziecko **SIGINT** - restartuje maszynę **Do czego służą `sigprocmask(2)` i `sigwait(3)`?** `sigprocmask(2)` - sprawdza i zmienia zablokowane sygnały `sigwait(3)` - czeka na sygnał **W jaki sposób grzebie swoje dzieci?** W pętli czeka na zakończenie się jakiegokolwiek dziecka (wszystkich dzieci). WNOHANG - zwraca informację, że nie ma dzieci ### Zadanie 6 ```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 do_nothing() { } static void grandchild(void) { printf("(%d) Waiting for signal!\n", getpid()); /* TODO: Something is missing here! */ // signal(SIGINT, do_nothing); 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 = Fork(); if(pid == 0) { char* argv[] = {"ps", "-o", "pid,ppid,pgrp,stat,cmd", NULL}; int t = execve("/bin/ps", argv, NULL); printf("(%d) Returned from execve() with %d", t); exit(EXIT_SUCCESS); } 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, pgrp; int status; /* TODO: Start child and grandchild, then kill child! * Remember that you need to kill all subprocesses before quit. */ pid = spawn(child); setpgid(0, getppid()); ps(); waitpid(pid, NULL, 0); kill(-getpid(), SIGINT); setpgid(0, 0); waitpid(-1, &status, 0); printf("(%d) Killed grandchild's status is %d\n", getpid(), status); ps(); return EXIT_SUCCESS; } ``` ### Zadanie 7 ```c= #include "csapp.h" 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); } } 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]); int children = atoi(argv[1]); 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! */ sigset_t set; sigprocmask(SIG_UNBLOCK, NULL, &set); pid_t previous_pid, pid = -1, father_pid = getpid(); for(int i = 0; i <= children; i++) { previous_pid = pid; pid = Fork(); if(pid == 0) { if(i == children) { exit(EXIT_SUCCESS); } if(previous_pid == -1) { play(father_pid, &set); } else { play(previous_pid, &set); } } } waitpid(pid, NULL, 0); kill(previous_pid, SIGUSR1); play(previous_pid, &set); return EXIT_SUCCESS; } ``` ### Zadanie 8