{ "$schema": "../../../tools/card-layouts/schemas/card-source.schema.json", "schema": "esc-card-source.v1", "card": { "id": "mpabi-freertos-c-08-mutex-priority-inheritance", "series": "freertos-c", "series_title": "FreeRTOS C", "number": "08", "count": "15", "slug": "mutex-priority-inheritance", "title": "Mutex i dziedziczenie priorytetu", "topic": "ownership, bounded inversion i priority inheritance", "project": "Freestanding C nad FreeRTOS", "subject": "Informatyka", "level": "Rok 2 · L08 · RV32I/Hazard3", "revision_date": "2026-07-19T00:00:00+02:00", "status": "Gotowa", "version": "v00.01", "uuid": "b408a0e1-ca9f-52b8-9075-ff324bfce778", "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 jest utrwalona w FC07." }, { "id": "A2", "label": "STRUCTURE", "subtitle": "Mutex, owner, wait list i zasób", "status": "enabled", "target_label": "fig:a2-structure" }, { "id": "A3", "label": "DISPATCH", "subtitle": "Binding", "status": "unavailable", "reason": "FC08 nie wprowadza callbacku ani granicy ISR." }, { "id": "A4", "label": "APPLICATION", "subtitle": "Low, Medium, High i verifier", "status": "enabled", "target_label": "fig:a4-application" }, { "id": "A5", "label": "FLOW", "subtitle": "E01–E10 i handoff mutexu", "status": "enabled", "target_label": "fig:a5-flow" }, { "id": "A6", "label": "STATE", "subtitle": "Owner, waiter i effective priority", "status": "enabled", "target_label": "fig:a6-state" }, { "id": "A7", "label": "RUNTIME", "subtitle": "Handle, TCB, stos i event log", "status": "enabled", "target_label": "fig:a7-runtime" }, { "id": "A8", "label": "PATTERNS", "subtitle": "Critical, suspend, mutex, gatekeeper", "status": "enabled", "target_label": "fig:a8-patterns" } ], "debug_strategies": { "code.contract": { "id": "code.contract", "kind": "code", "action": "open", "expected_observations": [ "genuine mutex API", "brak vTaskPrioritySet" ], "assertions": [ "one mutex", "fixed p1/p2/p3" ], "evidence_fields": [ "code_ref", "API", "priority" ], "prerequisites": [ "źródło FC08" ], "layout": [ "FreeRTOSConfig", "MutexExperiment", "task priorities" ], "commands": [ "rg -n 'configUSE_MUTEXES|xSemaphore|uxTaskPriorityGet' include src" ] }, "run.inheritance": { "id": "run.inheritance", "kind": "run", "action": "replay", "expected_observations": [ "Low effective=3", "Medium Ready and not started" ], "assertions": [ "holder=Low", "High uses portMAX_DELAY" ], "evidence_fields": [ "event", "holder", "priority", "state", "PC", "SP", "timestamp" ], "prerequisites": [ "Hazard3 online", "czysta RAM" ], "layout": [ "Low/High/Medium", "mutex holder", "task states", "event log" ], "commands": [ "print g_fc08", "print g_fc08_events" ] }, "run.handoff": { "id": "run.handoff", "kind": "run", "action": "replay", "expected_observations": [ "High E07 before Medium E08", "value 2 under High ownership" ], "assertions": [ "Low restored to 1", "resource invariant" ], "evidence_fields": [ "order", "priority", "value" ], "prerequisites": [ "Low owns contended mutex" ], "layout": [ "give path", "High", "Medium", "protected value" ], "commands": [ "print g_fc08.protected_value", "print g_fc08_events[6]", "print g_fc08_events[7]" ] }, "run.pass": { "id": "run.pass", "kind": "run", "action": "replay", "expected_observations": [ "PASS=1", "10 committed records" ], "assertions": [ "stable three-run digest", "verifier priority 0" ], "evidence_fields": [ "PASS", "digest", "source blob", "ELF hash", "timestamp" ], "prerequisites": [ "three workers finished" ], "layout": [ "bounded log", "PASS", "digest" ], "commands": [ "print g_fc08_pass", "print g_fc08.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": "Mutex i dziedziczenie priorytetu", "url": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/2392f81a-ed6c-510b-86b5-06c5e2f1c6aa", "repository_url": "https://zsl-gitea.mpabi.pl/edu-freertos-c/lab-rv32i-freertos-c-resource-management", "url_host_uuid": "dce7fb9d-7b2f-5d49-96a2-3a30d3070b84", "url_domain": "mpabi.pl", "doc_uuid": "2392f81a-ed6c-510b-86b5-06c5e2f1c6aa", "revision": "v00.01", "issued_on": "2026-07-19T00:00:00+02:00", "series": "FREERTOS-C-08", "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ń odróżnia mutex od semafora binarnego i dowodzi, że FreeRTOS tymczasowo podnosi efektywny priorytet właściciela blokującego task o wyższym priorytecie.", "scope_title": "Zakres karty", "scope_content_tex": "Low p1 przejmuje mutex i tworzy High p3. High blokuje się bez timeoutu, Low dziedziczy p3, a nowy Medium p2 pozostaje Ready bez wykonania. Po give High przejmuje zasób przed Medium, a Low wraca do p1. Verifier sprawdza publiczne API, własność, trzy stosy, porządek E01–E10 i stabilny digest.", "scope_table": { "headers": [ "Lekcja", "Task", "Najważniejsza idea", "Priorytet", "Status", "Version" ], "rows": [ { "chapter": "FC08", "task": "Task01", "idea_tex": "ownership, bounded inversion i priority inheritance", "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": { "FC08.EN01": { "bloom_level": "Analiza", "label": "Model mutexu", "text": "Uczeń wiąże ownership, wait list i effective priority bez ręcznej zmiany priorytetu.", "assessment_criteria": [ "FC08.KW01" ] }, "FC08.EK01": { "bloom_level": "Zastosowanie", "label": "Replay PIP", "text": "Uczeń odtwarza E01–E10 i pokazuje holder, publiczne priority/state, trzy stosy, protected value i digest.", "assessment_criteria": [ "FC08.KW01" ] } }, "assessment_criteria": { "FC08.KW01": { "text": "PASS; Low 1→3→1; Medium eReady i started=0 podczas dziedziczenia; High E07 przed Medium E08; digest jest deterministyczny.", "learning_effects": [ "FC08.EN01", "FC08.EK01" ] } }, "educational_requirements": { "FC08.WE01": { "text": "Zbadanie mechanizmu bounded priority inversion na prawdziwym mutexie FreeRTOS.", "label": "ownership, bounded inversion i priority inheritance", "learning_effects": [ "FC08.EN01", "FC08.EK01" ], "learning_tree": { "schema": "we-learning-tree.v1", "policy": "Każda aktywna kotwica wskazuje kod lub checkpoint.", "ogolne": [ { "effect_ref": "FC08.EN01", "display": "EN LOCAL RTOS.08", "source": "LOCAL", "official": "RTOS", "local": "08", "kind": "EN", "tree_id": "FC08.WE01.OG.LOCAL.RTOS.08", "text": "Uczeń wiąże ownership, wait list i effective priority bez ręcznej zmiany priorytetu.", "kw": [ { "criterion_ref": "FC08.KW01", "display": "KW LOCAL RTOS.08", "source": "LOCAL", "kind": "KW", "official": "RTOS", "local": "08", "text": "Łączy kod, diagram i zweryfikowany dowód." } ] } ], "zawodowe": [ { "effect_ref": "FC08.EK01", "display": "EK LOCAL RTOS.08", "source": "LOCAL", "official": "RTOS", "local": "08", "kind": "EK", "tree_id": "FC08.WE01.TECH.LOCAL.RTOS.08", "text": "Uczeń odtwarza E01–E10 i pokazuje holder, publiczne priority/state, trzy stosy, protected value i digest.", "kw": [ { "criterion_ref": "FC08.KW01", "display": "KW LOCAL RTOS.08", "source": "LOCAL", "kind": "KW", "official": "RTOS", "local": "08", "text": "Łączy kod, diagram i zweryfikowany dowód." } ] } ] } } }, "debug_checkpoints": { "schema": "stem-debug-checkpoints.v1", "semantics": "deterministic-replay", "artifact": { "source": "src/tasks/task01_mutex.c", "source_git_blob": "520c0396319fb331443650c1664dfb692a806e44", "elf": "build/task01_mutex/prog.elf", "hazard3_elf_sha256": "9a02076cc36ed00ad1ca23e90c756f30cb69524fe6531983b536538bf5ebd388", "hazard3_image": "build/task01_mutex/prog.bin", "hazard3_image_sha256": "89802a1007fc59f285d07da7ba002b6593ae2cf9891df151af8182fe8bfe9b04" }, "targets": { "hazard3-sim": { "adapter": "hazard3-reset-load-replay.v1", "baseline": "restart-backend", "clean_ram": true } }, "items": { "task01.config": { "event_id": "E01", "stop": { "symbol": "fc08_checkpoint_committed", "offset": 0, "condition": "$a0 == 1" }, "verify": { "expressions": [ { "expr": "g_fc08_event_count", "equals": 1 } ] } }, "task01.low-owns": { "event_id": "E02", "stop": { "symbol": "fc08_checkpoint_committed", "offset": 0, "condition": "$a0 == 2" }, "verify": { "expressions": [ { "expr": "g_fc08.protected_value", "equals": 1 }, { "expr": "g_fc08.low_sp != 0", "equals": 1 } ] } }, "task01.high-blocks": { "event_id": "E03", "stop": { "symbol": "fc08_checkpoint_committed", "offset": 0, "condition": "$a0 == 3" }, "verify": { "expressions": [ { "expr": "g_fc08.high_sp != 0", "equals": 1 } ] } }, "task01.inherited": { "event_id": "E04", "stop": { "symbol": "fc08_checkpoint_committed", "offset": 0, "condition": "$a0 == 4" }, "verify": { "expressions": [ { "expr": "g_fc08.inherited_priority", "equals": 3 }, { "expr": "g_fc08.holder_while_contended == g_fc08.low_handle", "equals": 1 } ] } }, "task01.medium-ready": { "event_id": "E05", "stop": { "symbol": "fc08_checkpoint_committed", "offset": 0, "condition": "$a0 == 5" }, "verify": { "expressions": [ { "expr": "g_fc08.medium_state_while_inherited", "equals": 1 }, { "expr": "g_fc08.medium_started_while_inherited", "equals": 0 } ] } }, "task01.release": { "event_id": "E06", "stop": { "symbol": "fc08_checkpoint_committed", "offset": 0, "condition": "$a0 == 6" }, "verify": { "expressions": [ { "expr": "g_fc08.protected_value", "equals": 1 } ] } }, "task01.high-acquires": { "event_id": "E07", "stop": { "symbol": "fc08_checkpoint_committed", "offset": 0, "condition": "$a0 == 7" }, "verify": { "expressions": [ { "expr": "g_fc08.high_acquired", "equals": 1 }, { "expr": "g_fc08.protected_value", "equals": 2 } ] } }, "task01.medium-runs": { "event_id": "E08", "stop": { "symbol": "fc08_checkpoint_committed", "offset": 0, "condition": "$a0 == 8" }, "verify": { "expressions": [ { "expr": "g_fc08.medium_started", "equals": 1 }, { "expr": "g_fc08_events[6].event", "equals": 7 } ] } }, "task01.restored": { "event_id": "E09", "stop": { "symbol": "fc08_checkpoint_committed", "offset": 0, "condition": "$a0 == 9" }, "verify": { "expressions": [ { "expr": "g_fc08.restored_priority", "equals": 1 } ] } }, "task01.pass": { "event_id": "E10", "stop": { "symbol": "fc08_checkpoint_committed", "offset": 0, "condition": "$a0 == 10" }, "verify": { "expressions": [ { "expr": "g_fc08_pass", "equals": 1 }, { "expr": "g_fc08_event_count", "equals": 10 } ] } } } }, "sections": [ { "title": "A2 — Structure", "order": 20, "content_kind": "prose", "asset_page_mode": "one-per-page", "page_orientation": "portrait", "content_tex": "Mutex przechowuje właściciela i wait list. Dziedziczenie zmienia efektywny priorytet właściciela, nie bazową konfigurację aplikacji.", "assets": [ { "path": "assets/a2-structure.png", "html_path": "assets/a2-structure.svg", "source_path": "assets/a2-structure.puml", "caption": "A2 STRUCTURE — ownership i wait list.", "label": "fig:a2-structure", "alt": "Struktura mutexu i trzech tasków.", "kind": "diagram", "width": 1.0, "page_grid": { "columns": 1, "rows": 1, "page_width": 660, "page_height": 760, "overview": true, "step_tiles": { "mutex": 1, "low": 1, "high": 1, "medium": 1, "resource": 1 } }, "interactive": { "kind": "uml-class", "storage_key": "fc08-a2-structure", "title": "A2 · struktura mutexu", "task": { "id": "task01", "label": "Task01 · mutex i PIP" }, "block": { "id": "a2", "label": "A2 STRUCTURE", "description": "Genuine mutex, owner, waiter, Ready task and guarded resource." }, "phases": [ { "id": "structure", "label": "MUTEX / OWNER / WAITERS", "steps": [ { "id": "mutex", "number": 1, "label": "genuine FreeRTOS mutex", "mode": "CODE", "strategy_ref": "code.contract", "svg_label": "01", "code_ref": "src/tasks/task01_mutex.c:237", "description": "xSemaphoreCreateMutex wybiera mechanizm ownership/PIP.", "evidence": "xQueueCreateMutex symbol." }, { "id": "low", "number": 2, "label": "Low owns protected value", "mode": "RUN", "event_id": "E02", "strategy_ref": "run.inheritance", "svg_label": "02", "code_ref": "src/tasks/task01_mutex.c:142", "snapshot_ref": "task01.low-owns", "description": "Take z zerowym wait jest legalny dla wolnego mutexu.", "evidence": "holder Low; value 1." }, { "id": "high", "number": 3, "label": "High waits indefinitely", "mode": "RUN", "event_id": "E03", "strategy_ref": "run.inheritance", "svg_label": "03", "code_ref": "src/tasks/task01_mutex.c:97", "snapshot_ref": "task01.high-blocks", "description": "High trafia na mutex wait list.", "evidence": "High stack and Blocked path." }, { "id": "medium", "number": 4, "label": "Medium is Ready, not executed", "mode": "RUN", "event_id": "E05", "strategy_ref": "run.inheritance", "svg_label": "04", "code_ref": "src/tasks/task01_mutex.c:160", "snapshot_ref": "task01.medium-ready", "description": "P2 nie wyprzedza odziedziczonego p3.", "evidence": "eReady; started=0." }, { "id": "resource", "number": 5, "label": "all writes occur under ownership", "mode": "RUN", "event_id": "E07", "strategy_ref": "run.handoff", "svg_label": "05", "code_ref": "src/tasks/task01_mutex.c:101", "snapshot_ref": "task01.high-acquires", "description": "High zapisuje 2 po przejęciu mutexu.", "evidence": "protected_value=2." } ] } ] } } ] }, { "title": "A4 — Application", "order": 30, "content_kind": "prose", "asset_page_mode": "one-per-page", "page_orientation": "portrait", "content_tex": "Low tworzy High dopiero po przejęciu mutexu, a Medium dopiero po potwierdzeniu dziedziczenia. Topologia jest deterministyczna.", "assets": [ { "path": "assets/a4-application.png", "html_path": "assets/a4-application.svg", "source_path": "assets/a4-application.puml", "caption": "A4 APPLICATION — deterministic creation topology.", "label": "fig:a4-application", "alt": "Topologia Low, High, Medium i verifier.", "kind": "diagram", "width": 1.0, "page_grid": { "columns": 1, "rows": 1, "page_width": 660, "page_height": 760, "overview": true, "step_tiles": { "main": 1, "low": 1, "high": 1, "inherited": 1, "medium": 1, "verifier": 1 } }, "interactive": { "kind": "uml-class", "storage_key": "fc08-a4-application", "title": "A4 · topologia eksperymentu", "task": { "id": "task01", "label": "Task01 · mutex i PIP" }, "block": { "id": "a4", "label": "A4 APPLICATION", "description": "Construction order makes inheritance observable without timing guesses." }, "phases": [ { "id": "topology", "label": "CREATE / BLOCK / VERIFY", "steps": [ { "id": "main", "number": 1, "label": "main creates only Low and verifier", "mode": "CODE", "strategy_ref": "code.contract", "svg_label": "01", "code_ref": "src/tasks/task01_mutex.c:233", "description": "High nie może przejąć wolnego mutexu przed Low.", "evidence": "fixed topology." }, { "id": "low", "number": 2, "label": "Low creates High while owning", "mode": "RUN", "event_id": "E02", "strategy_ref": "run.inheritance", "svg_label": "02", "code_ref": "src/tasks/task01_mutex.c:149", "snapshot_ref": "task01.low-owns", "description": "High natychmiast preemptuje i blokuje się.", "evidence": "next event E03." }, { "id": "high", "number": 3, "label": "High creates contention", "mode": "RUN", "event_id": "E03", "strategy_ref": "run.inheritance", "svg_label": "03", "code_ref": "src/tasks/task01_mutex.c:96", "snapshot_ref": "task01.high-blocks", "description": "Nie ma sztucznej zmiany priorytetu.", "evidence": "real mutex wait." }, { "id": "inherited", "number": 4, "label": "Low continues at effective p3", "mode": "RUN", "event_id": "E04", "strategy_ref": "run.inheritance", "svg_label": "04", "code_ref": "src/tasks/task01_mutex.c:152", "snapshot_ref": "task01.inherited", "description": "Public API zwraca 3.", "evidence": "holder remains Low." }, { "id": "medium", "number": 5, "label": "Medium is the inversion probe", "mode": "RUN", "event_id": "E05", "strategy_ref": "run.inheritance", "svg_label": "05", "code_ref": "src/tasks/task01_mutex.c:162", "snapshot_ref": "task01.medium-ready", "description": "Ready p2 nie wykonuje nawet pierwszej instrukcji.", "evidence": "started=0." }, { "id": "verifier", "number": 6, "label": "lowest verifier asserts relations", "mode": "RUN", "event_id": "E10", "strategy_ref": "run.pass", "svg_label": "06", "code_ref": "src/tasks/task01_mutex.c:207", "snapshot_ref": "task01.pass", "description": "Sprawdzenie nie zakłóca workerów.", "evidence": "PASS and digest." } ] } ] } } ] }, { "title": "A5 — Flow", "order": 40, "content_kind": "prose", "asset_page_mode": "one-per-page", "page_orientation": "portrait", "content_tex": "Decydujący porządek to High blocks → Low inherits → Medium Ready/not-run → give → High acquires → Medium runs.", "assets": [ { "path": "assets/a5-flow.png", "html_path": "assets/a5-flow.svg", "source_path": "assets/a5-flow.puml", "caption": "A5 FLOW — bounded priority inversion.", "label": "fig:a5-flow", "alt": "Sekwencja dziedziczenia priorytetu.", "kind": "diagram", "width": 1.0, "page_grid": { "columns": 1, "rows": 1, "page_width": 660, "page_height": 760, "overview": true, "step_tiles": { "config": 1, "own": 1, "block": 1, "inherit": 1, "ready": 1, "give": 1, "high": 1, "medium": 1, "restore": 1, "pass": 1 } }, "interactive": { "kind": "uml-sequence", "storage_key": "fc08-a5-flow", "title": "A5 · priority inheritance flow", "task": { "id": "task01", "label": "Task01 · mutex i PIP" }, "block": { "id": "a5", "label": "A5 FLOW", "description": "One complete E01–E10 run." }, "phases": [ { "id": "flow", "label": "OWN / INHERIT / HANDOFF / RESTORE", "steps": [ { "id": "config", "number": 1, "label": "configuration committed", "mode": "RUN", "event_id": "E01", "strategy_ref": "run.inheritance", "svg_label": "01", "code_ref": "src/tasks/task01_mutex.c:236", "snapshot_ref": "task01.config", "description": "Clean RAM and fixed priorities.", "evidence": "one record." }, { "id": "own", "number": 2, "label": "Low takes mutex", "mode": "RUN", "event_id": "E02", "strategy_ref": "run.inheritance", "svg_label": "02", "code_ref": "src/tasks/task01_mutex.c:142", "snapshot_ref": "task01.low-owns", "description": "Low becomes owner.", "evidence": "value=1." }, { "id": "block", "number": 3, "label": "High blocks", "mode": "RUN", "event_id": "E03", "strategy_ref": "run.inheritance", "svg_label": "03", "code_ref": "src/tasks/task01_mutex.c:97", "snapshot_ref": "task01.high-blocks", "description": "Non-zero wait creates contention.", "evidence": "High stack." }, { "id": "inherit", "number": 4, "label": "Low inherits p3", "mode": "RUN", "event_id": "E04", "strategy_ref": "run.inheritance", "svg_label": "04", "code_ref": "src/tasks/task01_mutex.c:152", "snapshot_ref": "task01.inherited", "description": "Kernel PIP, not application code.", "evidence": "priority=3." }, { "id": "ready", "number": 5, "label": "Medium Ready but not run", "mode": "RUN", "event_id": "E05", "strategy_ref": "run.inheritance", "svg_label": "05", "code_ref": "src/tasks/task01_mutex.c:162", "snapshot_ref": "task01.medium-ready", "description": "Bounded inversion proof.", "evidence": "eReady and zero flag." }, { "id": "give", "number": 6, "label": "Low begins give", "mode": "RUN", "event_id": "E06", "strategy_ref": "run.handoff", "svg_label": "06", "code_ref": "src/tasks/task01_mutex.c:169", "snapshot_ref": "task01.release", "description": "High may preempt inside API.", "evidence": "value still 1." }, { "id": "high", "number": 7, "label": "High acquires first", "mode": "RUN", "event_id": "E07", "strategy_ref": "run.handoff", "svg_label": "07", "code_ref": "src/tasks/task01_mutex.c:101", "snapshot_ref": "task01.high-acquires", "description": "Ownership transfers to top waiter.", "evidence": "value=2." }, { "id": "medium", "number": 8, "label": "Medium runs after High", "mode": "RUN", "event_id": "E08", "strategy_ref": "run.handoff", "svg_label": "08", "code_ref": "src/tasks/task01_mutex.c:123", "snapshot_ref": "task01.medium-runs", "description": "No priority inversion remains.", "evidence": "E07 before E08." }, { "id": "restore", "number": 9, "label": "Low returns to base p1", "mode": "RUN", "event_id": "E09", "strategy_ref": "run.handoff", "svg_label": "09", "code_ref": "src/tasks/task01_mutex.c:175", "snapshot_ref": "task01.restored", "description": "Disinherit after give.", "evidence": "priority=1." }, { "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_mutex.c:207", "snapshot_ref": "task01.pass", "description": "All relational assertions hold.", "evidence": "digest 5433b784." } ] } ] } } ] }, { "title": "A6 — State", "order": 50, "content_kind": "prose", "asset_page_mode": "one-per-page", "page_orientation": "portrait", "content_tex": "High nie przejmuje zasobu w chwili blokady. Kernel tymczasowo podnosi właściciela, a dopiero give przenosi własność i przywraca bazowy priorytet.", "assets": [ { "path": "assets/a6-state.png", "html_path": "assets/a6-state.svg", "source_path": "assets/a6-state.puml", "caption": "A6 STATE — free, owned, contended, transferred.", "label": "fig:a6-state", "alt": "Maszyna stanu mutexu.", "kind": "diagram", "width": 1.0, "page_grid": { "columns": 1, "rows": 1, "page_width": 660, "page_height": 760, "overview": true, "step_tiles": { "free": 1, "owned": 1, "contended": 1, "transfer": 1, "verified": 1 } }, "interactive": { "kind": "uml-class", "storage_key": "fc08-a6-state", "title": "A6 · owner and priority state", "task": { "id": "task01", "label": "Task01 · mutex i PIP" }, "block": { "id": "a6", "label": "A6 STATE", "description": "Mutex ownership and effective-priority states." }, "phases": [ { "id": "state", "label": "FREE / OWNED / CONTENDED / TRANSFERRED", "steps": [ { "id": "free", "number": 1, "label": "mutex starts free", "mode": "RUN", "event_id": "E01", "strategy_ref": "run.inheritance", "svg_label": "01", "code_ref": "src/tasks/task01_mutex.c:237", "snapshot_ref": "task01.config", "description": "No owner.", "evidence": "handle created after E01." }, { "id": "owned", "number": 2, "label": "Low owns at p1", "mode": "RUN", "event_id": "E02", "strategy_ref": "run.inheritance", "svg_label": "02", "code_ref": "src/tasks/task01_mutex.c:142", "snapshot_ref": "task01.low-owns", "description": "Uncontended state.", "evidence": "protected value 1." }, { "id": "contended", "number": 3, "label": "High waits; Low effective p3", "mode": "RUN", "event_id": "E04", "strategy_ref": "run.inheritance", "svg_label": "03", "code_ref": "src/tasks/task01_mutex.c:152", "snapshot_ref": "task01.inherited", "description": "Owner stays Low.", "evidence": "priority 3, holder Low." }, { "id": "transfer", "number": 6, "label": "give transfers to High", "mode": "RUN", "event_id": "E07", "strategy_ref": "run.handoff", "svg_label": "06", "code_ref": "src/tasks/task01_mutex.c:103", "snapshot_ref": "task01.high-acquires", "description": "High returns from take.", "evidence": "value 2." }, { "id": "verified", "number": 9, "label": "Low is restored", "mode": "RUN", "event_id": "E09", "strategy_ref": "run.handoff", "svg_label": "09", "code_ref": "src/tasks/task01_mutex.c:175", "snapshot_ref": "task01.restored", "description": "Effective equals base again.", "evidence": "priority 1." } ] } ] } } ] }, { "title": "A7 — Runtime", "order": 60, "content_kind": "prose", "asset_page_mode": "one-per-page", "page_orientation": "portrait", "content_tex": "Aplikacja asercyjnie używa wyłącznie publicznego API. uxBasePriority i uxPriority są dowodem debuggera, a nie kontraktem kodu ucznia.", "assets": [ { "path": "assets/a7-runtime.png", "html_path": "assets/a7-runtime.svg", "source_path": "assets/a7-runtime.puml", "caption": "A7 RUNTIME — handles, stacks, public states and TCB detail.", "label": "fig:a7-runtime", "alt": "Runtime mutexu i trzech tasków.", "kind": "diagram", "width": 1.0, "page_grid": { "columns": 1, "rows": 1, "page_width": 660, "page_height": 760, "overview": true, "step_tiles": { "experiment": 1, "low": 1, "high": 1, "medium": 1, "tcb": 1, "log": 1 } }, "interactive": { "kind": "uml-class", "storage_key": "fc08-a7-runtime", "title": "A7 · runtime evidence", "task": { "id": "task01", "label": "Task01 · mutex i PIP" }, "block": { "id": "a7", "label": "A7 RUNTIME", "description": "Public acceptance evidence plus optional TCB inspection." }, "phases": [ { "id": "runtime", "label": "HANDLES / STACKS / TCB / LOG", "steps": [ { "id": "experiment", "number": 1, "label": "experiment owns bounded evidence", "mode": "CODE", "strategy_ref": "code.contract", "svg_label": "01", "code_ref": "include/task01_mutex.h:26", "description": "Persistent static context.", "evidence": "handles and observations." }, { "id": "low", "number": 2, "label": "Low handle remains forensic identity", "mode": "RUN", "event_id": "E04", "strategy_ref": "run.inheritance", "svg_label": "02", "code_ref": "src/tasks/task01_mutex.c:153", "snapshot_ref": "task01.inherited", "description": "Holder compares to saved handle.", "evidence": "SP and priority." }, { "id": "high", "number": 3, "label": "High owns distinct stack", "mode": "RUN", "event_id": "E03", "strategy_ref": "run.inheritance", "svg_label": "03", "code_ref": "src/tasks/task01_mutex.c:95", "snapshot_ref": "task01.high-blocks", "description": "Blocked task preserves context.", "evidence": "high_sp." }, { "id": "medium", "number": 4, "label": "Medium state is public eReady", "mode": "RUN", "event_id": "E05", "strategy_ref": "run.inheritance", "svg_label": "04", "code_ref": "src/tasks/task01_mutex.c:162", "snapshot_ref": "task01.medium-ready", "description": "No private TCB dependency.", "evidence": "eTaskGetState." }, { "id": "tcb", "number": 5, "label": "TCB base/effective is debugger evidence", "mode": "RUN", "event_id": "E04", "strategy_ref": "run.inheritance", "svg_label": "05", "code_ref": "vendor/FreeRTOS-Kernel/tasks.c:1000", "snapshot_ref": "task01.inherited", "description": "Inspect uxBasePriority and uxPriority only in GDB.", "evidence": "1 and 3." }, { "id": "log", "number": 6, "label": "record commits marker last", "mode": "CODE", "strategy_ref": "code.contract", "svg_label": "06", "code_ref": "src/tasks/task01_mutex.c:55", "description": "Partial record cannot masquerade as evidence.", "evidence": "committed after payload." } ] } ] } } ] }, { "title": "A8 — Patterns", "order": 70, "content_kind": "prose", "asset_page_mode": "one-per-page", "page_orientation": "landscape", "content_tex": "Critical section, scheduler suspension, mutex and gatekeeper solve different problems. FC08 requires task ownership and priority inheritance, therefore selects a mutex.", "assets": [ { "path": "assets/a8-patterns.png", "html_path": "assets/a8-patterns.svg", "source_path": "assets/a8-patterns.puml", "caption": "A8 PATTERNS — four distinct synchronization contracts.", "label": "fig:a8-patterns", "alt": "Porównanie czterech wzorców ochrony zasobu.", "kind": "diagram", "width": 1.0, "page_grid": { "columns": 1, "rows": 1, "page_width": 940, "page_height": 560, "overview": true, "step_tiles": { "critical": 1, "suspend": 1, "mutex": 1, "gatekeeper": 1 } }, "interactive": { "kind": "uml-class", "storage_key": "fc08-a8-patterns", "title": "A8 · resource-management choices", "task": { "id": "task01", "label": "Task01 · mutex i PIP" }, "block": { "id": "a8", "label": "A8 PATTERNS", "description": "Select synchronization by contract, not by similar syntax." }, "phases": [ { "id": "patterns", "label": "CRITICAL / SUSPEND / MUTEX / GATEKEEPER", "steps": [ { "id": "critical", "number": 1, "label": "critical section is bounded and nonblocking", "mode": "CODE", "strategy_ref": "code.contract", "svg_label": "01", "code_ref": "src/tasks/task01_mutex.c:48", "description": "Protects evidence commit only.", "evidence": "short interrupt mask." }, { "id": "suspend", "number": 2, "label": "scheduler suspension is not a lock", "mode": "CODE", "strategy_ref": "code.contract", "svg_label": "02", "code_ref": "doc/card-plan.md:1", "description": "Interrupts continue and ownership is absent.", "evidence": "not selected." }, { "id": "mutex", "number": 3, "label": "mutex owns and inherits", "mode": "RUN", "event_id": "E04", "strategy_ref": "run.inheritance", "svg_label": "03", "code_ref": "src/tasks/task01_mutex.c:152", "snapshot_ref": "task01.inherited", "description": "Selected FC08 contract.", "evidence": "holder Low, effective 3." }, { "id": "gatekeeper", "number": 4, "label": "gatekeeper serializes by message", "mode": "CODE", "strategy_ref": "code.contract", "svg_label": "04", "code_ref": "doc/card-plan.md:1", "description": "Useful when only one task may touch device API.", "evidence": "extension decision." } ] } ] } } ] }, { "title": "Task01 — mutex i PIP", "order": 90, "content_kind": "tasks", "task_refs": [ "task01" ] } ], "tasks": { "task01": { "title": "Low/Medium/High: ownership i dziedziczenie priorytetu", "uuid": "2392f81a-ed6c-510b-86b5-06c5e2f1c6aa", "prompt_tex": "Przejdź po A2, A4, A5, A6, A7 i A8. Odtwórz E01–E10 i udowodnij, że task średni nie wyprzedza właściciela z odziedziczonym p3.", "criterion": "PASS; Low 1→3→1; Medium eReady i started=0 podczas dziedziczenia; High E07 przed Medium E08; digest jest deterministyczny.", "conclusion_tex": "Mutex rozwiązuje bounded priority inversion przez tymczasowe podniesienie efektywnego priorytetu właściciela. Give może uruchomić High wewnątrz API, zanim kod Low wykona następną instrukcję.", "flow": [ { "kind": "block", "id": "predict", "title": "A — kontrakt i przewidywanie", "content_tex": "Rozpisz owner, wait list i priorytety p1/p2/p3.", "steps": [ { "id": "order", "title": "Przewidź E03–E08.", "content_tex": "Wskaż, kiedy Medium może wykonać pierwszą instrukcję." }, { "id": "api", "title": "Odrzuć fałszywe zamienniki.", "content_tex": "Wyjaśnij, dlaczego semafor binarny i vTaskPrioritySet nie dowodzą PIP." } ] }, { "kind": "block", "id": "replay", "title": "B — replay Hazard3", "content_tex": "Każdy RUN zaczyna się od czystej RAM.", "steps": [ { "id": "inherit", "title": "Zbadaj E02–E05.", "content_tex": "Porównaj holder, priority, eReady i started." }, { "id": "handoff", "title": "Zbadaj E06–E09.", "content_tex": "Sprawdź High-before-Medium i przywrócenie p1." }, { "id": "pass", "title": "Zbadaj E10.", "content_tex": "Zapisz PASS, trzy SP i digest." } ] }, { "kind": "exercise", "id": "lock-order", "title": "Ćwiczenie — dwie blokady", "prompt_tex": "Dodaj drugi zasób wyłącznie do modelu projektowego. Utwórz tabelę globalnego lock order, która usuwa cykl oczekiwania, i wskaż maksymalny czas trzymania obu mutexów.", "evidence_tex": "Diagram A8, tabela lock order i kontrprzykład z cyklem.", "criterion": "Porządek jest globalny, acykliczny i nie obejmuje nieograniczonej operacji.", "based_on": [ "predict", "replay" ] } ], "educational_requirement_refs": [ "FC08.WE01" ], "learning_effect_refs": [ "FC08.EN01", "FC08.EK01" ], "assessment_criterion_ref": "FC08.KW01" } }, "tasks_order": [ "task01" ] }