\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}