Files

90 lines
22 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.
{
"card":{"number":"08","slug":"mutex-priority-inheritance","title":"Mutex i dziedziczenie priorytetu","topic":"ownership, bounded inversion i priority inheritance","status":"Gotowa","version":"v00.01"},
"front":{"goal":"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":"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 E01E10 i stabilny digest."},
"viewpoints":[
{"id":"A1","label":"CONTEXT","status":"unavailable","subtitle":"Granice systemu","reason":"Granica aplikacjakernelHazard3 jest utrwalona w FC07."},
{"id":"A2","label":"STRUCTURE","status":"enabled","subtitle":"Mutex, owner, wait list i zasób"},
{"id":"A3","label":"DISPATCH","status":"unavailable","subtitle":"Binding","reason":"FC08 nie wprowadza callbacku ani granicy ISR."},
{"id":"A4","label":"APPLICATION","status":"enabled","subtitle":"Low, Medium, High i verifier"},
{"id":"A5","label":"FLOW","status":"enabled","subtitle":"E01E10 i handoff mutexu"},
{"id":"A6","label":"STATE","status":"enabled","subtitle":"Owner, waiter i effective priority"},
{"id":"A7","label":"RUNTIME","status":"enabled","subtitle":"Handle, TCB, stos i event log"},
{"id":"A8","label":"PATTERNS","status":"enabled","subtitle":"Critical, suspend, mutex, gatekeeper"}
],
"artifact":{"source":"src/tasks/task01_mutex.c","elf":"build/task01_mutex/prog.elf","image":"build/task01_mutex/prog.bin"},
"strategies":[
{"id":"code.contract","kind":"code","prerequisites":["źródło FC08"],"layout":["FreeRTOSConfig","MutexExperiment","task priorities"],"commands":["rg -n 'configUSE_MUTEXES|xSemaphore|uxTaskPriorityGet' include src"],"expected_observations":["genuine mutex API","brak vTaskPrioritySet"],"assertions":["one mutex","fixed p1/p2/p3"],"evidence_fields":["code_ref","API","priority"]},
{"id":"run.inheritance","kind":"run","prerequisites":["Hazard3 online","czysta RAM"],"layout":["Low/High/Medium","mutex holder","task states","event log"],"commands":["print g_fc08","print g_fc08_events"],"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"]},
{"id":"run.handoff","kind":"run","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]"],"expected_observations":["High E07 before Medium E08","value 2 under High ownership"],"assertions":["Low restored to 1","resource invariant"],"evidence_fields":["order","priority","value"]},
{"id":"run.pass","kind":"run","prerequisites":["three workers finished"],"layout":["bounded log","PASS","digest"],"commands":["print g_fc08_pass","print g_fc08.evidence_digest"],"expected_observations":["PASS=1","10 committed records"],"assertions":["stable three-run digest","verifier priority 0"],"evidence_fields":["PASS","digest","source blob","ELF hash","timestamp"]}
],
"checkpoints":{
"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":[
{"id":"A2","label":"STRUCTURE","title":"Structure","order":20,"orientation":"portrait","description":"Genuine mutex, owner, waiter, Ready task and guarded resource.","content_tex":"Mutex przechowuje właściciela i wait list. Dziedziczenie zmienia efektywny priorytet właściciela, nie bazową konfigurację aplikacji.","assets":[{"stem":"a2-structure","title":"A2 · struktura mutexu","caption":"A2 STRUCTURE — ownership i wait list.","label":"fig:a2-structure","alt":"Struktura mutexu i trzech tasków.","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."}
]}]}]},
{"id":"A4","label":"APPLICATION","title":"Application","order":30,"orientation":"portrait","description":"Construction order makes inheritance observable without timing guesses.","content_tex":"Low tworzy High dopiero po przejęciu mutexu, a Medium dopiero po potwierdzeniu dziedziczenia. Topologia jest deterministyczna.","assets":[{"stem":"a4-application","title":"A4 · topologia eksperymentu","caption":"A4 APPLICATION — deterministic creation topology.","label":"fig:a4-application","alt":"Topologia Low, High, Medium i verifier.","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."}
]}]}]},
{"id":"A5","label":"FLOW","title":"Flow","order":40,"orientation":"portrait","description":"One complete E01E10 run.","content_tex":"Decydujący porządek to High blocks → Low inherits → Medium Ready/not-run → give → High acquires → Medium runs.","assets":[{"stem":"a5-flow","diagram_kind":"sequence","title":"A5 · priority inheritance flow","caption":"A5 FLOW — bounded priority inversion.","label":"fig:a5-flow","alt":"Sekwencja dziedziczenia priorytetu.","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."}
]}]}]},
{"id":"A6","label":"STATE","title":"State","order":50,"orientation":"portrait","description":"Mutex ownership and effective-priority states.","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":[{"stem":"a6-state","title":"A6 · owner and priority state","caption":"A6 STATE — free, owned, contended, transferred.","label":"fig:a6-state","alt":"Maszyna stanu mutexu.","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."}
]}]}]},
{"id":"A7","label":"RUNTIME","title":"Runtime","order":60,"orientation":"portrait","description":"Public acceptance evidence plus optional TCB inspection.","content_tex":"Aplikacja asercyjnie używa wyłącznie publicznego API. uxBasePriority i uxPriority są dowodem debuggera, a nie kontraktem kodu ucznia.","assets":[{"stem":"a7-runtime","title":"A7 · runtime evidence","caption":"A7 RUNTIME — handles, stacks, public states and TCB detail.","label":"fig:a7-runtime","alt":"Runtime mutexu i trzech tasków.","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."}
]}]}]},
{"id":"A8","label":"PATTERNS","title":"Patterns","order":70,"orientation":"landscape","description":"Select synchronization by contract, not by similar syntax.","content_tex":"Critical section, scheduler suspension, mutex and gatekeeper solve different problems. FC08 requires task ownership and priority inheritance, therefore selects a mutex.","assets":[{"stem":"a8-patterns","title":"A8 · resource-management choices","caption":"A8 PATTERNS — four distinct synchronization contracts.","label":"fig:a8-patterns","alt":"Porównanie czterech wzorców ochrony zasobu.","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."}
]}]}]}
],
"learning":{"model_label":"Model mutexu","model":"Uczeń wiąże ownership, wait list i effective priority bez ręcznej zmiany priorytetu.","replay_label":"Replay PIP","replay":"Uczeń odtwarza E01E10 i pokazuje holder, publiczne priority/state, trzy stosy, protected value i digest.","criterion":"PASS; Low 1→3→1; Medium eReady i started=0 podczas dziedziczenia; High E07 przed Medium E08; digest jest deterministyczny.","requirement":"Zbadanie mechanizmu bounded priority inversion na prawdziwym mutexie FreeRTOS."},
"task":{"short_label":"mutex i PIP","title":"Low/Medium/High: ownership i dziedziczenie priorytetu","prompt_tex":"Przejdź po A2, A4, A5, A6, A7 i A8. Odtwórz E01E10 i udowodnij, że task średni nie wyprzedza właściciela z odziedziczonym p3.","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ź E03E08.","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 E02E05.","content_tex":"Porównaj holder, priority, eReady i started."},{"id":"handoff","title":"Zbadaj E06E09.","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"]}
]}
}