# 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 ![](https://www.unitedchurchofsoro.org/wp-content/uploads/blog-road-runner-self-defeating-statements-2048px-2000x1200.jpg) ::: ## 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)