# Plan ataku `SIGSTOP` i `SIGCONT`
## `SIGSTOP`
### Implementacja w NetBSD
#### Wysłanie `SIGSTOP` do pojedynczego procesu przez `kill`
- [`sys_kill`](http://bxr.su/NetBSD/sys/kern/sys_sig.c#301)
- [`kill1`](http://bxr.su/NetBSD/sys/kern/sys_sig.c#kill1)
- [`kpsignal2`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1297): wysyła sygnał do pojedynczego procesu
-- Wyczyść oczekujące sygnały `SIGCONT`
-- Jeśli proces już jest zatrzymany, koniec
-- Dodaj sygnał do listy oczekujących na dostarczenie do procesu ([`sigput`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#sigput))
-- Dostarcz sygnał do każdego wątku zdolnego go obsłużyć/przyjąć (czyli do wszystkich poza tymi śpiącymi snem nieprzerywalnym i zatrzymanymi przez debugger)
--- Sygnał próbujemy dostarczyć do wątku przy użyciu [`sigpost`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1109)
- [`sigpost`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1109): powiadamia wątek o sygnale i wybudza żeby mógł go obsłużyć
-- Powiadom wątek o sygnale ([`signotify`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#signotify))
-- Jeśli wątek jest aktywny (wykonuje się albo jest na runqueue) to koniec
-- Jeśli wątek jest zatrzymany to koniec (ale tylko dlatego że wysyłamy `SIGSTOP`, jeśli wysyłalibyśmy inny sygnał (taki, który nie zatrzymuje procesu), to wątek zostałby wybudzony aby mógł obsłużyć sygnał)
-- Jeśli wątek śpi snem przerywalnym, to jest wybudzany ([`setrunnable`](http://bxr.su/NetBSD/sys/kern/kern_synch.c#855))
#### Odbiór sygnału `SIGSTOP`
- [`lwp_userret`](http://bxr.su/NetBSD/sys/kern/kern_lwp.c#1587)
-- Sprawdź, czy nie czekają na nas jakieś sygnały (flaga `LW_PENDSIG`, ustawiana w [`signotify`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#signotify))
-- Znajdź sygnał czekający na obsługę ([`issignal`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1827))
-- Obsłuż sygnał ([`postsig`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#2050))
- [`issignal`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1827): Wybiera oczekujący sygnał dla wątku, zatrzymuje wątek jeśli sygnał tak mówi
-- Najpierw szukaj sygnału w liście per-wątek, potem w liście per-proces
-- Jeśli sygnał ma zatrzymać proces, to zatrzymaj się ([`sigswitch`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#sigswitch))
- [`sigswitch`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#sigswitch):
-- Jeśli jesteś pierwszym zatrzymującym się wątkiem procesu, [`proc_stop`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#proc_stop)
-- Jeśli jesteś ostatnim zatrzymującym się wątkiem, [`proc_stop_done`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#proc_stop_done)
-- Przełącz się na inny wątek ([`sigswitch_unlock_and_switch_away`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#sigswitch_unlock_and_switch_away))
- [`proc_stop`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#proc_stop): Zatrzymuje proces
-- Ustaw w procesie flagę `PS_STOPPING` -- to daje innym wątkom sygnał do zatrzymania
-- Zatrzymaj wszystkie wątki śpiące snem przerywalnym ([`proc_stop_lwps`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#proc_stop_lwps)):
--- Zatrzymane w ten sposób wątki są cały czas na sleepqueue, zmienia się tylko ich status (z `LSSLEEP` na `LSSTOP`)
-- Spraw, aby pozostałe wątki sprawdziły na wyjściu z jądra sygnały ([`sigpost`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1109))
-- Uruchom callouta, który co chwilę skanuje procesy i dla każdego zatrzymującego się procesu, którego nie wszystkie wątki się zatrzymały, zatrzymuje wątki śpiące snem przerywalnym ([`proc_stop_callout`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#2403)).
- [`proc_stop_done`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#proc_stop_done): Oznacza proces jako zatrzymany i powiadamia rodzica sygnałem `SIGCHLD`
- [`sigswitch_unlock_and_switch_away`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#sigswitch_unlock_and_switch_away): Ustawia status wątku na `LSSTOP` i przełącza wątek (`mi_switch`)
## `SIGCONT`
### Implementacja w NetBSD
#### Wysłanie `SIGCONT` do pojedynczego procesu przez `kill`
- [`sys_kill`](http://bxr.su/NetBSD/sys/kern/sys_sig.c#301)
- [`kill1`](http://bxr.su/NetBSD/sys/kern/sys_sig.c#kill1)
- [`kpsignal2`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1297): wysyła sygnał do pojedynczego procesu
-- Wyczyść oczekujące sygnały zatrzymujące proces (`SIGTSTP`, `SIGSTOP`, `SIGTTOU`, `SIGTTIN`)
-- Jeśli proces jest aktywny, nie jest w trakcie zatrzymywania się i proces nie obsługuje `SIGCONT`, koniec
-- Jeśli proces jest zatrzymany lub w trakcie zatrzymywania się:
--- Zmień status procesu na aktywny
--- Powiadom rodzica o zmianie statusu dziecka sygnałem SIGCHLD
--- Jeśli proces obsługuje `SIGCONT`, dodaj sygnał do listy oczekujących na dostarczenie do procesu ([`sigput`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#sigput))
-- Dostarcz sygnał do każdego wątku zdolnego go obsłużyć/przyjąć (czyli do wszystkich poza tymi śpiącymi snem nieprzerywalnym i zatrzymanymi przez debugger)
--- Sygnał próbujemy dostarczyć do wątku przy użyciu [`sigpost`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1109)
- [`sigpost`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1109): powiadamia wątek o sygnale i wybudza żeby mógł go obsłużyć
-- Powiadom wątek o sygnale ([`signotify`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#signotify))
-- Jeśli wątek maskuje `SIGCONT` i nie jest zatrzymany, koniec (zatrzymane wątki zawsze są wybudzane `SIGCONT`em, niezależnie od innych rzeczy)
-- Jeśli wątek jest aktywny (wykonuje się albo jest na runqueue) to koniec
-- Jeśli wątek jest zatrzymany:
--- Jeśli `l_wchan != NULL` (czyli wątek jest na sleepqueue), przywracamy go do stanu `LSSLEEP`
--- W p.p. wątek jest wybudzany ([`setrunnable`](http://bxr.su/NetBSD/sys/kern/kern_synch.c#855))
--- Jeśli wątek śpi snem przerywalnym, to jest wybudzany ([`setrunnable`](http://bxr.su/NetBSD/sys/kern/kern_synch.c#855))
## Wysyłanie sygnału do zatrzymanego procesu
- [`sys_kill`](http://bxr.su/NetBSD/sys/kern/sys_sig.c#301): nie ma żadnej logiki
- [`kill1`](http://bxr.su/NetBSD/sys/kern/sys_sig.c#kill1): sprawdza uprawnienia i czy proces jest żywy (`SACTIVE` lub `SSTOP`)
- [`kpsignal2`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1297): po wstawieniu sygnału na listę pending bezwarunkowo powiadamiamy wątek lub wątki o sygnale ([w tym miejscu](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1491))
- [`sigpost`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1109):
-- [`case LSSTOP:`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1192)
--- Jeśli wątek nie jest na sleepqueue lub jest na sleepqueue i można go przerwać, to wybudzamy wątek [w tym miejscu](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1212)
- Wątki zatrzymują się w [`issignal`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1827): pierwszy wątek (ten, który zdjął sygnał do zatrzymania z kolejki sygnałów) zatrzymuje się [tu](http://bxr.su/NetBSD/sys/kern/kern_sig.c#2006), wszystkie pozostałe [tu](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1853). Po wybudzeniu wątek od razu sprawdza, czy proces jest zatrzymany i zatrzymuje się jeśli tak, więc inne sygnały nie będą obsługiwane dopóki proces nie zostanie wznowiony.
## Co trzeba zrobić w Mimikerze
- Nowe akcje w `def_sigact`: `SA_STOP` i `SA_CONT`
- Nowy stan wątku: `TDS_STOPPED`
- Nowy stan procesu: `PS_STOPPED`
- `sig_kill`:
-- Wznawianie procesu
-- Dochodzi dodatkowy przypadek przy wybudzaniu wątku: teraz może też być zatrzymany
-- Może przyda się funkcja do wybudzania wątków, coś w stylu [`setrunnable`](http://bxr.su/NetBSD/sys/kern/kern_synch.c#855)
- Zatrzymywanie procesu w `sig_post`
- `sleepq`: czy chcemy pozostawiać zatrzymane wątki śpiące snem przerywalnym na sleepq? Chyba prościej będzie przerywać sen przed zatrzymaniem
## Co jest w POSIXie ale nie jest priorytetem
- Powiadamianie rodzica o zmianie statusu dziecka