285 lines
10 KiB
TeX
285 lines
10 KiB
TeX
\documentclass[10pt]{article}
|
|
\usepackage[T1]{fontenc}
|
|
\usepackage[utf8]{inputenc}
|
|
\usepackage[polish]{babel}
|
|
\usepackage[a4paper,margin=1.55cm]{geometry}
|
|
\usepackage{array,tabularx,booktabs}
|
|
\usepackage{amsmath,amssymb}
|
|
\usepackage{xcolor,listings}
|
|
\usepackage{hyperref,fancyhdr,lastpage,enumitem}
|
|
|
|
\definecolor{accent}{HTML}{16324A}
|
|
\definecolor{accentlight}{HTML}{EEF3F7}
|
|
\definecolor{rulegray}{HTML}{D7DEE5}
|
|
\hypersetup{colorlinks=true,linkcolor=accent,urlcolor=blue}
|
|
\IfFileExists{build-meta.tex}{\input{build-meta.tex}}{\newcommand{\BuildCommit}{local}}
|
|
\newcommand{\PublisherDomain}{mpabi}
|
|
\newcommand{\CardArea}{inf}
|
|
\newcommand{\CardSeries}{freertos-cpp}
|
|
\newcommand{\CardNumber}{04}
|
|
\newcommand{\CardCount}{16}
|
|
\newcommand{\CardSlug}{scheduler-states}
|
|
\newcommand{\CardVersion}{v00.01}
|
|
\newcommand{\DocumentUUID}{853a7dd7-b00b-4f4a-96e8-c160fc5bb04a}
|
|
\newcommand{\blank}[1]{\rule{#1}{.2pt}}
|
|
|
|
\lstset{
|
|
language=C++,basicstyle=\ttfamily\scriptsize,columns=fullflexible,
|
|
keepspaces=true,frame=single,breaklines=true,showstringspaces=false,
|
|
numbers=none,backgroundcolor=\color{accentlight},rulecolor=\color{rulegray}
|
|
}
|
|
\pagestyle{fancy}
|
|
\fancyhf{}
|
|
\lhead{\textbf{K04 · FreeRTOS C++ · scheduler}}
|
|
\rhead{\small L03 · stany, priorytety, ticki}
|
|
\lfoot{\scriptsize commit \BuildCommit}
|
|
\cfoot{\scriptsize \thepage/\pageref{LastPage}}
|
|
\rfoot{\scriptsize V11.3.0 / \CardVersion}
|
|
\setlength{\headheight}{14pt}
|
|
\setlength{\footskip}{19pt}
|
|
\setlist[itemize]{nosep,leftmargin=1.45em}
|
|
\setlist[enumerate]{nosep,leftmargin=1.65em}
|
|
|
|
\begin{document}
|
|
\sloppy
|
|
|
|
\begin{center}
|
|
{\LARGE\bfseries Scheduler: stany, priorytety i typowane ticki}\par
|
|
\vspace{.25em}
|
|
{\large przewidź przełączenie, potem udowodnij je śladem}\par
|
|
\end{center}
|
|
|
|
\noindent\begin{tabularx}{\textwidth}{@{}p{1.65cm}Xp{1.55cm}X@{}}
|
|
\toprule
|
|
Karta & K04 / \CardCount & Czas & 30 minut \\
|
|
Platforma & Hazard3 / RV32I & Język & freestanding C++17 \\
|
|
Scheduler & preemption + time slicing & Kernel & V11.3.0, bez zmian \\
|
|
Wersja & \CardVersion & UUID karty & \texttt{853a7dd7-...} \\
|
|
\bottomrule
|
|
\end{tabularx}
|
|
|
|
\section*{Cel i jedna sekwencja dowodowa}
|
|
|
|
Dwa zadania A i B mają priorytet 2. Najpierw scheduler dzieli CPU między
|
|
równych. Potem A blokuje się na 3 ticki. Na końcu A podnosi priorytet B do 3.
|
|
Nie zgadujemy kolejności --- zapisujemy stany, ticki oraz znaczniki wykonania.
|
|
|
|
\begin{center}
|
|
\texttt{READY} $\rightarrow$ \texttt{RUNNING} $\rightarrow$
|
|
\texttt{BLOCKED} $\rightarrow$ \texttt{READY} $\rightarrow$
|
|
\texttt{RUNNING} $\rightarrow$ \texttt{DELETED}
|
|
\end{center}
|
|
|
|
\noindent\fcolorbox{accent}{accentlight}{%
|
|
\begin{minipage}{.94\textwidth}
|
|
\textbf{Dwa warunki K04.} Zadanie o najwyższym priorytecie wygrywa tylko wtedy,
|
|
gdy jest gotowe. Tick jest jednostką schedulera, nie ukrytą nazwą milisekundy.
|
|
\end{minipage}}
|
|
|
|
\section*{Plan 30 minut}
|
|
|
|
\begin{tabularx}{\textwidth}{@{}p{1.35cm}p{3.0cm}X@{}}
|
|
\toprule
|
|
Czas & Tryb & Dowód ucznia \\
|
|
\midrule
|
|
0--4 & predykcja & tabela stanów i bieżącego zadania \\
|
|
4--8 & czas typowany & \texttt{Ticks} kontra \texttt{TickPoint} \\
|
|
8--13 & time slicing & A--B--A albo B--A--B przy priorytecie 2 \\
|
|
13--19 & blokada & A=BLOCKED, B=RUNNING, różnica ticków 3 \\
|
|
19--25 & priorytet & BEFORE--HIGH--AFTER ma wartości 1--2--3 \\
|
|
25--30 & wyjście & delay względny/okresowy i granica \texttt{TaskRef} \\
|
|
\bottomrule
|
|
\end{tabularx}
|
|
|
|
\section*{Najpierw przewidź}
|
|
|
|
Który identyfikator pojawi się pierwszy: A czy B? \blank{2cm}\quad
|
|
Czy test powinien wymagać właśnie tej odpowiedzi? \blank{5cm}
|
|
|
|
\newpage
|
|
\section{Stany są warunkiem kwalifikacji do CPU}
|
|
|
|
\begin{tabularx}{\textwidth}{@{}p{2.5cm}p{4.0cm}X@{}}
|
|
\toprule
|
|
Stan & Czy może teraz dostać CPU? & Typowa przyczyna \\
|
|
\midrule
|
|
\texttt{eRunning} & tak, jedno zadanie na rdzeń & scheduler właśnie je wybrał \\
|
|
\texttt{eReady} & tak, czeka na wybór & równy/niższy priorytet lub wywłaszczenie \\
|
|
\texttt{eBlocked} & nie & delay albo oczekiwanie na zdarzenie \\
|
|
\texttt{eSuspended} & nie & jawne zawieszenie, nie upływ czasu \\
|
|
\texttt{eDeleted} & nie & stan terminalny w śladzie tej karty \\
|
|
\bottomrule
|
|
\end{tabularx}
|
|
|
|
\subsection*{Pułapka „najwyższy zawsze działa”}
|
|
|
|
Jeżeli A ma priorytet 4, ale jest \texttt{BLOCKED}, a B ma priorytet 2 i jest
|
|
\texttt{READY}, scheduler wybierze \blank{2cm}, ponieważ
|
|
\blank{10cm}.
|
|
|
|
\subsection*{Równe priorytety i time slicing}
|
|
|
|
Przy \texttt{configUSE\_PREEMPTION=1} oraz
|
|
\texttt{configUSE\_TIME\_SLICING=1} tick może przenieść wykonanie do innego
|
|
gotowego zadania o tym samym priorytecie. Zalicza relacja:
|
|
|
|
\begin{center}
|
|
\texttt{first == third \&\& first != second}
|
|
\end{center}
|
|
|
|
Wpisz dwa dopuszczalne ślady: \blank{3cm}\quad lub \quad\blank{3cm}.
|
|
|
|
\section{Czas: wartość ma znaczenie dopiero z jednostką}
|
|
|
|
\begin{lstlisting}
|
|
freertos::Ticks duration{3};
|
|
const auto start = freertos::TickPoint::now();
|
|
vTaskDelay(duration.count());
|
|
const auto elapsed = freertos::TickPoint::now() - start;
|
|
\end{lstlisting}
|
|
|
|
\texttt{Ticks} jest czasem trwania. \texttt{TickPoint} jest punktem na
|
|
zawijającym się liczniku. Odejmowanie dwóch punktów daje czas trwania także
|
|
przy przejściu licznika przez maksimum typu bez znaku.
|
|
|
|
\noindent\begin{tabularx}{\textwidth}{@{}p{4.4cm}X@{}}
|
|
\toprule
|
|
API & Znaczenie \\
|
|
\midrule
|
|
\texttt{vTaskDelay(3)} & blokada względna: trzy ticki od chwili wywołania \\
|
|
\texttt{xTaskDelayUntil} (\texttt{\&next,3}) & kolejny termin względem zapamiętanej osi okresu \\
|
|
\bottomrule
|
|
\end{tabularx}
|
|
|
|
W laboratorium tick rate wynosi 1000 Hz, ale poprawne zdanie brzmi
|
|
„A było zablokowane przez \blank{1.5cm} ticki”. Przeliczenie na ms:
|
|
\blank{3cm}. Co zmieni się przy 250 Hz? \blank{5cm}
|
|
|
|
\newpage
|
|
\section{Tabela predykcji i obserwacji}
|
|
|
|
Najpierw wypełnij kolumnę „predykcja”. Dopiero potem uruchom program i wpisz
|
|
wartości z \texttt{g\_snapshots}. Priorytet zapisuj obok stanu, np.
|
|
\texttt{READY/p2}.
|
|
|
|
\renewcommand{\arraystretch}{1.32}
|
|
\noindent\begin{tabularx}{\textwidth}{@{}p{.7cm}p{2.3cm}p{3.2cm}p{3.2cm}p{1.8cm}X@{}}
|
|
\toprule
|
|
Nr & Zdarzenie & A: pred./odczyt & B: pred./odczyt & Current & Dlaczego? \\
|
|
\midrule
|
|
1 & startup & \blank{2.7cm} & \blank{2.7cm} & \blank{1.3cm} & \blank{2.05cm} \\
|
|
2 & przed delay & \blank{2.7cm} & \blank{2.7cm} & \blank{1.3cm} & \blank{2.05cm} \\
|
|
3 & A czeka & \blank{2.7cm} & \blank{2.7cm} & \blank{1.3cm} & \blank{2.05cm} \\
|
|
4 & A obudzone & \blank{2.7cm} & \blank{2.7cm} & \blank{1.3cm} & \blank{2.05cm} \\
|
|
5 & BEFORE & \blank{2.7cm} & \blank{2.7cm} & \blank{1.3cm} & \blank{2.05cm} \\
|
|
6 & HIGH & \blank{2.7cm} & \blank{2.7cm} & \blank{1.3cm} & \blank{2.05cm} \\
|
|
7 & AFTER & \blank{2.7cm} & \blank{2.7cm} & \blank{1.3cm} & \blank{2.05cm} \\
|
|
8 & verifier & \blank{2.7cm} & \blank{2.7cm} & \blank{1.3cm} & \blank{2.05cm} \\
|
|
\bottomrule
|
|
\end{tabularx}
|
|
\renewcommand{\arraystretch}{1}
|
|
|
|
\section*{Trzy znaczniki jako dowód wywłaszczenia}
|
|
|
|
Kod A zapisuje \texttt{BEFORE=1}, podnosi B do priorytetu 3, a po powrocie z
|
|
API zapisuje \texttt{AFTER=3}. Kod B zapisuje \texttt{HIGH=2} natychmiast po
|
|
uzyskaniu CPU.
|
|
|
|
\begin{lstlisting}
|
|
append_priority_order(BEFORE); // A: 1
|
|
peer.set_priority(3); // B staje sie wyzej priorytetowe
|
|
append_priority_order(AFTER); // A: 3, dopiero po powrocie
|
|
|
|
// B, zanim wywolanie w A zdazy wrocic:
|
|
append_priority_order(HIGH); // B: 2
|
|
\end{lstlisting}
|
|
|
|
Gdyby nie doszło do natychmiastowego wywłaszczenia, możliwa kolejność
|
|
wynosiłaby \blank{4cm}. Odczyt oczekiwany: \blank{4cm}.
|
|
|
|
\section*{Osiem rekordów, ale żadnego użycia wiszącego uchwytu}
|
|
|
|
Po usunięciu zadania jego TCB może zostać odzyskany przez idle task.
|
|
\texttt{TaskRef} nie posiada TCB i nie wydłuża jego życia. Dlatego terminalny
|
|
rekord zapisuje znany stan \texttt{DELETED}, ale nie wywołuje
|
|
\texttt{eTaskGetState()} przez stary uchwyt.
|
|
|
|
\newpage
|
|
\section{Uruchomienie i kontrakt dowodu}
|
|
|
|
\begin{lstlisting}[language=bash]
|
|
make check
|
|
riscv64-unknown-elf-gdb build/task01_scheduler_states/prog.elf
|
|
\end{lstlisting}
|
|
|
|
\begin{lstlisting}
|
|
p g_alternating_tasks
|
|
p g_alternating_ticks
|
|
p g_snapshots
|
|
p g_delay_start_tick
|
|
p g_delay_observed_tick
|
|
p g_delay_end_tick
|
|
p g_delay_elapsed
|
|
p g_priority_order
|
|
p g_scheduler_states_pass
|
|
\end{lstlisting}
|
|
|
|
\noindent\begin{tabularx}{\textwidth}{@{}p{5.2cm}X@{}}
|
|
\toprule
|
|
Warunek & Odczyt ucznia \\
|
|
\midrule
|
|
identyfikatory mają postać X,Y,X, $X\ne Y$ & \blank{6cm} \\
|
|
w zdarzeniu 3: A=BLOCKED, B=RUNNING & \blank{6cm} \\
|
|
\texttt{delay\_end - delay\_start == 3} & \blank{6cm} \\
|
|
obserwacja blokady jest przed końcem delay & \blank{6cm} \\
|
|
w zdarzeniu 6 B ma priorytet 3 & \blank{6cm} \\
|
|
\texttt{priority\_order == \{1,2,3\}} & \blank{6cm} \\
|
|
osiem snapshotów i \texttt{pass == 1} & \blank{6cm} \\
|
|
\bottomrule
|
|
\end{tabularx}
|
|
|
|
\section*{Minimalne wrappery C++}
|
|
|
|
\begin{lstlisting}
|
|
class TaskRef final {
|
|
public:
|
|
explicit TaskRef(TaskHandle_t h) : handle_{h} {}
|
|
eTaskState state() const { return eTaskGetState(handle_); }
|
|
UBaseType_t priority() const { return uxTaskPriorityGet(handle_); }
|
|
void set_priority(UBaseType_t p) const {
|
|
vTaskPrioritySet(handle_, p);
|
|
}
|
|
private:
|
|
TaskHandle_t handle_; // non-owning
|
|
};
|
|
\end{lstlisting}
|
|
|
|
Nie ma tu wirtualności, alokacji ani automatycznego delete. Rozmiar
|
|
\texttt{TaskRef} jest równy rozmiarowi uchwytu. Pełna polityka własności taska
|
|
pojawi się dopiero w K07--K09.
|
|
|
|
\section*{Wyjście — cztery krótkie odpowiedzi}
|
|
|
|
\begin{enumerate}
|
|
\item Dlaczego zadanie o priorytecie 4 może nie działać, gdy działa p2?\\[1em]
|
|
\item Dlaczego test nie wymaga, by A było pierwsze w śladzie time slicing?\\[1em]
|
|
\item Kiedy \texttt{vTaskDelay(3)} oznacza dokładnie 3 ms?\\[1em]
|
|
\item Co dokładnie dowodzi kolejność \texttt{1,2,3}?\\[1em]
|
|
\end{enumerate}
|
|
|
|
\section*{Zaliczenie}
|
|
|
|
\begin{itemize}
|
|
\item $\square$ rozróżniam READY, RUNNING, BLOCKED i DELETED;
|
|
\item $\square$ pokazuję X--Y--X, blokadę na 3 ticki i porządek 1--2--3;
|
|
\item $\square$ odróżniam delay względny od okresowego terminu;
|
|
\item $\square$ nie utożsamiam ticka z milisekundą bez konfiguracji;
|
|
\item $\square$ wiem, że \texttt{TaskRef} nie jest właścicielem TCB.
|
|
\end{itemize}
|
|
|
|
\vfill
|
|
\noindent\textbf{Następna karta K05:} most C++ do heapu, porównanie modeli
|
|
FreeRTOS oraz tylko-odczytowy \texttt{HeapStats}.
|
|
|
|
\end{document}
|