---
# System prepended metadata

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

---

# Lista 3

17 marca 2021:

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

## Zadanie 3-1

:::info
Autor: Michał Myczkowski
:::

> Zreferuj w jaki sposób w systemie FreeRTOS zachodzi wywłaszczanie zadań. Zakładamy, że [EnterIntr](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/kernel/intr.S?r=6065630e#EnterIntr) wywoła procedurę [SystemClockTickHandler](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/examples/preemption/main.c?r=38be906a#SystemClockTickHandler) i ustawi flagę [xNeedRescheduleTask](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/kernel/port.c?r=7a11ae78#xNeedRescheduleTask). Pierwsza instrukcja procedury obsługi przerwania leży pod adresem [AmigaLvl3Handler](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/kernel/intr.S?r=6065630e#AmigaLvl3Handler). Należy dotrzeć do miejsca, w którym zakończone zostanie przełączanie kontekstu na nowo wybrane zadanie. Co mogłoby się popsuć, gdybyśmy dopuścili zmianę kontekstu, gdy SR$_{IM}$ > 0?
>
>*Uwaga: To gdzie skacze procedura «EnterIntr» będziemy analizować w następnym zadaniu.*

W naszej konfiguracji FreeRTOS mamy ustawione:
[#define configUSE_PREEMPTION 1](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOSConfig.h?r=acd50743#16)
[#define configUSE_TIME_SLICING 1](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/include/FreeRTOS.h?r=9f4d3da8#794)

Co oznacza, że korzystamy z algorytmu planisty zwanego: 
"Fixed Priority Pre-emptive Scheduling with Time Slicing"
oznacza to:

|pojęcie|definicja|
|-|-|
|Fixed Priority| algorytm planisty nie ingeruje w przydzielone priorytety zadań, ale też nie zabrania im zmieniać priorytet swój lub innego zadania|
|Pre-emptive|Algorytm "Wywłaszczający" automatycznie wywłaszczy zadanie jeżeli na Ready-Liście pojawi się zadanie o wyższym priorytecie. Bycie wywłaszczonym oznacza, że mimowolnie zostaje nam odebrany czas procesora ( bez ustępowania lub blokowania się ) i zostajemy przeniesieni ze stanu Running do stanu Ready |
|Time Slicing| Oznacza to, że czas procesora jest dzielony między zadania o tym samym priorytecie. Kolejne zadanie z listy zostaje wyznaczone na koniec każdego "plastra czasu" czyli co 'tyknięcie zegara' (u nas configTICK_RATE_HZ = 50 czyli 1/50s)|

![](https://i.imgur.com/WNmBVEs.png)

#### Co mogłoby się popsuć, gdybyśmy dopuścili zmianę kontekstu, gdy SR$_{IM}$ > 0?
Mogłoby dojść do sytuacji w której wykonanie ISR zostałoby odroczone.

Przykład:
![](https://i.imgur.com/oQYcR3t.png)


## Zadanie 3-2

:::info
Autor: Artur Juraszek
:::

Wygaszanie pionowe - czas pomiędzy wyświetlanymi przez monitor kineskopowy klatkami.
W tym czasie odpowiadające za wyświetlanie obrazu działo elektronowe wraca z pozycji górnej na dolną(?)

Przerwanie VERTB jest przypisane do priorytetu 3, zatem zaczynamy działanie tutaj:

```c=
ENTRY(AmigaLvl1Handler)
        FIRST   INTB_TBE
        NEXT    INTB_DSKBLK
        NEXT    INTB_SOFTINT
        FINISH
END(AmigaLvl1Handler)
```
>[name=Michał Myczkowski] 
:::spoiler
```as=
40 # Level 3 Interrupt Autovector
41 
42 ENTRY(AmigaLvl3Handler)
43         FIRST   INTB_COPER
44         NEXT    INTB_VERTB
45         NEXT    INTB_BLIT
46         FINISH
47 END(AmigaLvl3Handler)
```
:::


```c=
.macro  FIRST   intb
         movem.l d0-d1/a0-a1,-(sp)
         moveq   #\intb,d1        
         move.w  custom+intreqr,d0  // http://amigadev.elowar.com/read/ADCD_2.1/Hardware_Manual_guide/node0037.html
         and.w   custom+intenar,d0  // http://amigadev.elowar.com/read/ADCD_2.1/Hardware_Manual_guide/node0036.html
         btst    d1,d0              // sprawdza wartość bitu intb w tym, co wyliczyliśmy ^wyżej. zapala (lub nie) condition code Z(ero)
         jne     EnterIntr          

.macro   NEXT    irq
         addq.w  #1,d1
         btst    d1,d0
         jne     EnterIntr
.endm

.macro  FINISH
        jra     LeaveIntr
.endm
```

```c=
ENTRY(EnterIntr)
        /* Make INTF_* mask, and clear pending interrupt. */
        clr.w   d0                // d0 := #0
        bset    d1,d0             // zapala bit odpowiadający właśnie obsługiwanemu przerwaniu
        move.w  d0,custom+intreq  // wyłączamy żądanie tego przerwania - bit SET/CLR jest wygaszony, więc odpowiada to wyzerowaniu

        lea     IntVec,a0
        lsl.w   #3,d1             // d1 << 3
        add.w   d1,a0             // każdy wpis w IntVec ma 8 bajtów

        /* Enter interrupt service routine. */
        move.l  (a0)+,a1                /* IntVecEntry_t.code */
        move.l  (a0)+,-(sp)             /* IntVecEntry_t.data */
        jsr     (a1)
        addq.l  #4,sp
END(EnterIntr)
```

Widzimy jednak, że przypisaną do tego wektora procedurą jest [interrupt chain](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/kernel/port.c?r=7a11ae78#147),
mechanizm pozwalający na elastyczną obsługę danego przerwania poprzez rejestrowanie/derejestrowanie wykonywanych po kolei procedur w trakcie działania systemu - każda z nich ma również przypisany priorytet, który decyduje o kolejności wywołań.

https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/kernel/include/interrupt.h?r=7a11ae78#79

https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/kernel/include/interrupt.h?r=7a11ae78#106

https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/kernel/intsrv.c?r=7a11ae78
https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/examples/preemption/main.c?r=38be906a#106

> Gdzie następuje poinformowanie sprzętu o końcu obsługi przerwania?

Wygląda na to, że w `EnterIntr` - zatem zanim obsługa się w ogóle zacznie. Przerwanie tego samego typu nie przerwie jednak działania danej procedurze obsługi, ponieważ podczas całej zabawy przypisany temu przerwaniu priorytet (3) pozostaje zamaskowany w SR.


## Zadanie 3-3

:::info
Autor: Wojciech Jasiński
:::
  * Przeprowadź słuchaczy przez źródła czasomierza [cia-line.c](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/drivers/cia-line.c#cia-line.c) zliczającego linie rastra
    - [LineCounterInit](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/drivers/cia-line.c?r=2608cf89#64)
      - podpinamy się pod zewnętrzne przerwania `ExterChain`
        - handler: [LineCounterHandler](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/drivers/cia-line.c?r=2608cf89#37), stan: [WaitingTasks](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/drivers/cia-line.c?r=2608cf89#8)
    - [LineCounterHandler](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/drivers/cia-line.c?r=2608cf89#37)
      - [51](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/drivers/cia-line.c?r=2608cf89#51): wybudzanie odpowiednich wątków przez `vTaskNotifyGiveFromISR`
    - [LineCounterWait](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/drivers/cia-line.c?r=2608cf89#76)
      - [83](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/drivers/cia-line.c?r=2608cf89#83): ustalamy czas
      - 87-88: dodajemy do listy `WaitingTasks`
      - 90: przestawiamy czasomierz, jeśli nowe zadanie ma być wybudzone jako pierwsze
      - 92: oczekujemy notyfikacji (wysyłanej przez `LineCounterHandler`
  * Zauważ, że z czasomierza może korzystać wiele zadań równocześnie – jak zostało to osiągnięte?
    Trzymamy listę oczekujących zadań `WaitingTasks` posortowanej po oczekiwanej liczbie linii. Czasomierz nastawiamy zawsze na najwcześniejsze zadanie.

## Zadanie 3-4

:::info
Autor: Maksymilian Zawartko
:::

Zegar systemowy liczy takty systemowe.

Uśpienie zadania polega na wykluczeniu go z kolejki zadań do wykonania na pewien czas.

Wybudzenie to ponowne dodanie zadania do kolejki.

[vTaskDelay](https://mimiker.ii.uni.wroc.pl/source/xref/FreeRTOS-Amiga/FreeRTOS/tasks.c?r=9f4d3da8#vTaskDelay)

`xTaskIncrementTick` iteruje po uśpionych zadaniach i sprawdza, czy wymagają wybudzenia. Jeśli nie, następuje przerwanie iteracji, bo zadania są posortowane wg czasu snu. Każde wybudzane zadanie jest usuwane z listy zadań uśpionych i dodawane do 'ready'. Dodatkowo, jeśli jedno z wybudzonych zadań ma priorytet wyższy od aktualnie wykonywanego, ustawiane jest `xSwitchRequired`:
```c=
if( xConstTickCount < xNextTaskUnblockTime ) { }

for( ;; ) {
	if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) {
		xNextTaskUnblockTime = portMAX_DELAY;
		break;
	}
	else {
		pxTCB = listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );
		xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) );

		if( xConstTickCount < xItemValue ) {
			xNextTaskUnblockTime = xItemValue;
			break;
		}

		( void ) uxListRemove( &( pxTCB->xStateListItem ) );

		if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) {
			( void ) uxListRemove( &( pxTCB->xEventListItem ) );
		}

		prvAddTaskToReadyList( pxTCB );

		if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) {
			xSwitchRequired = pdTRUE;
		}
	}
}
```

## Zadanie 3-5

:::info
Autor: Jazek Bizub
:::

> Dlaczego należy unikać funkcji rekurencyjnych programując wewnątrz jądra?

Każde wywołanie funkcji wymaga umieszczenia na stosie ramki (adres powrotu, backup rejestrów itd.). Jądro posiada stos ograniczonej wielkości a przepełnienie stosu supervisora może mieć tragiczne skutki dla całego systemu.

> Na podstawie strony [How big should the stack be](https://freertos.org/FAQMem.html#StackSize) wyjaśnij jak wyznaczyć górne ograniczenie na rozmiar stosu.

 Exactly as when writing a bare metal application, the amount of stack required is dependent on the following application specific parameters:
-    The function call nesting depth
-   The number and size of function scope variable declarations
-   The number of function parameters
-   The processor architecture
-   The compiler
-   The compiler optimisation level
-   The stack requirements of interrupt service routines – which for many RTOS ports is zero as the RTOS will switch to use a dedicated interrupt stack on entry to an interrupt service routine.

.
.
.

While it is not easy to determine how much stack to allocate a task, the RTOS does provide functionality that allows a task’s stack size to be tuned taking a pragmatic trial and error approach; the [uxTaskGetStackHighWaterMark()](https://freertos.org/uxTaskGetStackHighWaterMark.html) API function can be used to see how much stack has actually been used, allowing the stack size to be reduced if more was allocated than necessary, and the stack overflow detection features can be used to determine if a stack is too small. 


> Czemu należy brać pod uwagę procedury obsługi przerwań?

ISR nie posiada własnego kontekstu *(\* w niektórych systemach to nie jest prawdą)*, "kradnie" kontekst (w tym także stos) od zadania wykonywanego kiedy przerwanie zostało odebrane.

> Na podstawie [Stack Usage and Stack Overflow Checking](https://freertos.org/Stacks-and-stack-overflow-checking.html) wyjaśnij strategie wykrywania przepełnienia stosu w systemach bez ochrony pamięci.

**Metoda 1:** Sprawdzanie Stack Pointera w trakcie zmiany kontekstu

Jądro w trakcie zmiany kontekstu może sprawdzić czy wartość SP mieści się w prawidłowym zakresie.

*Wada*: Mogło nastąpić przepełnienie w trakcie działania programu ale w momencie zmiany kontekstu SP jest prawidłowy.

**Metoda 2:** Kanarek

Na końcu stosu (we FreeRTOSie ostatnie 16 bajtów) umieszczamy kanarka.
W trakcie zmiany kontekstu sprawdzamy czy ten nie zostały nadpisany. Jeśli został to musimy założyć przepełnienie.
