1333 lines
44 KiB
JSON
1333 lines
44 KiB
JSON
{
|
||
"$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"
|
||
]
|
||
}
|