\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} i \texttt{StaticQueue}}\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::value, "Queue 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} & \texttt{StaticQueue} \\ \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 forbidden{2}; // must not compile \end{lstlisting} Oczekiwana przyczyna, nie przypadkowy błąd linkera: \texttt{Queue 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}