{ "$schema": "../../../tools/card-layouts/schemas/card-source.schema.json", "schema": "esc-card-source.v1", "card": { "id": "mpabi-freertos-c-05-queue", "series": "freertos-c", "series_title": "FreeRTOS C", "number": "05", "count": "15", "slug": "queue", "title": "Kolejki: blokowanie, FIFO i kopiowanie wartości", "topic": "xQueueSend, xQueueReceive, wait lists i ownership danych", "project": "Freestanding C nad FreeRTOS", "subject": "Informatyka", "level": "Rok 2 · L05 · RV32I/Hazard3", "revision_date": "2026-07-19T00:00:00+02:00", "status": "Gotowa", "version": "v00.01", "uuid": "6ddb3c92-5612-5809-84cf-715d21c18bc6", "author": "M. Pabiszczak", "year": "2026" }, "generated": { "tex": "doc/generated/main.tex", "html": "web/index.html", "html_css": "web/style.css", "html_tree_inspector": false, "react_app": true }, "render_dictionary": false, "viewpoints": [ { "id": "A1", "label": "CONTEXT", "subtitle": "Granice systemu", "status": "unavailable", "reason": "Granica aplikacja–kernel–Hazard3 pozostaje taka jak w FC03." }, { "id": "A2", "label": "STRUCTURE", "subtitle": "Message, Queue<1> i trzy taski", "status": "enabled", "target_label": "fig:a2-structure" }, { "id": "A3", "label": "DISPATCH", "subtitle": "Callback ABI", "status": "unavailable", "reason": "Kolejka nie wprowadza nowego callbacku C." }, { "id": "A4", "label": "APPLICATION", "subtitle": "Konkretny eksperyment", "status": "unavailable", "reason": "Topologia eksperymentu jest kompletna w A2 i A5." }, { "id": "A5", "label": "FLOW", "subtitle": "E01–E10 i dwa wait lists", "status": "enabled", "target_label": "fig:a5-flow" }, { "id": "A6", "label": "STATE", "subtitle": "EMPTY, FULL i handoff", "status": "enabled", "target_label": "fig:a6-state" }, { "id": "A7", "label": "RUNTIME", "subtitle": "Queue object, TCB, stos i storage", "status": "enabled", "target_label": "fig:a7-runtime" }, { "id": "A8", "label": "PATTERNS", "subtitle": "Value message kontra pointer ownership", "status": "enabled", "target_label": "fig:a8-patterns" } ], "debug_strategies": { "code.queue-contract": { "id": "code.queue-contract", "kind": "code", "action": "open", "expected_observations": [ "item size jest stały", "storage kolejki nie jest buforem źródłowym" ], "assertions": [ "length=1", "payload ma checksum" ], "evidence_fields": [ "code_ref", "typ", "rozmiar" ], "prerequisites": [ "źródło FC05" ], "layout": [ "QueueMessage", "QueueExperiment", "FreeRTOSConfig" ], "commands": [ "rg -n 'QueueMessage|FC05_QUEUE_LENGTH|xQueueCreate' include src" ] }, "run.queue-state": { "id": "run.queue-state", "kind": "run", "action": "replay", "expected_observations": [ "receiver czeka na empty", "sender czeka na full" ], "assertions": [ "publiczny eTaskState=eBlocked", "uxMessagesWaiting=1" ], "evidence_fields": [ "event", "task state", "queue occupancy", "PC", "SP", "timestamp" ], "prerequisites": [ "Hazard3 online", "czysta RAM" ], "layout": [ "source", "queue object", "sender/receiver TCB", "event log" ], "commands": [ "print g_fc05", "print g_fc05_events", "print g_fc05_event_count" ] }, "run.byte-copy": { "id": "run.byte-copy", "kind": "run", "action": "replay", "expected_observations": [ "source=0xDEAD", "received M2=0x2222" ], "assertions": [ "checksum M2 poprawny", "adresy storage są różne" ], "evidence_fields": [ "source payload", "received payload", "checksum" ], "prerequisites": [ "M2 znajduje się w queue storage" ], "layout": [ "mutated source", "queue storage", "received M2" ], "commands": [ "print g_fc05.mutated_source", "print g_fc05.received[1]" ] }, "run.pass": { "id": "run.pass", "kind": "run", "action": "replay", "expected_observations": [ "1/2/3", "PASS=1", "10 committed records" ], "assertions": [ "digest jest stabilny w trzech procesach", "verifier ma najniższy priorytet" ], "evidence_fields": [ "PASS", "digest", "source blob", "ELF hash", "timestamp" ], "prerequisites": [ "sender i receiver zakończone" ], "layout": [ "FIFO", "bounded evidence", "digest" ], "commands": [ "print g_fc05_pass", "print g_fc05.evidence_digest" ] } }, "template": "templates/karta-klasyczna.json", "title_block": { "category": "KARTA PRACY · INFORMATYKA", "prepared_by": "M. Pabiszczak", "prepared_on": "2026-07-19T00:00:00+02:00", "title": "Kolejki: blokowanie, FIFO i kopiowanie wartości", "url": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/8ee8f36a-471b-51bc-97b8-e204bd541c61", "repository_url": "https://zsl-gitea.mpabi.pl/edu-freertos-c/lab-rv32i-freertos-c-queue", "url_host_uuid": "dce7fb9d-7b2f-5d49-96a2-3a30d3070b84", "url_domain": "mpabi.pl", "doc_uuid": "8ee8f36a-471b-51bc-97b8-e204bd541c61", "revision": "v00.01", "issued_on": "2026-07-19T00:00:00+02:00", "series": "FREERTOS-C-05", "document_type": "karta pracy", "tool": "card-layouts", "show_qr": true, "show_repository_qr": true, "height_cm": 2.6, "repeat_on_every_page": true, "replace_front_matter": true }, "front_page_scope": { "title": "Cel karty", "content_tex": "Uczeń wyjaśnia, kiedy kolejka blokuje sendera lub receivera, oraz dowodzi, że FreeRTOS kopiuje stałą liczbę bajtów do własnego storage.", "scope_title": "Zakres karty", "scope_content_tex": "Kolejka długości 1 przenosi M1, M2 i M3. Receiver blokuje się na pustej kolejce, sender na pełnej. Po wysłaniu M2 źródło zmienia się na 0xDEAD, lecz receiver odbiera niezmienione 0x2222. Verifier sprawdza FIFO, publiczny stan eBlocked, osobne stosy i digest dziesięciu zdarzeń.", "scope_table": { "headers": [ "Lekcja", "Task", "Najważniejsza idea", "Priorytet", "Status", "Version" ], "rows": [ { "chapter": "FC05", "task": "Task01", "idea_tex": "xQueueSend, xQueueReceive, wait lists i ownership danych", "priority": "główny", "status": "ready", "version": "v00.01", "key": true } ] } }, "side_margin_tree_layout": { "columns": [ { "id": "zawodowe", "label": "TECH", "side": "left", "tree": "WE -> EK -> KW", "description": "Dowody runtime." }, { "id": "ogolne", "label": "OG", "side": "right", "tree": "WE -> EN -> KW", "description": "Model FreeRTOS C." } ] }, "learning_effects": { "FC05.EN01": { "bloom_level": "Analiza", "label": "Model kolejki", "text": "Uczeń wiąże EMPTY/FULL z wait lists oraz rozróżnia storage kolejki od pamięci producenta.", "assessment_criteria": [ "FC05.KW01" ] }, "FC05.EK01": { "bloom_level": "Zastosowanie", "label": "Replay FIFO i copy", "text": "Uczeń odtwarza E01–E10 i pokazuje publiczny stan, occupancy, payload, PC/SP i digest.", "assessment_criteria": [ "FC05.KW01" ] } }, "assessment_criteria": { "FC05.KW01": { "text": "Program kończy się PASS; sender jest eBlocked na FULL; odbiór ma kolejność 1/2/3; M2 pozostaje 0x2222 po mutacji źródła; ślad i hashe są stabilne.", "learning_effects": [ "FC05.EN01", "FC05.EK01" ] } }, "educational_requirements": { "FC05.WE01": { "text": "Zaprojektowanie i zbadanie deterministycznej komunikacji przez kolejkę FreeRTOS.", "label": "xQueueSend, xQueueReceive, wait lists i ownership danych", "learning_effects": [ "FC05.EN01", "FC05.EK01" ], "learning_tree": { "schema": "we-learning-tree.v1", "policy": "Każda aktywna kotwica wskazuje kod lub checkpoint.", "ogolne": [ { "effect_ref": "FC05.EN01", "display": "EN LOCAL RTOS.05", "source": "LOCAL", "official": "RTOS", "local": "05", "kind": "EN", "tree_id": "FC05.WE01.OG.LOCAL.RTOS.05", "text": "Uczeń wiąże EMPTY/FULL z wait lists oraz rozróżnia storage kolejki od pamięci producenta.", "kw": [ { "criterion_ref": "FC05.KW01", "display": "KW LOCAL RTOS.05", "source": "LOCAL", "kind": "KW", "official": "RTOS", "local": "05", "text": "Łączy kod, diagram i zweryfikowany dowód." } ] } ], "zawodowe": [ { "effect_ref": "FC05.EK01", "display": "EK LOCAL RTOS.05", "source": "LOCAL", "official": "RTOS", "local": "05", "kind": "EK", "tree_id": "FC05.WE01.TECH.LOCAL.RTOS.05", "text": "Uczeń odtwarza E01–E10 i pokazuje publiczny stan, occupancy, payload, PC/SP i digest.", "kw": [ { "criterion_ref": "FC05.KW01", "display": "KW LOCAL RTOS.05", "source": "LOCAL", "kind": "KW", "official": "RTOS", "local": "05", "text": "Łączy kod, diagram i zweryfikowany dowód." } ] } ] } } }, "debug_checkpoints": { "schema": "stem-debug-checkpoints.v1", "semantics": "deterministic-replay", "artifact": { "source": "src/tasks/task01_queue.c", "source_git_blob": "4babdd55987939f3ea1e2a88d62a28b887392761", "elf": "build/task01_queue/prog.elf", "hazard3_elf_sha256": "5e572e007b5fab036a61cfdaaf3ef2c4581fbebd7cfd79815264b7abf98cda12", "hazard3_image": "build/task01_queue/prog.bin", "hazard3_image_sha256": "6b9ac458173df6ec030f88319fdf4f6a44f6ca5d4314539f69f417916033610f" }, "targets": { "hazard3-sim": { "adapter": "hazard3-reset-load-replay.v1", "baseline": "restart-backend", "clean_ram": true } }, "items": { "task01.config": { "event_id": "E01", "stop": { "symbol": "fc05_checkpoint_committed", "offset": 0, "condition": "$a0 == 1" }, "verify": { "expressions": [ { "expr": "g_fc05_event_count", "equals": 1 }, { "expr": "g_fc05.queue == 0", "equals": 1 } ] } }, "task01.receiver-empty": { "event_id": "E02", "stop": { "symbol": "fc05_checkpoint_committed", "offset": 0, "condition": "$a0 == 2" }, "verify": { "expressions": [ { "expr": "uxQueueMessagesWaiting(g_fc05.queue)", "equals": 0 }, { "expr": "g_fc05.receiver_sp != 0", "equals": 1 } ] } }, "task01.send-m1": { "event_id": "E03", "stop": { "symbol": "fc05_checkpoint_committed", "offset": 0, "condition": "$a0 == 3" }, "verify": { "expressions": [ { "expr": "g_fc05_event_count", "equals": 3 }, { "expr": "g_fc05.sender_sp != 0", "equals": 1 } ] } }, "task01.receive-m1": { "event_id": "E04", "stop": { "symbol": "fc05_checkpoint_committed", "offset": 0, "condition": "$a0 == 4" }, "verify": { "expressions": [ { "expr": "g_fc05.received[0].sequence", "equals": 1 }, { "expr": "g_fc05.received[0].payload", "equals": 4369 } ] } }, "task01.mutated-source": { "event_id": "E05", "stop": { "symbol": "fc05_checkpoint_committed", "offset": 0, "condition": "$a0 == 5" }, "verify": { "expressions": [ { "expr": "g_fc05.mutated_source.payload", "equals": 57005 }, { "expr": "uxQueueMessagesWaiting(g_fc05.queue)", "equals": 1 } ] } }, "task01.sender-blocked": { "event_id": "E06", "stop": { "symbol": "fc05_checkpoint_committed", "offset": 0, "condition": "$a0 == 6" }, "verify": { "expressions": [ { "expr": "g_fc05.sender_state_when_full", "equals": 2 }, { "expr": "g_fc05.waiting_when_full", "equals": 1 } ] } }, "task01.receive-m2": { "event_id": "E07", "stop": { "symbol": "fc05_checkpoint_committed", "offset": 0, "condition": "$a0 == 7" }, "verify": { "expressions": [ { "expr": "g_fc05.received[1].sequence", "equals": 2 }, { "expr": "g_fc05.received[1].payload", "equals": 8738 } ] } }, "task01.receive-m3": { "event_id": "E08", "stop": { "symbol": "fc05_checkpoint_committed", "offset": 0, "condition": "$a0 == 8" }, "verify": { "expressions": [ { "expr": "g_fc05.received[2].sequence", "equals": 3 }, { "expr": "g_fc05.received[2].payload", "equals": 13107 } ] } }, "task01.sender-finished": { "event_id": "E09", "stop": { "symbol": "fc05_checkpoint_committed", "offset": 0, "condition": "$a0 == 9" }, "verify": { "expressions": [ { "expr": "g_fc05.received[2].sequence", "equals": 3 }, { "expr": "g_fc05_event_count", "equals": 9 } ] } }, "task01.pass": { "event_id": "E10", "stop": { "symbol": "fc05_checkpoint_committed", "offset": 0, "condition": "$a0 == 10" }, "verify": { "expressions": [ { "expr": "g_fc05_pass", "equals": 1 }, { "expr": "g_fc05.receiver_done", "equals": 1 }, { "expr": "g_fc05.sender_done", "equals": 1 } ] } } } }, "sections": [ { "title": "A2 — Structure", "order": 20, "content_kind": "prose", "asset_page_mode": "one-per-page", "page_orientation": "landscape", "content_tex": "Kolejka zna rozmiar elementu i przechowuje własne bajty. Konteksty aplikacji przechowują wyłącznie uchwyty i dowody.", "assets": [ { "path": "assets/a2-structure.png", "html_path": "assets/a2-structure.svg", "source_path": "assets/a2-structure.puml", "caption": "A2 STRUCTURE — message, queue i trzy taski.", "label": "fig:a2-structure", "alt": "Struktura eksperymentu kolejki.", "kind": "diagram", "width": 1.0, "page_grid": { "columns": 1, "rows": 1, "page_width": 940, "page_height": 560, "overview": true, "step_tiles": { "message": 1, "queue": 1, "receiver": 1, "sender": 1, "verifier": 1, "evidence": 1 } }, "interactive": { "kind": "uml-class", "storage_key": "fc05-a2-structure", "title": "A2 · struktura kolejki", "task": { "id": "task01", "label": "Task01 · queue i FIFO" }, "block": { "id": "a2", "label": "A2 STRUCTURE", "description": "QueueMessage, Queue<1>, trzy taski i bounded evidence." }, "phases": [ { "id": "structure", "label": "MESSAGE / QUEUE / TASKS", "steps": [ { "id": "message", "number": 1, "label": "fixed-size value message", "mode": "CODE", "strategy_ref": "code.queue-contract", "svg_label": "01", "code_ref": "include/task01_queue_model.h:7", "description": "Trzy pola tworzą payload kopiowany bajtowo.", "evidence": "sizeof i checksum." }, { "id": "queue", "number": 2, "label": "queue owns one item slot", "mode": "CODE", "strategy_ref": "code.queue-contract", "svg_label": "02", "code_ref": "src/tasks/task01_queue.c:267", "description": "Length=1 ujawnia oba rodzaje blokowania.", "evidence": "xQueueCreate(1,sizeof message)." }, { "id": "receiver", "number": 3, "label": "higher receiver waits on empty", "mode": "RUN", "event_id": "E02", "strategy_ref": "run.queue-state", "svg_label": "03", "code_ref": "src/tasks/task01_queue.c:91", "snapshot_ref": "task01.receiver-empty", "description": "Receiver nie wykonuje polling.", "evidence": "queue empty, receiver blocks." }, { "id": "sender", "number": 4, "label": "sender waits on full", "mode": "RUN", "event_id": "E06", "strategy_ref": "run.queue-state", "svg_label": "04", "code_ref": "src/tasks/task01_queue.c:173", "snapshot_ref": "task01.sender-blocked", "description": "M3 czeka na zwolnienie slotu.", "evidence": "sender eBlocked." }, { "id": "verifier", "number": 5, "label": "low verifier checks invariants", "mode": "RUN", "event_id": "E10", "strategy_ref": "run.pass", "svg_label": "05", "code_ref": "src/tasks/task01_queue.c:220", "snapshot_ref": "task01.pass", "description": "PASS powstaje po obu taskach roboczych.", "evidence": "FIFO, copy, states, digest." }, { "id": "evidence", "number": 6, "label": "records commit marker last", "mode": "CODE", "strategy_ref": "code.queue-contract", "svg_label": "06", "code_ref": "src/tasks/task01_queue.c:55", "description": "Niepełny rekord nie wygląda jak dowód.", "evidence": "committed zapisany po payload." } ] } ] } } ] }, { "title": "A5 — Flow", "order": 40, "content_kind": "prose", "asset_page_mode": "one-per-page", "page_orientation": "landscape", "content_tex": "Sekwencja eksponuje moment blokowania, preemption po handoff i moment kopiowania wartości.", "assets": [ { "path": "assets/a5-flow.png", "html_path": "assets/a5-flow.svg", "source_path": "assets/a5-flow.puml", "caption": "A5 FLOW — trzy komunikaty przez kolejkę długości 1.", "label": "fig:a5-flow", "alt": "Sekwencja receiver, queue, sender i verifier.", "kind": "diagram", "width": 1.0, "page_grid": { "columns": 1, "rows": 1, "page_width": 940, "page_height": 560, "overview": true, "step_tiles": { "config": 1, "empty": 1, "send1": 1, "recv1": 1, "mutate": 1, "full": 1, "recv2": 1, "recv3": 1, "sender-done": 1, "pass": 1 } }, "interactive": { "kind": "uml-sequence", "storage_key": "fc05-a5-flow", "title": "A5 · empty/full/FIFO", "task": { "id": "task01", "label": "Task01 · queue i FIFO" }, "block": { "id": "a5", "label": "A5 FLOW", "description": "Jeden deterministyczny przebieg E01–E10." }, "phases": [ { "id": "replay", "label": "EMPTY / FULL / COPY / PASS", "steps": [ { "id": "config", "number": 1, "label": "configuration committed", "mode": "RUN", "event_id": "E01", "strategy_ref": "run.queue-state", "svg_label": "01", "code_ref": "src/tasks/task01_queue.c:265", "snapshot_ref": "task01.config", "description": "RAM i evidence zaczynają od zera.", "evidence": "count=1 przed create." }, { "id": "empty", "number": 2, "label": "receiver reaches empty receive", "mode": "RUN", "event_id": "E02", "strategy_ref": "run.queue-state", "svg_label": "02", "code_ref": "src/tasks/task01_queue.c:89", "snapshot_ref": "task01.receiver-empty", "description": "Kolejne API przeniesie task do Blocked.", "evidence": "occupancy=0." }, { "id": "send1", "number": 3, "label": "sender publishes M1", "mode": "RUN", "event_id": "E03", "strategy_ref": "run.queue-state", "svg_label": "03", "code_ref": "src/tasks/task01_queue.c:153", "snapshot_ref": "task01.send-m1", "description": "Send budzi wyższego receivera.", "evidence": "sender SP i M1." }, { "id": "recv1", "number": 4, "label": "receiver obtains M1", "mode": "RUN", "event_id": "E04", "strategy_ref": "run.queue-state", "svg_label": "04", "code_ref": "src/tasks/task01_queue.c:97", "snapshot_ref": "task01.receive-m1", "description": "Handoff następuje przed dalszym kodem sendera.", "evidence": "M1=0x1111." }, { "id": "mutate", "number": 5, "label": "M2 stored, source mutated", "mode": "RUN", "event_id": "E05", "strategy_ref": "run.byte-copy", "svg_label": "05", "code_ref": "src/tasks/task01_queue.c:164", "snapshot_ref": "task01.mutated-source", "description": "Queue storage zachowuje poprzednie bajty.", "evidence": "source=0xDEAD, occupancy=1." }, { "id": "full", "number": 6, "label": "sender blocked with M3", "mode": "RUN", "event_id": "E06", "strategy_ref": "run.queue-state", "svg_label": "06", "code_ref": "src/tasks/task01_queue.c:103", "snapshot_ref": "task01.sender-blocked", "description": "Receiver obserwuje publiczny stan.", "evidence": "eBlocked i one item." }, { "id": "recv2", "number": 7, "label": "receiver gets copied M2", "mode": "RUN", "event_id": "E07", "strategy_ref": "run.byte-copy", "svg_label": "07", "code_ref": "src/tasks/task01_queue.c:118", "snapshot_ref": "task01.receive-m2", "description": "Mutacja źródła nie zmienia queue storage.", "evidence": "M2=0x2222." }, { "id": "recv3", "number": 8, "label": "receiver gets FIFO M3", "mode": "RUN", "event_id": "E08", "strategy_ref": "run.queue-state", "svg_label": "08", "code_ref": "src/tasks/task01_queue.c:129", "snapshot_ref": "task01.receive-m3", "description": "Zwolniony sender kończy send.", "evidence": "M3=0x3333." }, { "id": "sender-done", "number": 9, "label": "sender completes after unblock", "mode": "RUN", "event_id": "E09", "strategy_ref": "run.queue-state", "svg_label": "09", "code_ref": "src/tasks/task01_queue.c:177", "snapshot_ref": "task01.sender-finished", "description": "Publikacja następuje przed self-delete.", "evidence": "nine committed events." }, { "id": "pass", "number": 10, "label": "verifier commits PASS", "mode": "RUN", "event_id": "E10", "strategy_ref": "run.pass", "svg_label": "10", "code_ref": "src/tasks/task01_queue.c:228", "snapshot_ref": "task01.pass", "description": "Najniższy priorytet sprawdza całość.", "evidence": "PASS=1 i digest." } ] } ] } } ] }, { "title": "A6 — State", "order": 50, "content_kind": "prose", "asset_page_mode": "one-per-page", "page_orientation": "landscape", "content_tex": "EMPTY może blokować receive, FULL może blokować send. Operacja przeciwna zwalnia wait list i może natychmiast uruchomić task o wyższym priorytecie.", "assets": [ { "path": "assets/a6-state.png", "html_path": "assets/a6-state.svg", "source_path": "assets/a6-state.puml", "caption": "A6 STATE — EMPTY, FULL, handoff i FIFO.", "label": "fig:a6-state", "alt": "Maszyna stanów kolejki długości 1.", "kind": "diagram", "width": 1.0, "page_grid": { "columns": 1, "rows": 1, "page_width": 940, "page_height": 560, "overview": true, "step_tiles": { "empty": 1, "full": 1, "handoff": 1, "done": 1 } }, "interactive": { "kind": "uml-class", "storage_key": "fc05-a6-state", "title": "A6 · occupancy i task state", "task": { "id": "task01", "label": "Task01 · queue i FIFO" }, "block": { "id": "a6", "label": "A6 STATE", "description": "Occupancy kolejki jako przyczyna Blocked i Ready." }, "phases": [ { "id": "state", "label": "OCCUPANCY / WAIT LISTS", "steps": [ { "id": "empty", "number": 1, "label": "EMPTY blocks receiver", "mode": "RUN", "event_id": "E02", "strategy_ref": "run.queue-state", "svg_label": "01", "code_ref": "src/tasks/task01_queue.c:91", "snapshot_ref": "task01.receiver-empty", "description": "Brak itemu jest przyczyną blokady.", "evidence": "occupancy=0." }, { "id": "full", "number": 2, "label": "FULL blocks sender", "mode": "RUN", "event_id": "E06", "strategy_ref": "run.queue-state", "svg_label": "02", "code_ref": "src/tasks/task01_queue.c:173", "snapshot_ref": "task01.sender-blocked", "description": "Brak slotu jest przyczyną blokady.", "evidence": "occupancy=1, eBlocked." }, { "id": "handoff", "number": 3, "label": "receive frees slot and sender", "mode": "RUN", "event_id": "E07", "strategy_ref": "run.queue-state", "svg_label": "03", "code_ref": "src/tasks/task01_queue.c:112", "snapshot_ref": "task01.receive-m2", "description": "Wait list sendera staje się Ready.", "evidence": "M2 opuszcza storage." }, { "id": "done", "number": 6, "label": "FIFO trace is complete", "mode": "RUN", "event_id": "E10", "strategy_ref": "run.pass", "svg_label": "06", "code_ref": "src/tasks/task01_queue.c:220", "snapshot_ref": "task01.pass", "description": "Verifier widzi 1,2,3.", "evidence": "PASS=1." } ] } ] } } ] }, { "title": "A7 — Runtime", "order": 60, "content_kind": "prose", "asset_page_mode": "one-per-page", "page_orientation": "landscape", "content_tex": "Checkpoint E06 łączy publiczny stan taska, queue occupancy, stack sendera i niezależny storage M2.", "assets": [ { "path": "assets/a7-runtime.png", "html_path": "assets/a7-runtime.svg", "source_path": "assets/a7-runtime.puml", "caption": "A7 RUNTIME — sender Blocked na pełnej kolejce.", "label": "fig:a7-runtime", "alt": "Runtime snapshot E06.", "kind": "diagram", "width": 1.0, "page_grid": { "columns": 1, "rows": 1, "page_width": 940, "page_height": 560, "overview": true, "step_tiles": { "experiment": 1, "queue": 1, "sender": 1, "receiver": 1, "source": 1 } }, "interactive": { "kind": "uml-class", "storage_key": "fc05-a7-runtime", "title": "A7 · full queue snapshot", "task": { "id": "task01", "label": "Task01 · queue i FIFO" }, "block": { "id": "a7", "label": "A7 RUNTIME", "description": "Pełna kolejka, dwa TCB i dwa różne obszary pamięci." }, "phases": [ { "id": "runtime", "label": "TCB / QUEUE / STACK / STORAGE", "steps": [ { "id": "experiment", "number": 1, "label": "experiment stores public evidence", "mode": "RUN", "event_id": "E06", "strategy_ref": "run.queue-state", "svg_label": "01", "code_ref": "src/tasks/task01_queue.c:103", "snapshot_ref": "task01.sender-blocked", "description": "Aplikacja nie czyta prywatnego TCB.", "evidence": "eBlocked i waiting=1." }, { "id": "queue", "number": 2, "label": "queue storage owns M2", "mode": "RUN", "event_id": "E05", "strategy_ref": "run.byte-copy", "svg_label": "02", "code_ref": "src/tasks/task01_queue.c:160", "snapshot_ref": "task01.mutated-source", "description": "Queue zawiera kopię sprzed mutacji.", "evidence": "queued M2=0x2222." }, { "id": "sender", "number": 3, "label": "sender waits with pending M3", "mode": "RUN", "event_id": "E06", "strategy_ref": "run.queue-state", "svg_label": "03", "code_ref": "src/tasks/task01_queue.c:173", "snapshot_ref": "task01.sender-blocked", "description": "PC pozostaje wewnątrz send path.", "evidence": "TCB state i sender SP." }, { "id": "receiver", "number": 4, "label": "receiver runs on another stack", "mode": "RUN", "event_id": "E06", "strategy_ref": "run.queue-state", "svg_label": "04", "code_ref": "src/tasks/task01_queue.c:103", "snapshot_ref": "task01.sender-blocked", "description": "Receiver wykonuje obserwację.", "evidence": "receiver SP != sender SP." }, { "id": "source", "number": 5, "label": "source lifetime remains sender-owned", "mode": "RUN", "event_id": "E05", "strategy_ref": "run.byte-copy", "svg_label": "05", "code_ref": "src/tasks/task01_queue.c:164", "snapshot_ref": "task01.mutated-source", "description": "Zmiana źródła jest legalna po send.", "evidence": "payload=0xDEAD." } ] } ] } } ] }, { "title": "A8 — Patterns", "order": 70, "content_kind": "prose", "asset_page_mode": "one-per-page", "page_orientation": "portrait", "content_tex": "FreeRTOS zawsze kopiuje bytes itemu. Gdy item jest wskaźnikiem, kopiowany jest tylko adres, dlatego lifetime i mutability wymagają osobnego kontraktu.", "assets": [ { "path": "assets/a8-patterns.png", "html_path": "assets/a8-patterns.svg", "source_path": "assets/a8-patterns.puml", "caption": "A8 PATTERNS — value kontra pointer message.", "label": "fig:a8-patterns", "alt": "Porównanie ownership danych kolejki.", "kind": "diagram", "width": 1.0, "page_grid": { "columns": 1, "rows": 1, "page_width": 660, "page_height": 760, "overview": true, "step_tiles": { "value": 1, "pointer": 1, "contract": 1, "decision": 1 } }, "interactive": { "kind": "uml-class", "storage_key": "fc05-a8-patterns", "title": "A8 · message ownership", "task": { "id": "task01", "label": "Task01 · queue i FIFO" }, "block": { "id": "a8", "label": "A8 PATTERNS", "description": "Jawny wybór value message albo pointer ownership." }, "phases": [ { "id": "ownership", "label": "VALUE / POINTER / CONTRACT", "steps": [ { "id": "value", "number": 1, "label": "value message owns copied bytes", "mode": "CODE", "strategy_ref": "code.queue-contract", "svg_label": "01", "code_ref": "include/task01_queue_model.h:7", "description": "Mały payload jest samowystarczalny.", "evidence": "checksum w itemie." }, { "id": "pointer", "number": 2, "label": "pointer message copies address only", "mode": "CODE", "strategy_ref": "code.queue-contract", "svg_label": "02", "code_ref": "include/task01_queue_model.h:7", "description": "Alternatywa wymaga zewnętrznego lifetime.", "evidence": "Nie jest używana w FC05." }, { "id": "contract", "number": 3, "label": "ownership must be explicit", "mode": "CODE", "strategy_ref": "code.queue-contract", "svg_label": "03", "code_ref": "doc/card-plan.md:1", "description": "API musi określić mutability i release.", "evidence": "Decyzja projektowa." }, { "id": "decision", "number": 4, "label": "FC05 chooses value message", "mode": "RUN", "event_id": "E07", "strategy_ref": "run.byte-copy", "svg_label": "04", "code_ref": "src/tasks/task01_queue.c:118", "snapshot_ref": "task01.receive-m2", "description": "Eksperyment dowodzi niezależności kopii.", "evidence": "0x2222 mimo 0xDEAD." } ] } ] } } ] }, { "title": "Task01 — queue i FIFO", "order": 90, "content_kind": "tasks", "task_refs": [ "task01" ] } ], "tasks": { "task01": { "title": "Kolejka długości 1: empty, full, copy i FIFO", "uuid": "8ee8f36a-471b-51bc-97b8-e204bd541c61", "prompt_tex": "Przejdź po A2, A5, A6, A7 i A8. Odtwórz E01–E10, wskaż dwa różne wait lists i udowodnij byte-copy M2.", "criterion": "Program kończy się PASS; sender jest eBlocked na FULL; odbiór ma kolejność 1/2/3; M2 pozostaje 0x2222 po mutacji źródła; ślad i hashe są stabilne.", "conclusion_tex": "Queue occupancy jest przyczyną blokowania, priorytet steruje handoff, a queue storage zachowuje własną kopię itemu. Pointer payload wymagałby osobnego kontraktu ownership.", "flow": [ { "kind": "block", "id": "predict", "title": "A — model i przewidywanie", "content_tex": "Najpierw rozrysuj EMPTY/FULL i kolejność M1–M3.", "steps": [ { "id": "wait-lists", "title": "Wskaż dwa wait lists.", "content_tex": "Określ, które API blokuje task na EMPTY i FULL." }, { "id": "copy", "title": "Przewidź wynik mutacji.", "content_tex": "Zapisz wartość M2 przed uruchomieniem replay." } ] }, { "kind": "block", "id": "replay", "title": "B — replay Hazard3", "content_tex": "Każdy RUN rozpoczyna czystą RAM i kończy stabilnym checkpointem.", "steps": [ { "id": "empty-full", "title": "Zbadaj E02 i E06.", "content_tex": "Porównaj occupancy oraz stan receivera/sendera." }, { "id": "byte-copy", "title": "Zbadaj E05 i E07.", "content_tex": "Porównaj source, queue storage i received M2." }, { "id": "finish", "title": "Zbadaj E08–E10.", "content_tex": "Sprawdź FIFO, bounded log i digest." } ] }, { "kind": "exercise", "id": "pointer-contract", "title": "Ćwiczenie — pointer payload", "prompt_tex": "Zmień item na wskaźnik do statycznej puli trzech buforów. Zdefiniuj ownership, mutability i moment zwrotu slotu, a następnie dodaj checksum generacji zapobiegający ABA.", "evidence_tex": "Diagram A8 po zmianie, snapshot puli oraz kanoniczny digest trzech komunikatów.", "criterion": "Uczeń nie dereferencjonuje obiektu po zwrocie slotu i potrafi wskazać właściciela w każdym checkpointcie.", "based_on": [ "predict", "replay" ] } ], "educational_requirement_refs": [ "FC05.WE01" ], "learning_effect_refs": [ "FC05.EN01", "FC05.EK01" ], "assessment_criterion_ref": "FC05.KW01" } }, "tasks_order": [ "task01" ] }