Files
lab-rv32i-freertos-kernel-f…/doc/main.tex
T

238 lines
8.7 KiB
TeX

\documentclass[10pt]{article}
\usepackage[T1]{fontenc}\usepackage[utf8]{inputenc}\usepackage[polish]{babel}
\usepackage[a4paper,margin=1.55cm]{geometry}
\usepackage{array,tabularx,booktabs,amsmath,amssymb,xcolor,listings,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}{09}
\newcommand{\CardCount}{16}
\newcommand{\CardSlug}{kernel-facade}
\newcommand{\CardVersion}{v00.01}
\newcommand{\DocumentUUID}{6a2ab068-17e7-4bfa-b726-2df37787ed69}
\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{K09 · FreeRTOS C++ · kernel facade}}\rhead{\small L08 · paired kernel state}
\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 facade i scoped guards}\par
\vspace{.25em}{\large statyczna usługa; RAII tylko dla prawdziwych par}\par
\end{center}
\noindent\begin{tabularx}{\textwidth}{@{}p{1.65cm}Xp{1.55cm}X@{}}
\toprule
Karta & K09 / \CardCount & Czas & 30 minut \\
Platforma & Hazard3 / RV32I & Język & freestanding C++17 \\
Dowód & nesting + \texttt{mstatus.MIE} & API & task context \\
Wersja & \CardVersion & UUID karty & \texttt{6a2ab068-...} \\
\bottomrule
\end{tabularx}
\section*{Najpierw klasyfikacja lifetime}
\begin{center}
\texttt{Scheduler::start/state} $\rightarrow$ usługa procesu, brak scoped lifetime\\[.35em]
\texttt{enter/exit}, \texttt{suspend/resume} $\rightarrow$ pary, więc guard RAII
\end{center}
\noindent\fcolorbox{accent}{accentlight}{\begin{minipage}{.94\textwidth}
\textbf{Kontrakt K09.} Destruktor guarda ma odtworzyć stan również przy każdym
\texttt{return}. Nie wolno jednak blokować przy zawieszonym schedulerze, a
\texttt{CriticalSection} nie jest mutexem ani API dla ISR.
\end{minipage}}
\section*{Plan 30 minut}
\noindent\begin{tabularx}{\textwidth}{@{}p{1.35cm}p{3.15cm}X@{}}
\toprule
Czas & Tryb & Dowód \\
\midrule
0--5 & raw API & rozdziel usługi od par \\
5--10 & critical & nesting oraz MIE przed/wewnątrz/po \\
10--15 & guard & trzy wczesne wyjścia wracają do stanu bazowego \\
15--20 & suspend & scheduler suspended, lecz MIE pozostaje 1 \\
20--25 & nesting & inner exit nie wznawia jeszcze outer suspension \\
25--30 & ABI & inline do raw API; brak vtable/runtime \\
\bottomrule
\end{tabularx}
\section*{Dwie różne blokady}
\noindent\begin{tabularx}{\textwidth}{@{}p{4.1cm}p{3.3cm}p{3.2cm}X@{}}
\toprule
Operacja & Context switch & Przerwania & Para \\
\midrule
\texttt{vTaskSuspendAll} & odroczony & działają & \texttt{xTaskResumeAll} \\
\texttt{taskENTER\_CRITICAL} & niemożliwy & MIE=0 & \texttt{taskEXIT\_CRITICAL} \\
\bottomrule
\end{tabularx}
Predykcja MIE podczas suspension: \blank{2cm}. Predykcja critical depth po
dwóch enter i jednym exit: \blank{2cm}.
\newpage
\section{Raw critical: zmierz dokładną sekwencję}
\begin{lstlisting}
taskENTER_CRITICAL(); // depth + 1, MIE=0
taskENTER_CRITICAL(); // depth + 1, MIE=0
taskEXIT_CRITICAL(); // depth - 1, nadal MIE=0
taskEXIT_CRITICAL(); // depth == 0, MIE=1
\end{lstlisting}
\noindent\begin{tabularx}{\textwidth}{@{}p{2.0cm}p{3.0cm}p{2.5cm}X@{}}
\toprule
Checkpoint & Operacja & Predykcja depth/MIE & Odczyt depth/MIE \\
\midrule
C0 & przed & 0 / 1 & \blank{2.5cm} \\
C1 & enter & 1 / 0 & \blank{2.5cm} \\
C2 & drugi enter & 2 / 0 & \blank{2.5cm} \\
C3 & pierwszy exit & 1 / 0 & \blank{2.5cm} \\
C4 & drugi exit & 0 / 1 & \blank{2.5cm} \\
\bottomrule
\end{tabularx}
\section{RAII zamienia trzy krawędzie w jedną parę}
\begin{lstlisting}
uint32_t repair(uint32_t path) {
freertos::CriticalSection guard;
if (path == 0) return 0x10;
if (path == 1) return 0x20;
return 0x30;
} // destructor runs on every return
\end{lstlisting}
\noindent\begin{tabularx}{\textwidth}{@{}p{1.5cm}p{2.6cm}p{2.7cm}p{2.5cm}X@{}}
\toprule
Path & Wynik & inside depth/MIE & after depth/MIE & PASS \\
\midrule
0 & \texttt{0x10} & \blank{2cm} & \blank{2cm} & $\square$ \\
1 & \texttt{0x20} & \blank{2cm} & \blank{2cm} & $\square$ \\
2 & \texttt{0x30} & \blank{2cm} & \blank{2cm} & $\square$ \\
\bottomrule
\end{tabularx}
\section*{Co dokładnie gwarantuje guard?}
\begin{itemize}
\item paruje wywołania w normalnym przepływie i przy wcześniejszym return;
\item nie jest kopiowalny ani przenoszalny, więc nie powiela exit;
\item zachowuje zagnieżdżenie: inner exit nie kończy outer critical section.
\end{itemize}
Czy RAII pozwala wywołać blokujące API wewnątrz critical section?
\blank{2cm}. Uzasadnienie:\\[.5em]\blank{16cm}
\newpage
\section{SchedulerSuspendGuard: context switch bez maskowania IRQ}
\begin{lstlisting}
{
freertos::SchedulerSuspendGuard guard;
// scheduler state == suspended; mstatus.MIE == 1
// no delay, queue wait, semaphore wait or other blocking API
} // xTaskResumeAll exactly once
\end{lstlisting}
\noindent\begin{tabularx}{\textwidth}{@{}p{2cm}p{3.3cm}p{3.1cm}X@{}}
\toprule
Path & Inside state/MIE & After state/MIE & Wynik \\
\midrule
0 & suspended / \blank{1cm} & running / \blank{1cm} & \texttt{0x40} \\
1 & suspended / \blank{1cm} & running / \blank{1cm} & \texttt{0x50} \\
2 & suspended / \blank{1cm} & running / \blank{1cm} & \texttt{0x60} \\
\bottomrule
\end{tabularx}
\section*{Zagnieżdżenie}
\begin{center}
\texttt{running}\\
$\downarrow$ outer ctor: \texttt{suspended}\\
$\downarrow$ inner ctor: \texttt{suspended}\\
$\downarrow$ inner dtor: \texttt{suspended}\\
$\downarrow$ outer dtor: \texttt{running}
\end{center}
Dlaczego inner destructor nie może jeszcze zwrócić stanu running?\\[.5em]
\blank{16cm}
\section{Statyczna fasada i bieżący task}
\begin{lstlisting}
freertos::Scheduler::start();
auto state = freertos::Scheduler::state();
auto handle = freertos::this_task::current();
auto tick = freertos::this_task::tick_count();
freertos::this_task::yield();
\end{lstlisting}
\noindent\begin{tabularx}{\textwidth}{@{}p{5cm}p{4cm}X@{}}
\toprule
Relacja & Predykcja & Odczyt \\
\midrule
state przed start & not started & \blank{2.5cm} \\
state w workerze & running & \blank{2.5cm} \\
this task handle & worker handle & \blank{2.5cm} \\
tick after yield & $\geq$ tick before & \blank{2.5cm} \\
\bottomrule
\end{tabularx}
\section*{Granice}
Suspension nie wyłącza ISR; tylko odracza przełączenie taska. Critical section
maskuje przerwania i musi być krótka. Żaden z guardów nie jest zamiennikiem
mutexa chroniącego zasób przez długą operację.
\newpage
\section{Hazard3/GDB i ABI}
\begin{lstlisting}[language=bash]
make check
riscv64-unknown-elf-gdb build/task01_kernel_facade/prog.elf
b kernel_facade_debug_checkpoint
\end{lstlisting}
\begin{lstlisting}
p g_raw_critical_depth
p g_raw_critical_mie
p g_guard_critical_after_depth
p g_guard_critical_after_mie
p g_raw_scheduler_state
p g_guard_scheduler_after_state
p g_nested_scheduler_state
p g_this_task_handle
p g_worker_handle
p g_kernel_facade_pass
\end{lstlisting}
\section*{Co ma zostać w assembly?}
\noindent\begin{tabularx}{\textwidth}{@{}p{5.3cm}p{3.3cm}X@{}}
\toprule
Dowód & Oczekiwane & Odczyt \\
\midrule
disable IRQ & \texttt{csrci mstatus,8} & \blank{2.5cm} \\
enable IRQ & \texttt{csrsi mstatus,8} & \blank{2.5cm} \\
symbole wrappera & brak & \blank{2.5cm} \\
vtable/RTTI/exception runtime & brak & \blank{2.5cm} \\
\bottomrule
\end{tabularx}
\section*{Zaliczenie}
\begin{itemize}
\item $\square$ rozdzielam statyczną fasadę od scoped ownera;
\item $\square$ odtwarzam critical depth 0--1--2--1--0 i MIE 1--0--0--0--1;
\item $\square$ pokazuję restore po trzech wczesnych return;
\item $\square$ pokazuję, że suspension zachowuje MIE=1;
\item $\square$ wyjaśniam nesting outer/inner i zakaz blokowania;
\item $\square$ dowodzę inline facade/guards oraz końcowy PASS.
\end{itemize}
\section*{Wyjście}
Kiedy wybrać \texttt{CriticalSection}, a kiedy \texttt{SchedulerSuspendGuard}?\\[.5em]
\blank{16cm}\\[1em]
Dlaczego \texttt{Scheduler} nie jest obiektem RAII?\\[.5em]
\blank{16cm}
\vfill
\noindent\textbf{Następna karta K10:} typed \texttt{Queue<T>} i
\texttt{StaticQueue<T,N>} z jawnym kontraktem copyable message type.
\end{document}