---
# System prepended metadata

title: Lista 5
tags: [sju21, ćwiczenia]

---

# Lista 5

###### tags: `sju21` `ćwiczenia`

## Deklaracje

Gotowość rozwiązania zadania należy wyrazić poprzez postawienie X w odpowiedniej kolumnie! Jeśli pożądasz zreferować dane zadanie w trakcie dyskusji (co najwyżej jedno!) oznacz je znakiem ==X== na żółtym tle.

**UWAGA: Tabelkę wolno edytować tylko wtedy, gdy jest na zielonym tle!**

:::danger
|                       | 5-1 | 5-2 | 5-3 | 5-4 | 5-5 |
| ---------------------:| --- | --- | --- | --- | --- |
|           Jacek Bizub |  X  |     |  X  |  X  |  X  |
|     Wojciech Jasiński |  X  |  X  |  X  |     |  X  |
|        Artur Juraszek |     |     |     |     |     |
|     Michał Myczkowski |     |     |     |     |     |
|       Michał Odorczuk |  X  |     |  X  |  X  |     |
|       Damian Ratajski |     |     |     |     |     |
|         Łukasz Siudek |     |     |     |     |     |
|           Błażej Sowa |     |     |     |     |     |
|         Andrzej Turko |  X  |  X  |  X  |  X  |  X  |
|  Maksymilian Zawartko |==X==|  X  |  X  |  X  |  X  |
:::

## Zadanie 5-1

:::info
Autor: Maksymilian Zawartko
:::

Wątki przerwań to wątki jądra, które uruchamiają ciąg ISRów (handlerów) wyzwolone przerwaniem sprzętowym lub programowym. Każda ISR ma nazwę, powiązaną funkcję, argument, priorytet i różne flagi. Każdy wątek przerwań ma listę ISRów posortowaną wg priorytetu, dzięki czemu ISRy o wyższym priorytecie są wykonywane przed tymi o niższym. Każdy wątek przyjmuje za swój priorytet najwyższy priorytet ISRa lub PRIO_MAX, jeśli nie ma ISRów. Wątki przerwań są powiązane z pojedynczym źródłem przerwań, reprezentowanym przez liczbę (vector number).


FreeBSD Device Drivers, 126, Interrupt Handlers in FreeBSD:

> In FreeBSD, interrupt handlers are composed of a filter routine, an ithread routine, or both.

ISRy składają się z filtra (filter routine), ithreada (ithread routine), lub obu. Filtr nie może zmieniać kontekstu, tylko operuje w tym przerwania. Nie może też zatem się blokować, a jedyne dostępne dla niego mechanizmy synchronizacji to spinlocki (spin mutexes). Z tych właśnie powodów filtry są zwykle używane z urządzeniami, które wymagają niewywyłaszczalnych ISRów.
Filtr może albo całkowicie obsłużyć przerwanie, albo przenieść odpowiedzialność za wykonanie ciężkiej obliczeniowo pracy na powiązanego ithreada, jeśli taki istnieje.
Wartości zwracane przez filtr:
FILTER_STRAY - oznacza, że filtr nie mógł obsłużyć przerwania; błąd.
FILTER_HANDLED - przerwanie zostało całkowicie obsłużone.
FILTER_SCHEDULE_THREAD - przerwania zostało przekazane do ithreada.

ithread operuje w swoim własnym kontekście. W ithreadzie można robić wszystko poza dobrowolną zmianą kontekstu (spaniem) i czekaniem na zmienną warunkową. Większość ISRów we FreeBSD to ithread, bo są wywłaszczalne.


pre_ithread jest wołana przed wykonaniem ithreada bez filtrów. Robi 2 rzeczy.
1. Upewnia się, że nie nastąpi burza przerwań (interrupt storm) ze źródła powiązanego z ithreadem, zwykle przez wyłączenie tych przerwań level-triggered do końca wykonania ithreada.
2. Upewnia się, że CPU może odbierać przerwania z innych źródeł. On some platforms this is done by acknowledging the interrupts via an EOI.

post_ithread jest wołana po wykonaniu ithreada. Upewnia się, że CPU znów może przyjmować przerwania ze źródła wyciszonego (wyłączonego) przez pre_ithread. Zwykle implementacja obejmuje włączenie przerwań level-triggered wyłączonych przez pre_ithread.

post_filter jest wołana podczas wykonania filtra (nie po - tak wynika z komentarza w `interrupt.h`). Upewnia się, że CPU znów może przyjmować przerwania. On some platforms this is done by acknowledging the interrupts via an EOI.
  
## Zadanie 5-2

:::info
Autor: Wojciech Jasiński
:::
  * jakie niepożądane zjawiska mogłyby wystąpić, gdybyśmy wewnątrz procedur `ih_filter` i `ih_handler` przeszli odpowiednio w sen ograniczony i sen nieograniczony?
    - sen ograniczony w `ih_filter`
      - czekamy aż pewien wątek zwolni blokadę, na którą czekamy
        - jego priorytet jest podbijany przez turnstile, więc nie jest beznadziejnie
        - procedury obsługi przerwań `ih_handler` się nie wykonują (niższy priorytet)
        - skoro zmieniamy kontekst na inny wątek, to przywracamy jego maskę przerwań i znowu możemy je otrzymywać
          - w przypadku przerwań wyzwalanych poziomem wprowadzi nas to w pętlę obsługi przerwań (ISR -> filter -> sleep -> zmień kontekst -> ISR)
      - fatalny przypadek: wątek, na który czekamy, czeka na wątek, w którego kontekście obsługujemy przerwanie -> deadlock
    - sen nieograniczony w `ih_handler`
      - przerwanie jest w tym czasie wyłączone
      - nie wiemy jak długo będziemy spać, więc nie wiemy, jak dużo przerwań stracimy
      - całkiem możliwe, że urządzenie nie dostanie ważnej odpowiedzi w czasie i przestanie działać

## Zadanie 5-3

:::success
Autor: Michał Odorczuk
:::
> The functions tsleep(), [...] handle event-based thread blocking.

> If priority includes the PCATCH flag, pending signals are allowed to interrupt the sleep, otherwise pending signals are ignored during the sleep.
> 
> Because it is complex to
handle signals in the midst of doing some other operation, many sleep requests are
not interruptible; that is, a thread will not be scheduled to run until the event for
which it is waiting occurs. For example, a thread waiting for disk I/O will sleep
with signals blocked. [...] Occasionally, an event that is supposed to occur
quickly, such as a disk I/O, will get held up because of a hardware failure.
Because the thread is sleeping in the kernel with signals blocked, it will be impervious to any attempts to send it a signal, even a signal that should cause it to exit
unconditionally. The only solution to this problem is to change sleep()s on hardware events that may hang to be interruptible.
In the remainder of this book, we shall always use sleep() when referring to
the routine that puts a thread to sleep, even when one of the mtx_sleep(),
sx_sleep(), rw_sleep(), or t_sleep() interfaces is the one that is being used.


1) Oczekujemy na stronę z pamięci - dysk ulega awarii - zdarzenie jest ignorowane - sen nie zostaje przerwany i wątek śni snem wiecznym
2) Oczekujemy na inny obiekt w systemie - dysk ulega awarii - zdarzenie jest ignorowane - jesteśmy wybudzani ale nie jesteśmy świadomi jego awarii

Proces może wysypać się ze względu na opuszczone komunikaty lub wręcz nigdy się nie wybudzić.


:::spoiler
1. Dysk może ulec awarii. W takim wypadku wątek, który czekał na zdarzenie związane z dyskiem (I/O), nigdy się nie obudzi, nawet po wysłaniu do niego sygnału.
2. Sygnały mogą się kumulować, może ich być bardzo dużo, co ma negatywny wpływ na zajmowaną przez nie pamięć i późniejszy czas ich obsługi.
:::

## Zadanie 5-4

:::info
Autor: Jacek Bizub
:::

> W  [1,§3.4]  opisano  procedurę  `hardclock`.  W  nowszych  wersja  jądra FreeBSD jej  funkcje przejęła  procedura [handleevents](https://mimiker.ii.uni.wroc.pl/source/xref/FreeBSD/sys/kern/kern_clocksource.c?r=80f39bd9#handleevents),  która  jest  wołana  w  kontekście  przerwania  sprzętowego  z  procedury [hardclockintr](https://mimiker.ii.uni.wroc.pl/source/xref/FreeBSD/sys/kern/kern_clocksource.c?r=80f39bd9#hardclockintr). Ograniczając się do procedur z modułu [kern_clocksource.c](https://mimiker.ii.uni.wroc.pl/source/xref/FreeBSD/sys/kern/kern_clocksource.c?r=80f39bd9) przeprowadź uczestnikówzajęć przez procedurę [handleevents](https://mimiker.ii.uni.wroc.pl/source/xref/FreeBSD/sys/kern/kern_clocksource.c?r=80f39bd9#handleevents) oraz opisz zadania jakie realizuje. Zakładamy, że parametr `fake` jest równy `0`. Opisz zawartość struktury [cpu_state](https://mimiker.ii.uni.wroc.pl/source/xref/FreeBSD/sys/kern/kern_clocksource.c#pcpu_state).

```c=
113  struct pcpu_state {
114  	struct mtx	et_hw_mtx;	/* Per-CPU timer mutex. */
115  	u_int		action;		/* Reconfiguration requests. */
116  	u_int		handle;		/* Immediate handle resuests. */
117  	sbintime_t	now;		/* Last tick time. */
118  	sbintime_t	nextevent;	/* Next scheduled event on this CPU. */
119  	sbintime_t	nexttick;	/* Next timer tick time. */
120  	sbintime_t	nexthard;	/* Next hardclock() event. */
121  	sbintime_t	nextstat;	/* Next statclock() event. */
122  	sbintime_t	nextprof;	/* Next profclock() event. */
123  	sbintime_t	nextcall;	/* Next callout event. */
124  	sbintime_t	nextcallopt;	/* Next optional callout event. */
125  	int		ipi;		/* This CPU needs IPI. */
126  	int		idle;		/* This CPU is in idle mode. */
127  };
```

------

Obsługa `hardclock` musi być jak najszybsza. Nie chcemy zgubić żadnych ticków czy pakietów sieciowych. Dlatego główna procedura zajmuje się obsługą krytycznych rzeczy (jak nastawienie czasu systemowego i timerów). Mniej ważne rzeczy są delegowane do wątku o mniejszym priorytecie (`softclock`).

Aby nie wykonywać za często obsługi przerwania zegarowego, nie wykonujemy go standardowo 1000 razy na sekundę a zamiast tego wyliczamy kiedy nastąpi następny event wymagający obsługi i nastawiamy zegar żeby wtedy nas obudził.

Jeżeli system nie posiada oddzielnych zegarów do zbierania statystyk czy profilowania to hardclock wykonuje ich rolę.

## Zadanie 5-5

:::info
Autor: Andrzej Turko
:::

**userret()** jest wołana po to, aby z przestrzeni jądra wrócić do wykonywania kodu użytkownika (np. po wykonaniu pułapki). Podczas tej procedury sygnały są dostarczane do zadania. Jeśli jest to konieczne, znajdujemy nowe zadanie schedulerem i wracamy do niego.

[mi_userret](https://mimiker.ii.uni.wroc.pl/source/xref/NetBSD/sys/sys/userret.h?r=1fe5c4da#mi_userret)
1. Upewniamy się, że nikt nie trzyma kernel locka
2. Jeśli na tym cpu potrzebny jest rescheduling, wywłaszczamy obecne zadanie
3. Jeśli są odpowiednie flagi, wołamy lwp_userret
4. Uaktualniamy priorytet obecnego zadania (ustawiamy na nasz)

[cpu_need_resched](https://mimiker.ii.uni.wroc.pl/source/xref/NetBSD/sys/arch/riscv/riscv/riscv_machdep.c?r=1fe5c4da#cpu_need_resched)
1. Jeżeli możemy wywłaszczyć zadanie od razu: wysyłamy IPI (wywłaszczenie) na inne cpu, a jeśli mamy zrobić reschedule lokalnie, powodujemy odpowiednie przerwanie softwareowe.
2. Jeśli rescheduling ma się wydarzyć na innym cpu, generujemy na nim przerwanie.
3. Jeśli chcemy wywołać rescheduling normalnie, requestujemy o wywołanie AST (Asynchronous Software Trap).
AST wywołuje mi_userret, które zajmie się reschedulingiem.

[lwp_userret](https://mimiker.ii.uni.wroc.pl/source/xref/NetBSD/sys/kern/kern_lwp.c?r=1fe5c4da#lwp_userret)
1. Przetwarzamy sygnały.
2. W przypadku core-dump albo suspension -- zawieszamy nasze wykonywanie, zapisujem (mi_switch zmienia kontekst)
3. W zależności od flag, kończymy zadanie.
4. Uaktualniamy dane zadania.

[preempt](https://mimiker.ii.uni.wroc.pl/source/xref/NetBSD/sys/kern/kern_synch.c?r=1fe5c4da#preempt)
1. Zwalniamy kernel lock
2. Jeśli zostaliśmy oznaczeni jako CPU hogger, to zdejmujemy podwyższenie priorytetu (kernel priority boost)
3. Wołamy mi_switch -- zmiana kontekstu.