# Lista 2
10 marca 2021: zadania 1-5
17 marca 2021: zadania 6-7
###### 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
| | 2-1 | 2-2 | 2-3 | 2-4 | 2-5 | 2-6 | 2-7 |
| ---------------------:| --- | --- | --- | --- | --- | --- | --- |
| Jacek Bizub |==X==| | X | X | X | X | X |
| Maciej Dudek | | | | | | | |
| Wojciech Jasiński | X | X | X | X | | | |
| Artur Juraszek | X |==X==| X | | | | |
| Michał Myczkowski | | | | | | | |
| Michał Odorczuk | | | | | | | |
| Damian Ratajski | | | | | | | |
| Łukasz Siudek | X | X | | | | | |
| Błażej Sowa | X | X | | | | | |
| Andrzej Turko | X | X | X | X | X |==X==| X |
| Maksymilian Zawartko | X | X | X | X | X | . | X |
:::
> [name=Krystian Bacławski] Uważam, że... moje pytanie jest zasadne!
:::spoiler
Moje rozwiązanie alternatywne.
:::
## Zadanie 2-1
:::info
Autor: Błażej Sowa
:::
[pxCurrentTCB](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/tasks.c?r=9f4d3da8#337)
`pxCurrentTCB` - Wskaźnik na TCB ("Task Control Block") dla zadania, które jest aktualnie w stanie "Running".
`pxReadyTaskLists` - Tablica kolejek zadań dla każdego priorytetu.
[xTaskIncrementCount](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/tasks.c?r=9f4d3da8#2707)
`xTickCount` - Aktualny czas zmierzony przez kernel. Jest inkrementowany w przerwaniu które wykonuje się ze stałą częstotliwością.
> Czemu zadania, które zakończyły swoje działanie wywołując procedurę vTaskDelete, są umieszczane na liście xTasksWaitingTermination?
Ponieważ nie mogą zwolnić pamięci, którą sami używają. Musi to zrobić za nich inne zadanie.
[tasks.c:1198](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/tasks.c?r=9f4d3da8#1198)
> Kto i gdzie zajmuje się zwolnieniem pamięci takich zadań?
Zwolnieniem pamięci zajmie się zadanie Idle (Jałowe).
[tasks.c:3409](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/tasks.c?r=9f4d3da8#3409)
---
> [name=Jacek Bizub]
:::spoiler

:::
## Zadanie 2-2
:::info
Autor: Łukasz Siudek
:::
`pxTopOfStack` - wskaźnik na ostatni element stosu zadania. [tasks.c:254](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/tasks.c?r=9f4d3da8#254)
---
`uxPriority` - wartość z zakresu od `0` do `configMAX_PRIORITIES – 1` określająca priorytet zadania. [tasks.c:262](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/tasks.c?r=9f4d3da8#262)
---
`uxBasePriority` - priorytet nadawany zadaniu w momencie jego utworzenia. Jest wykorzystywany w przypadku, gdy zadanie próbuje przejąć muteks który jest trzymany przez zadanie o niższym priorytecie. Wtedy priorytet zadania trzymającego ten muteks zostaje zwiększony do wartości priorytetu zablokowanego zadania. Takie zachowanie minimalizuje czas oczekiwania zadań o wyższym priorytecie.
[tasks.c:280](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/tasks.c?r=9f4d3da8#280)
---
`ulRunTimeCounter` - licznik czasu spędzonego przez zadanie w stanie "Running" od momentu utworzenia. [tasks.c:293](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/tasks.c?r=9f4d3da8#293)
---
*Q*: Zadanie może być umieszczone jednocześnie na dwóch listach przy użyciu węzłów
`xStateListItem` i `xEventListItem`. Skąd wynika taka potrzeba? Uzasadnij ją na podstawie miejsc wywołań
`vListInsert`, `vListInsertEnd` i `uxListRemove` posługujących się wyżej wymienionymi węzłami.
*A*: `xStateListItem` wskazuje na jeden z węzłów list:
* `pxReadyTasksLists`, gdy zadanie znajduje się w stanie "Ready"
* `xSuspendedTaskList`, gdy zadanie znajduje się w stanie "Suspended"
* `pxDelayedTaskList` bądź `pxOverflowDelayedTaskList`, gdy zadanie znajduje się w stanie "Blocked"
* `xTasksWaitingTermination`, gdy zadanie zostało zakończone i powinny zostać zwolnione jego zasoby.
Zadanie może być wybudzone po wystąpieniu jakiegoś zdarzenia bądź wybudzone przez planistę po upływie określonej liczby ticków. Obecność węzła `xEventListItem` jest zatem wykorzystywana w przypadku nastąpienia eventu.
Przykładowo, zadanie może wejść w stan zblokowany oczekując na pojawienie się elementu w pustej kolejce. W takiej sytuacji wykonywana jest procedura [`vTaskPlaceOnEventList`](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/tasks.c?r=9f4d3da8&fi=vTaskPlaceOnEventList#3064) i `xEventListItem` umieszczany jest w liście [`xTasksWaitingToReceive`](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/queue.c?r=9f4d3da8#1378) należącej do kolejki, aby zostać odblokowanym w momencie pojawienia się danych.
## Zadanie 2-3
:::info
Autor: Artur Juraszek
:::
Oddanie sterowania - dobrowolne zrzeczenie się przez zadanie przydzielonego mu czasu pracy procesora
`pxTopOfStack` musi/powinien być pierwszym polem w TCB, ponieważ w interakcję z nim wchodzi kod zrzucający kontekst przełączanego właśnie zadania napisany w assemblerze - gdyby znajdował się na dalszym offsecie, to kod assemblerowy musiałby być w jakiś sposób parametryzowany szerokościami poszczególnych pól w TCB (które są konfigurowalne) oraz ewentualnych zwyczajów danego kompilatora na temat wyrównywania struktur.
Sam mechanizm przełączania wygląda tak (chyba najlepiej skomentować to już pokazując ekran):
```c=
#define portSAVE_CONTEXT() \
or.w #0x0700,sr; /* mask all interrupts */ \
movem.l d0-a6,-(sp); /* save D0-A6 registers */ \
move.l usp,a0; /* save USP register */ \
move.l a0,-(sp); \
move.l pxCurrentTCB,a0; /* load current task pointer */ \
move.l sp,(a0); /* save stack pointer */
```
skaczemy do [vTaskSwitchContext](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/tasks.c?r=9f4d3da8#vTaskSwitchContext) - tutaj odbywa się proces [decydowania](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/tasks.c?r=9f4d3da8#133) o tym, który zadanie zostanie wykonane jako następne. Kiedy procedura się zakończy, pxCurrentTCB będzie wskazywało już na nowe zadanie
```c=
#define portRESTORE_CONTEXT() \
move.l pxCurrentTCB,a0; /* load current task pointer */ \
move.l (a0),sp; /* restore stack pointer */ \
move.l (sp)+,a0; /* restore USP register */ \
move.l a0,usp; \
movem.l (sp)+,d0-a6; /* restore D0-A6 registers */ \
rte; /* restore SR and PC */
```
## Zadanie 2-4
:::info
Autor: Wojciech Jasiński
:::
* Co się dzieje w trakcie rozruchu planisty?
1. utwórz zadanie jałowe (alokacja statyczna lub dynamiczna) [[kod](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/tasks.c?r=9f4d3da8#1980)]
2. (opcjonalnie) utwórz zadanie obsługujące zegary (przetwarza zdarzenia zegara i śpi) [[kod](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/tasks.c?r=9f4d3da8#2022)]
3. ustaw obsługę `trap #0` na `yPortYieldHandler`
4. zmień kontekst na pierwsze zadanie [[kod](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/portable/m68k-amiga/portasm.S?r=a3121d83#38)]
* Pokaż w jaki sposób procesor zaczyna wykonywać instrukcje pierwszego wybranego zadania
- ustawiamy kontekst (`pxCurrentTCB`) w [main](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/examples/graphics/main.c?r=84123706#78) : [xTaskCreate](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/tasks.c?r=9f4d3da8#810) : [prvAddNewTaskToReadyList](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/tasks.c?r=9f4d3da8#1088)
- aktywujemy ten kontekst (przywracamy stan wliczając PC i wykonujemy RTE (ReTurn from Exception)) w [main](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/examples/graphics/main.c?r=84123706#81) : [vTaskStartScheduler](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/tasks.c?r=9f4d3da8&fi=vTaskStartScheduler#2075) : [xPortStartScheduler](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/portable/m68k-amiga/port.c?r=a3121d83&fi=xPortStartScheduler#93) : [vPortStartFirstTask](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/portable/m68k-amiga/portasm.S?r=a3121d83#39)
* Kto i jak tworzy rozruchowy kontekst zadania?
- [main : xTaskCreate](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/examples/graphics/main.c?r=84123706#78)
- [xTaskCreate : prvInitialiseNewTask](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/tasks.c?r=9f4d3da8#809)
- a tutaj konkretnie inicjalizujemy stos: [prvInitialiseNewTask](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/tasks.c?r=9f4d3da8#1023) : [pxPortInitialiseStack](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/portable/m68k-amiga/port.c?r=a3121d83&fi=pxPortInitialiseStack#62)
## Zadanie 2-5
:::info
Autor: Maksymilian Zawartko
:::
Blokowanie przerwań to chwilowe wyłączenie ich obsługi, celem realizacji zadania, w którym mogłyby przeszkodzić.
Przerwania należy blokować, kiedy w sekcji krytycznej aktualizowane lub odczytywane są listy zadań (a więc w szczególności zadania) i, ogólniej, dowolne globalne dane.
[queue.c:241](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/queue.c?r=9f4d3da8#241)
[queue.c:261](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/queue.c?r=9f4d3da8#261)
[queue.c:542](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/queue.c?r=9f4d3da8#542)
[queue.c:761](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/queue.c?r=9f4d3da8#761)
[queue.c:1303](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/queue.c?r=9f4d3da8#1303)
[queue.c:1448](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/queue.c?r=9f4d3da8#1448)
[queue.c:1556](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/queue.c?r=9f4d3da8#1556)
[queue.c:1607](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/queue.c?r=9f4d3da8#1607)
Sekcja krytyczna to fragment kodu, w którym realizowany jest dostęp do dzielonego zasobu. W sekcji krytycznej może wykonywać się tylko jeden kontekst naraz.
Liczba wywołań `taskENTER_CRITICAL` jest utrzymywana dla każdego wątku osobno, bo będąc w sekcji krytycznej wątek może stworzyć inny i przełączyć się na niego. Wychodząc z tego nowego wątku chcemy wiedzieć, czy zamknął za sobą wszystkie sekcje krytyczne.
## Zadanie 2-6
:::info
Autor: Andrzej Turko
:::
Te procedury blokują wywłaszczanie, ale nie przerwania. Ponadto, przetwarzanie ticków jest zablokowane, ponieważ jest ono obsługiwane przez scheduler, który jest zawieszany.
Dlatego tymi procedurami tworzy się sekcje krytyczne do:
* odczytywania liczby ticków
[przykład](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/tasks.c?r=9f4d3da8#2609)
* Przetwarzania list stanów zadań (np. delayed albo ready), ale nie event list, która może być modyfikowana przez przerwania (nawet gdy scheduler jest zawieszony, zadania są usuwane z event list)
[przykład](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/tasks.c?r=9f4d3da8#2629)
[xTaskResumeAll](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/tasks.c?r=9f4d3da8#xTaskResumeAll) oprócz zmiany wartości licznika musi:
* Dodać do kolejki ready wszystkie zadania, które są w stanie pending ready: Zadania odblokowane podczas gdy scheduler był zawieszony, nie mogły zostać dodane bezpośrednio do kolejki ready
* Przetworzyć wszystkie ticki: Zawieszenie schedulera powoduje też zatrzymanie przetwarzania ticków. Nie można ich opuścić, aby wszystkie zadania, które były opóźnione, zostały uruchomione w odpowiednim czasie.
* Oddać sterowanie innemu zadaniu: Powyższe akcje mogły sprawić, że na kolejce ready pojawiło się zadanie o wyższym priorytecie niż obecnie wykonywane. W takim wypadku konieczny jest rescheduling.
## Zadanie 2-7
:::info
Autor: Jacek Bizub
:::
> Procedury FreeRTOS, które można wołać tylko z procedur obsługi przerwań (sufiks `FromISR`), używają `portSET_INTERRUPT_MASK_FROM_ISR` i `portCLEAR_INTERRUPT_MASK_FROM_ISR`. Przy ich pomocy realizuje się sekcje krytyczne na architekturach dopuszczających zagnieżdżanie przerwań. Na podstawie [4, 6.8] wyjaśnij dlaczego jest to koniecznie i o jakie sekcje krytyczne chodzi.
Przerwanie może zostać przerwane przez inne przerwanie (o wyższym priorytecie). Może się zdarzyć tak, że przerwania te operują na wspólnych strukturach danych. Maskując `wszystkie` przerwania synchronizujemy dostęp do takiej pamięci.
> Przeprowadź uczestników zajęć przez procedurę ulPortSetIPL i wyjaśnij co ona robi.
```c
19 ENTRY(ulPortSetIPL)
20 move.l 4(sp),d0
21 move.w sr,-(sp)
22 move.w sr,d1
23 and.w #0xf8ff,d1 /* old SR with IPL bits cleared */
24 and.w #0x0700,d0 /* argument with IPL bits left */
25 or.w d0,d1
26 move.w d1,sr /* set new value of IPL in SR */
27 move.w (sp)+,d0
28 and.w #0x0700,d0 /* return IPL bits of original SR */
29 rts
30 END(ulPortSetIPL)
```
[ulPortSetIPL](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/portable/m68k-amiga/portasm.S?r=a3121d83#ulPortSetIPL)