Files

1333 lines
44 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"$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 aplikacjakernelHazard3 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": "E01E10 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 E01E10 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 E01E10 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 E01E10."
},
"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 E01E10, 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ść M1M3.",
"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 E08E10.",
"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"
]
}