Files
2026-07-21 19:14:19 +02:00

215 lines
7.8 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}{10}
\newcommand{\CardCount}{16}
\newcommand{\CardSlug}{queue}
\newcommand{\CardVersion}{v00.01}
\newcommand{\DocumentUUID}{66967c2d-bb34-4344-8064-f54d06cce47a}
\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{K10 · FreeRTOS C++ · typed queue}}\rhead{\small L09 · byte-copy contract}
\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 \texttt{Queue<T>} i \texttt{StaticQueue<T,N>}}\par
\vspace{.25em}{\large typowana granica nad kopiowaniem bajtów FreeRTOS}\par
\end{center}
\noindent\begin{tabularx}{\textwidth}{@{}p{1.65cm}Xp{1.9cm}X@{}}
\toprule
Karta & K10 / \CardCount & Czas & 30 minut \\
Platforma & Hazard3 / RV32I & Wiadomość & \texttt{Sample}, 12 B \\
Capacity & 2 elementy & Timeout & jawny, 0 lub 2 ticki \\
Wersja & \CardVersion & UUID karty & \texttt{66967c2d-...} \\
\bottomrule
\end{tabularx}
\section*{Kontrakt typu przed uruchomieniem}
\begin{lstlisting}
static_assert(std::is_trivially_copyable<T>::value,
"Queue<T> requires T to be trivially copyable");
\end{lstlisting}
Kernel zapamiętuje \texttt{sizeof(T)} bajtów. Nie wywołuje konstruktora,
destruktora ani operacji kopiowania C++. Dlatego owning \texttt{VectorV1} nie
może być wiadomością by value.
\noindent\fcolorbox{accent}{accentlight}{\begin{minipage}{.94\textwidth}
\textbf{Kontrakt K10.} \texttt{send} kopiuje bajty w chwili wywołania. Późniejsza
zmiana źródła nie może zmienić elementu w kolejce. Timeout jest jawny; wrapper
nie ukrywa \texttt{portMAX\_DELAY}.
\end{minipage}}
\section*{Plan 30 minut}
\noindent\begin{tabularx}{\textwidth}{@{}p{1.35cm}p{3.1cm}X@{}}
\toprule
Czas & Tryb & Dowód \\
\midrule
0--5 & gate & trivial Sample przechodzi; VectorV1 nie \\
5--10 & create & dynamic heap cost kontra static delta 0 \\
10--15 & copy & send, mutate, receive oryginalnej wartości \\
15--20 & bytes & snapshot 12 B caller storage \\
20--25 & full & trzeci send odmawia po 2 tickach \\
25--30 & FIFO & drain 0x2222, 0x3333; empty receive=false \\
\bottomrule
\end{tabularx}
\section*{Predykcja}
\texttt{sizeof(Sample)} = \blank{2cm} B. Po wysłaniu wartości \texttt{0x1111}
i zmianie źródła na \texttt{0xDEAD} odbiorę: \blank{3cm}.
\newpage
\section{Dynamiczna i statyczna własność}
\noindent\begin{tabularx}{\textwidth}{@{}p{4.1cm}p{4.5cm}X@{}}
\toprule
Właściwość & \texttt{Queue<Sample>} & \texttt{StaticQueue<Sample,2>} \\
\midrule
create API & \texttt{xQueueCreate} & \texttt{xQueueCreateStatic} \\
control & heap & caller \texttt{StaticQueue\_t} \\
item bytes & heap & caller \texttt{uint8\_t[24]} \\
item size & \texttt{sizeof(Sample)} & \texttt{sizeof(Sample)} \\
destructor & delete + heap free & delete, bez free caller bytes \\
\bottomrule
\end{tabularx}
\section*{Pomiar heap i adresów}
\noindent\begin{tabularx}{\textwidth}{@{}p{5.5cm}p{3.5cm}X@{}}
\toprule
Pomiar & Predykcja & Odczyt \\
\midrule
dynamic cost & $>0$ & \blank{3cm} B \\
static create delta & 0 & \blank{3cm} B \\
heap po obu destruktorach & baseline & \blank{3cm} \\
static handle & control address & \blank{3cm} \\
control/storage domain & .bss, poza heap & \blank{3cm} \\
\bottomrule
\end{tabularx}
\section{Kopia jest snapshotem}
\begin{lstlisting}
Sample source{1, 0x1111, 3, 0x55};
dynamic.send(source, 0);
source.value = 0xDEAD;
dynamic.receive(received, 0);
\end{lstlisting}
\noindent\begin{tabularx}{\textwidth}{@{}p{4.5cm}p{3.5cm}X@{}}
\toprule
Wartość & Źródło po mutate & Odebrana kopia \\
\midrule
\texttt{value} & \texttt{0xDEAD} & \blank{3cm} \\
\texttt{flags} & \texttt{0xAA} & \blank{3cm} \\
\bottomrule
\end{tabularx}
Co byłoby błędem przy \texttt{xQueueCreate(2,sizeof(Sample*))}, gdy send dostaje
\texttt{\&sample} zamiast \texttt{\&samplePointer}?\\[.5em]\blank{16cm}
\newpage
\section{Full, timeout, FIFO i empty}
\begin{center}
\texttt{send(first,0)} $\rightarrow$ count 1\\
\texttt{send(second,0)} $\rightarrow$ count 2 / FULL\\
\texttt{send(third,2)} $\rightarrow$ task blokuje maks. 2 ticki / false\\
\texttt{receive} $\rightarrow$ first, potem second\\
\texttt{receive(empty,0)} $\rightarrow$ false
\end{center}
\noindent\begin{tabularx}{\textwidth}{@{}p{4.8cm}p{3.6cm}X@{}}
\toprule
Dowód & Predykcja & Odczyt \\
\midrule
count przed trzecim send & 2 & \blank{2.5cm} \\
third send result & false & \blank{2.5cm} \\
tick delta & $\geq2$ & \blank{2.5cm} \\
FIFO first value & \texttt{0x2222} & \blank{2.5cm} \\
FIFO second value & \texttt{0x3333} & \blank{2.5cm} \\
empty receive, timeout 0 & false & \blank{2.5cm} \\
\bottomrule
\end{tabularx}
\section{Zajrzyj do caller storage}
Po pierwszym static send porównaj pierwsze 12 bajtów
\texttt{g\_static\_queue\_storage.bytes} z reprezentacją \texttt{first}.
\noindent\begin{tabularx}{\textwidth}{@{}p{3cm}p{4cm}X@{}}
\toprule
Pole & Wartość & Little-endian bytes \\
\midrule
sequence & 2 & \blank{5cm} \\
value & \texttt{0x2222} & \blank{5cm} \\
channel/flags & 4 / \texttt{0x10} & \blank{5cm} \\
\bottomrule
\end{tabularx}
\section*{Ćwiczenie typu}
Zaprojektuj trivial UART message: kierunek, długość, maks. 8 bajtów payload i
sequence. Zapisz definicję oraz policz \texttt{sizeof}:\\[.5em]
\blank{16cm}\\[1em]\blank{16cm}
Dlaczego sam fakt, że wskaźnik jest trivially copyable, nie rozwiązuje lifetime
wskazywanego obiektu?\\[.5em]\blank{16cm}
\newpage
\section{Hazard3/GDB i zaliczenie}
\begin{lstlisting}[language=bash]
make check
riscv64-unknown-elf-gdb build/task01_queue/prog.elf
b queue_debug_checkpoint
\end{lstlisting}
\begin{lstlisting}
p g_dynamic_queue_cost
p g_static_control_address
p g_static_bytes_address
p g_static_first_item_bytes
p g_copy_source_after_mutation
p g_copy_received_value
p g_full_count
p g_timeout_ticks
p g_fifo_values
p g_queue_pass
\end{lstlisting}
\section*{Negatywny test jest częścią kontraktu}
\begin{lstlisting}
struct VectorV1 {
unsigned* data;
~VectorV1() { data = nullptr; }
};
freertos::Queue<VectorV1> forbidden{2}; // must not compile
\end{lstlisting}
Oczekiwana przyczyna, nie przypadkowy błąd linkera:
\texttt{Queue<T> requires T to be trivially copyable}.
\section*{Zaliczenie}
\begin{itemize}
\item $\square$ wyjaśniam byte copy i gate trivially-copyable;
\item $\square$ pokazuję 128 B dynamic cost i 0 B static delta;
\item $\square$ dowodzę snapshot 0x1111 po mutate do 0xDEAD;
\item $\square$ wiążę 12 B item size z typed API i storage;
\item $\square$ pokazuję full, timeout 2, FIFO i empty=false;
\item $\square$ negatywny test VectorV1 kończy się właściwym static assert.
\end{itemize}
\section*{Wyjście}
Kiedy przesyłać wartość, a kiedy wskaźnik? Jak udokumentować ownership?\\[.5em]
\blank{16cm}\\[1em]\blank{16cm}
\vfill
\noindent\textbf{Następna karta K11:} \texttt{Mutex}, własny
\texttt{LockGuard} i obserwowalne dziedziczenie priorytetu.
\end{document}