{ "$schema": "../../../tools/card-layouts/schemas/card-source.schema.json", "schema": "esc-card-source.v1", "card": { "id": "mpabi-freertos-c-02-first-task", "series": "freertos-c", "series_title": "FreeRTOS C", "number": "02", "count": "15", "slug": "first-task-tcb-stack", "title": "Pierwszy task, TCB i stos taska", "topic": "TaskFunction_t, void* context, TaskHandle_t i time slicing", "project": "Freestanding C nad FreeRTOS", "subject": "Informatyka", "level": "Rok 2 · L02 · RV32I/Hazard3", "revision_date": "2026-07-18T00:00:00+02:00", "status": "Gotowa", "version": "v00.01", "uuid": "9ad444ee-ff3c-42c3-a108-80ed9ddb914d", "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": "Aplikacja C → FreeRTOS → Hazard3", "status": "enabled", "target_label": "fig:a1-context"}, {"id": "A2", "label": "STRUCTURE", "subtitle": "Konteksty, uchwyty, funkcje i domeny pamięci", "status": "enabled", "target_label": "fig:a2-structure"}, {"id": "A3", "label": "DISPATCH", "subtitle": "TaskFunction_t + void* → WorkerContext*", "status": "enabled", "target_label": "fig:a3-dispatch"}, {"id": "A4", "label": "APPLICATION", "subtitle": "Topologia aplikacji", "status": "unavailable", "reason": "Topologia i inwarianty surowego modułu C są już kompletne w A2 i A5; osobny A4 dublowałby treść."}, {"id": "A5", "label": "FLOW", "subtitle": "Deterministyczny przebieg E01–E12", "status": "enabled", "target_label": "fig:a5-flow-a"}, {"id": "A6", "label": "STATE", "subtitle": "Stan diagnostyczny kontekstu a stan kernela", "status": "enabled", "target_label": "fig:a6-state"}, {"id": "A7", "label": "RUNTIME", "subtitle": "Context, handle, TCB, stos, rejestry i tick", "status": "enabled", "target_label": "fig:a7-runtime"}, {"id": "A8", "label": "PATTERNS", "subtitle": "Wzorce projektowe", "status": "unavailable", "reason": "Context object, opaque handle i callback ABI są opisane dokładnie w A2/A3; osobny diagram wzorców byłby dekoracyjny."} ], "debug_strategies": { "code.context": { "id": "code.context", "kind": "code", "action": "open", "prerequisites": ["repozytorium FC02", "zweryfikowany source blob"], "layout": ["read-only source", "granica architektoniczna"], "commands": ["rg -n 'xTaskCreate|vTaskStartScheduler|TaskFunction_t' include src"], "expected_observations": ["aplikacja korzysta z publicznego C API", "kernel i port pozostają oddzielnymi warstwami"], "assertions": ["brak zależności aplikacji od pxCurrentTCB", "target to RV32I/Hazard3"], "evidence_fields": ["code_ref", "source_git_blob", "zaznaczona relacja UML"] }, "code.structure": { "id": "code.structure", "kind": "code", "action": "open", "prerequisites": ["freestanding C11", "include/task01_first_task.h"], "layout": ["source", "diagram danych", "mapa pamięci"], "commands": ["make check-contracts", "riscv64-unknown-elf-nm build/contracts/context_contract.o"], "expected_observations": ["WorkerContext nie ma ukrytego modelu obiektowego", "C akceptuje zły cast void* w fixture compile-only"], "assertions": ["&handle, wartość handle i TCB są odrębnymi pojęciami", "kontekst ma static lifetime"], "evidence_fields": ["source blob", "layout pól", "wynik check-contracts"] }, "code.abi": { "id": "code.abi", "kind": "code", "action": "open", "prerequisites": ["zbudowany prog.elf"], "layout": ["sygnatura C", "nm/readelf", "listing RV32I"], "commands": ["make check-abi", "riscv64-unknown-elf-objdump -d build/task01_first_task/prog.elf"], "expected_observations": ["TaskFunction_t ma sygnaturę void (*)(void*)", "brak manglingu i runtime C++"], "assertions": ["sum_task_entry jest symbolem C", "jawny cast nie wykonuje kontroli typu"], "evidence_fields": ["ELF hash", "symbol", "instrukcja wejścia"] }, "run.create": { "id": "run.create", "kind": "run", "action": "replay", "prerequisites": ["Hazard3 online", "czysta RAM", "aktualny ELF"], "layout": ["source", "argumenty ABI", "context", "heap_4"], "commands": ["info registers a0 a1 a2 a3 a4 a5 sp", "print g_worker_a", "print &g_worker_a.handle"], "expected_observations": ["xTaskCreate otrzymuje entry i &workerA", "handle otrzymuje opaque TCB pointer"], "assertions": ["E03 zatrzymuje się na xTaskCreate+0", "E04 ma handle != NULL"], "evidence_fields": ["event_id", "context address", "field address", "handle value", "timestamp"] }, "run.dispatch": { "id": "run.dispatch", "kind": "run", "action": "replay", "prerequisites": ["scheduler uruchomiony", "workerA READY"], "layout": ["sum_task_entry source", "assembly", "a0", "task stack"], "commands": ["info registers a0 sp pc", "x/i $pc", "print &g_worker_a", "bt"], "expected_observations": ["na sum_task_entry+0 a0 == &g_worker_a", "SP należy do osobnego stosu taska"], "assertions": ["typed pointer zachowuje ten sam adres", "cast nie tworzy drugiego dispatchu"], "evidence_fields": ["pvParameters", "WorkerContext*", "SP", "PC", "instruction"] }, "run.scheduler": { "id": "run.scheduler", "kind": "run", "action": "replay", "prerequisites": ["dwa workery priority=2", "time slicing włączony"], "layout": ["source loop", "tick", "A/B/A evidence", "PC"], "commands": ["print g_aba_task", "print g_aba_tick", "print g_observed_worker_changes"], "expected_observations": ["bufor zawiera podciąg A → B → A", "ticki są niemalejące"], "assertions": ["worker changes >= 2", "E08 emituje worker A dopiero po wykryciu podciągu"], "evidence_fields": ["triplet", "ticks", "change count", "timestamp"] }, "run.state": { "id": "run.state", "kind": "run", "action": "replay", "prerequisites": ["kanoniczny checkpoint"], "layout": ["WorkerContext", "public kernel state", "source"], "commands": ["print g_worker_a.trace_state", "print g_worker_a.handle", "info registers sp pc"], "expected_observations": ["trace_state nie jest eTaskState", "COMPLETED poprzedza self-delete"], "assertions": ["static context przeżywa usunięcie taska", "E11 jest stopem przed vTaskDelete"], "evidence_fields": ["trace state", "kernel state", "event_id", "PC"] }, "run.runtime": { "id": "run.runtime", "kind": "run", "action": "replay", "prerequisites": ["Hazard3/GDB online", "symbole ELF"], "layout": ["context", "handle/TCB", "stack", "registers", "listing"], "commands": ["print &g_worker_a", "print &g_worker_a.handle", "print g_worker_a.created_handle", "print g_worker_a.tcb_address", "print g_worker_a.stack_low", "print g_worker_a.stack_high", "info registers a0 sp pc"], "expected_observations": ["context, TCB i stack są trzema obszarami", "SP mieści się w stack range"], "assertions": ["created_handle == tcb_address", "zapisane adresy po delete są forensic i nie są dereferencjonowane"], "evidence_fields": ["context", "field address", "handle/TCB", "stack range", "SP", "PC"] }, "run.pass": { "id": "run.pass", "kind": "run", "action": "replay", "prerequisites": ["oba workery zakończone", "supervisor uruchomiony"], "layout": ["contexts", "trace", "assertions"], "commands": ["print g_worker_a", "print g_worker_b", "print g_aba_task", "print g_task01_pass"], "expected_observations": ["oba wyniki = 200010000", "oba workery wykonały 20000 iteracji"], "assertions": ["PASS = 1", "elapsed ticks >= 2", "A/B/A zapisane"], "evidence_fields": ["results", "iterations", "PASS", "ticks", "trace", "timestamp"] } }, "template": "templates/karta-klasyczna.json", "title_block": { "category": "KARTA PRACY · INFORMATYKA", "prepared_by": "M. Pabiszczak", "prepared_on": "2026-07-18T00:00:00+02:00", "title": "Pierwszy task, TCB i stos taska", "url": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/a2538a1a-3c37-4c14-a6ea-db5aba8fd038", "repository_url": "https://zsl-gitea.mpabi.pl/edu-freertos-c/lab-rv32i-freertos-c-first-task", "url_host_uuid": "dce7fb9d-7b2f-5d49-96a2-3a30d3070b84", "url_domain": "mpabi.pl", "doc_uuid": "a2538a1a-3c37-4c14-a6ea-db5aba8fd038", "revision": "v00.01", "issued_on": "2026-07-18T00:00:00+02:00", "series": "FREERTOS-C-02", "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ń tworzy task przez surowe API C FreeRTOS, śledzi \\texttt{pvParameters} od \\texttt{xTaskCreate} do typowanego \\texttt{WorkerContext} i odróżnia kontekst aplikacji od TCB oraz stosu taska. Każdy punkt wykonania odtwarza deterministycznie w Hazard3/GDB.", "scope_title": "Zakres karty", "scope_content_tex": "Dwa workery o równym priorytecie liczą sumę \\texttt{1..20000}; niżej priorytetowy supervisor sprawdza wyniki, ticki, podciąg \\texttt{A->B->A}, TCB i zakresy stosów. Poza zakresem są C++, kolejki, mutexy, ISR, timery i peryferia.", "scope_table": { "headers": ["Lekcja", "Task", "Najważniejsza idea", "Priorytet", "Status", "Version"], "rows": [{"chapter": "FC02", "task": "Task01", "idea_tex": "Raw C task, typed context, TCB i stack", "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 C i pamięci."} ] }, "learning_effects": { "FC02.EN01": {"bloom_level": "Analiza", "label": "Model C taska", "text": "Uczeń odróżnia kontekst aplikacji, opaque handle, TCB i osobny stos taska.", "assessment_criteria": ["FC02.KW01"]}, "FC02.EK01": {"bloom_level": "Zastosowanie", "label": "Replay callbacku i schedulera", "text": "Uczeń odtwarza E01–E12 i wiąże kod C z rejestrami, pamięcią oraz tickiem.", "assessment_criteria": ["FC02.KW01"]} }, "assessment_criteria": { "FC02.KW01": {"text": "Program kończy się PASS; oba wyniki wynoszą 200010000; callback-entry ma a0=&workerA; ślad zawiera A-B-A; context, TCB i stack są rozdzielone.", "learning_effects": ["FC02.EN01", "FC02.EK01"]} }, "educational_requirements": { "FC02.WE01": { "text": "Zaprojektowanie i zbadanie pierwszego taska FreeRTOS przez surowe API C.", "label": "Raw C FreeRTOS task", "learning_effects": ["FC02.EN01", "FC02.EK01"], "learning_tree": { "schema": "we-learning-tree.v1", "policy": "Każda kotwica UML ma wskazywać kod lub zweryfikowany checkpoint.", "ogolne": [{"effect_ref": "FC02.EN01", "display": "EN LOCAL C.01", "source": "LOCAL", "official": "C", "local": "01", "kind": "EN", "tree_id": "FC02.WE01.OG.LOCAL.C.01", "text": "Czyta jawny model danych C.", "kw": [{"criterion_ref": "FC02.KW01", "display": "KW LOCAL C.01", "source": "LOCAL", "kind": "KW", "official": "C", "local": "01", "text": "Rozróżnia adres pola, handle, TCB i stack."}]}], "zawodowe": [{"effect_ref": "FC02.EK01", "display": "EK LOCAL RTOS.01", "source": "LOCAL", "official": "RTOS", "local": "01", "kind": "EK", "tree_id": "FC02.WE01.TECH.LOCAL.RTOS.01", "text": "Odtwarza task w Hazard3/GDB.", "kw": [{"criterion_ref": "FC02.KW01", "display": "KW LOCAL RTOS.01", "source": "LOCAL", "kind": "KW", "official": "RTOS", "local": "01", "text": "Łączy checkpoint z UML i stanem CPU."}]}] } } }, "debug_checkpoints": { "schema": "stem-debug-checkpoints.v1", "semantics": "deterministic-replay", "artifact": { "source": "src/tasks/task01_first_task.c", "source_git_blob": "af1a98f7e0c2faaa4f7f25c0f42dd7aba723fae6", "elf": "build/task01_first_task/prog.elf", "hazard3_image": "build/task01_first_task/prog.bin", "hazard3_image_sha256": "9cc1295d111ba910077f64800905f9256d22dea97bfcfb40023444806a11ff1c" }, "targets": {"hazard3-sim": {"adapter": "hazard3-reset-load-replay.v1", "baseline": "restart-backend", "clean_ram": true}}, "items": { "task01.contexts": {"event_id": "E01", "stop": {"symbol": "task01_debug_checkpoint_committed", "offset": 0, "condition": "$a0 == 1 && $a1 == &g_worker_a"}, "verify": {"expressions": [{"expr": "g_last_checkpoint", "equals": 1}, {"expr": "g_worker_a.trace_state", "equals": 0}, {"expr": "g_worker_a.handle == 0", "equals": 1}]}}, "task01.create-request": {"event_id": "E02", "stop": {"symbol": "task01_debug_checkpoint_committed", "offset": 0, "condition": "$a0 == 2 && $a1 == &g_worker_a && g_last_checkpoint == 2"}, "verify": {"expressions": [{"expr": "g_worker_a.trace_state", "equals": 0}]}}, "task01.create-call": {"event_id": "E03", "stop": {"symbol": "xTaskCreate", "offset": 0, "condition": "$a0 == sum_task_entry && $a3 == &g_worker_a && $a5 == &g_worker_a.handle"}, "verify": {"expressions": [{"expr": "g_last_checkpoint", "equals": 3}, {"expr": "g_worker_a.trace_state", "equals": 1}]}}, "task01.ready": {"event_id": "E04", "stop": {"symbol": "task01_debug_checkpoint_committed", "offset": 0, "condition": "$a0 == 4 && $a1 == &g_worker_a"}, "verify": {"expressions": [{"expr": "g_worker_a.trace_state", "equals": 2}, {"expr": "g_worker_a.handle != 0", "equals": 1}, {"expr": "g_worker_a.created_handle == g_worker_a.handle", "equals": 1}]}}, "task01.scheduler": {"event_id": "E05", "stop": {"symbol": "task01_debug_checkpoint_committed", "offset": 0, "condition": "$a0 == 5 && $a1 == &g_worker_a"}, "verify": {"expressions": [{"expr": "g_worker_a.handle != 0", "equals": 1}, {"expr": "g_worker_b.handle != 0", "equals": 1}, {"expr": "g_supervisor.handle != 0", "equals": 1}]}}, "task01.entry": {"event_id": "E06", "stop": {"symbol": "sum_task_entry", "offset": 0, "condition": "$a0 == &g_worker_a"}, "verify": {"expressions": [{"expr": "g_worker_a.trace_state", "equals": 2}, {"expr": "g_worker_a.created_handle != 0", "equals": 1}]}}, "task01.work": {"event_id": "E07", "stop": {"symbol": "task01_debug_checkpoint_committed", "offset": 0, "condition": "$a0 == 7 && $a1 == &g_worker_a"}, "verify": {"expressions": [{"expr": "g_worker_a.trace_state", "equals": 3}, {"expr": "g_worker_a.tcb_address == g_worker_a.created_handle", "equals": 1}, {"expr": "g_worker_a.entry_sp >= g_worker_a.stack_low && g_worker_a.entry_sp <= g_worker_a.stack_high", "equals": 1}]}}, "task01.timeslice": {"event_id": "E08", "stop": {"symbol": "task01_debug_checkpoint_committed", "offset": 0, "condition": "$a0 == 8 && $a1 == &g_worker_a"}, "verify": {"expressions": [{"expr": "g_timeslice_checkpoint_seen", "equals": 1}, {"expr": "g_aba_task[0]", "equals": 0}, {"expr": "g_aba_task[1]", "equals": 1}, {"expr": "g_aba_task[2]", "equals": 0}, {"expr": "g_observed_worker_changes >= 2", "equals": 1}]}}, "task01.result": {"event_id": "E09", "stop": {"symbol": "task01_debug_checkpoint_committed", "offset": 0, "condition": "$a0 == 9 && $a1 == &g_worker_a"}, "verify": {"expressions": [{"expr": "g_worker_a.result", "equals": 200010000}, {"expr": "g_worker_a.iterations", "equals": 20000}]}}, "task01.completed": {"event_id": "E10", "stop": {"symbol": "task01_debug_checkpoint_committed", "offset": 0, "condition": "$a0 == 10 && $a1 == &g_worker_a"}, "verify": {"expressions": [{"expr": "g_worker_a.trace_state", "equals": 4}, {"expr": "g_worker_a.handle == 0", "equals": 1}, {"expr": "g_worker_a.created_handle != 0", "equals": 1}]}}, "task01.delete": {"event_id": "E11", "stop": {"symbol": "task01_debug_checkpoint_committed", "offset": 0, "condition": "$a0 == 11 && $a1 == &g_worker_a"}, "verify": {"expressions": [{"expr": "g_worker_a.trace_state", "equals": 4}, {"expr": "g_worker_a.result", "equals": 200010000}]}}, "task01.pass": {"event_id": "E12", "stop": {"symbol": "task01_debug_checkpoint_committed", "offset": 0, "condition": "$a0 == 12 && $a1 == &g_supervisor"}, "verify": {"expressions": [{"expr": "g_task01_pass", "equals": 1}, {"expr": "g_worker_a.result", "equals": 200010000}, {"expr": "g_worker_b.result", "equals": 200010000}, {"expr": "g_worker_a.iterations", "equals": 20000}, {"expr": "g_worker_b.iterations", "equals": 20000}, {"expr": "g_elapsed_ticks >= 2", "equals": 1}, {"expr": "g_observed_worker_changes >= 2", "equals": 1}, {"expr": "g_aba_seen", "equals": 1}]}} } }, "sections": [ { "title": "A1 — Context", "order": 10, "content_kind": "prose", "asset_page_mode": "one-per-page", "content_tex": "Granice odpowiedzialności: aplikacja C, publiczne API FreeRTOS, kernel/port i Hazard3.", "assets": [{ "path": "assets/a1-context.png", "html_path": "assets/a1-context.svg", "source_path": "assets/a1-context.puml", "caption": "A1 CONTEXT — od modułu aplikacji C do wykonania na Hazard3.", "label": "fig:a1-context", "alt": "Granice aplikacji C, FreeRTOS C API, kernela, portu i Hazard3.", "kind": "diagram", "width": 1.0, "page_grid": {"columns": 1, "rows": 1, "page_width": 660, "page_height": 760, "overview": true, "step_tiles": {"application": 1, "api": 1, "runtime": 1}}, "interactive": { "kind": "uml-class", "storage_key": "fc02-a1-context", "title": "A1 · granice systemu", "task": {"id": "task01", "label": "Task01 · raw C task"}, "block": {"id": "a1-context", "label": "A1 CONTEXT", "description": "Kierunek odpowiedzialności bez udawania runtime."}, "phases": [{"id": "system-boundary", "label": "BOUNDARIES", "steps": [ {"id": "application", "number": 1, "label": "application module requests tasks", "mode": "CODE", "strategy_ref": "code.context", "svg_label": "01", "svg_target": "Application", "code_ref": "src/tasks/task01_first_task.c:308", "description": "main przygotowuje konteksty i żąda utworzenia tasków.", "evidence": "Moduł zna wyłącznie publiczne nagłówki FreeRTOS."}, {"id": "api", "number": 2, "label": "FreeRTOS C API owns scheduling", "mode": "CODE", "strategy_ref": "code.context", "svg_label": "02", "svg_target": "CAPI", "code_ref": "vendor/FreeRTOS-Kernel/include/task.h:1", "description": "TaskFunction_t i xTaskCreate definiują granicę C.", "evidence": "Aplikacja nie używa pxCurrentTCB."}, {"id": "runtime", "number": 3, "label": "kernel/port execute on Hazard3", "mode": "CODE", "strategy_ref": "code.context", "svg_label": "03", "svg_target": "Runtime", "code_ref": "include/FreeRTOSConfig.h:1", "description": "Scheduler, tick, heap_4 i port RV32I wykonują taski.", "evidence": "Konfiguracja włącza preemption, time slicing i dynamic allocation."} ]}] } }] }, { "title": "A2 — Structure", "order": 20, "content_kind": "prose", "asset_page_mode": "one-per-page", "page_orientation": "landscape", "content_tex": "Jawny model danych C oraz rozdział static context, opaque handle, TCB i task stack.", "assets": [{ "path": "assets/a2-structure.png", "html_path": "assets/a2-structure.svg", "source_path": "assets/a2-structure.puml", "caption": "A2 STRUCTURE — konteksty, funkcje wejściowe, inwarianty i domeny pamięci.", "label": "fig:a2-structure", "alt": "Struktury WorkerContext i SupervisorContext oraz ich relacje z FreeRTOS.", "kind": "diagram", "width": 1.0, "page_grid": {"columns": 1, "rows": 1, "page_width": 940, "page_height": 560, "overview": true, "step_tiles": {"worker-context": 1, "handle": 1, "contexts": 1, "entries": 1, "supervisor": 1, "invariants": 1}}, "interactive": { "kind": "uml-class", "storage_key": "fc02-a2-structure", "title": "A2 · dane i funkcje C", "task": {"id": "task01", "label": "Task01 · raw C task"}, "block": {"id": "a2-structure", "label": "A2 STRUCTURE", "description": "Statyczna struktura kompilacyjna i domeny pamięci."}, "phases": [{"id": "c-data-functions", "label": "C DATA / FUNCTIONS", "steps": [ {"id": "worker-context", "number": 1, "label": "WorkerContext is application state", "mode": "CODE", "strategy_ref": "code.structure", "svg_label": "01", "svg_target": "Worker", "code_ref": "include/task01_first_task.h:18", "description": "Jawne pola tworzą obserwowalny kontekst aplikacji.", "evidence": "Brak ukrytego this, vptr i konstruktora."}, {"id": "handle", "number": 2, "label": "TaskHandle_t is an opaque handle", "mode": "CODE", "strategy_ref": "code.structure", "svg_label": "02", "svg_target": "Worker", "code_ref": "include/task01_first_task.h:25", "description": "&handle, wartość handle i adres TCB nie są tym samym pojęciem.", "evidence": "created_handle przechowuje historyczną wartość przed self-delete."}, {"id": "contexts", "number": 3, "label": "two static worker contexts", "mode": "CODE", "strategy_ref": "code.structure", "svg_label": "03", "svg_target": "Contexts", "code_ref": "src/tasks/task01_first_task.c:28", "description": "Konteksty istnieją przez cały program.", "evidence": "&g_worker_a i &g_worker_b nie leżą w ucHeap."}, {"id": "entries", "number": 4, "label": "entry functions have TaskFunction_t shape", "mode": "CODE", "strategy_ref": "code.abi", "svg_label": "04", "svg_target": "Entries", "code_ref": "include/task01_first_task.h:44", "description": "Obie funkcje wejściowe przyjmują dokładnie void*.", "evidence": "check-abi znajduje niemanglowane symbole C."}, {"id": "supervisor", "number": 5, "label": "SupervisorContext observes both workers", "mode": "CODE", "strategy_ref": "code.structure", "svg_label": "05", "svg_target": "Supervisor", "code_ref": "include/task01_first_task.h:36", "description": "Supervisor posiada wskaźniki do obu statycznych kontekstów.", "evidence": "Nie przejmuje ich lifetime ani storage."}, {"id": "invariants", "number": 6, "label": "common sum/scheduling invariants", "mode": "CODE", "strategy_ref": "code.structure", "svg_label": "06", "svg_target": "Invariants", "code_ref": "config/paired-experiment.json:1", "description": "Maszynowy kontrakt pary zamraża wspólne parametry C/C++.", "evidence": "make check-pair sprawdza kernel, config, stosy i workload."} ]}] } }] }, { "title": "A3 — Dispatch", "order": 30, "content_kind": "prose", "asset_page_mode": "one-per-page", "page_orientation": "landscape", "content_tex": "Jedna granica callbacku: function pointer i void* przechodzą do typowanego ciała C.", "assets": [{ "path": "assets/a3-dispatch.png", "html_path": "assets/a3-dispatch.svg", "source_path": "assets/a3-dispatch.puml", "caption": "A3 DISPATCH — od TaskFunction_t i xTaskCreate do WorkerContext*.", "label": "fig:a3-dispatch", "alt": "Przepływ callbacku C i odzyskanie typowanego kontekstu.", "kind": "diagram", "width": 1.0, "page_grid": {"columns": 1, "rows": 1, "page_width": 940, "page_height": 560, "overview": true, "step_tiles": {"signature": 1, "create": 1, "entry-abi": 1, "typed-context": 1, "work": 1, "wrong-cast": 1}}, "interactive": { "kind": "uml-class", "storage_key": "fc02-a3-dispatch", "title": "A3 · callback i context", "task": {"id": "task01", "label": "Task01 · raw C task"}, "block": {"id": "a3-dispatch", "label": "A3 DISPATCH", "description": "C function pointer, ABI RV32 i jawne odzyskanie typu."}, "phases": [{"id": "callback-context", "label": "CALLBACK / CONTEXT", "steps": [ {"id": "signature", "number": 1, "label": "TaskFunction_t erases context type", "mode": "CODE", "strategy_ref": "code.abi", "svg_label": "01", "svg_target": "Callback", "code_ref": "vendor/FreeRTOS-Kernel/include/projdefs.h:1", "description": "Kernel widzi tylko void (*)(void*).", "evidence": "Sygnatura nie koduje WorkerContext."}, {"id": "create", "number": 2, "label": "xTaskCreate receives entry and context", "mode": "RUN", "event_id": "E03", "strategy_ref": "run.create", "svg_label": "02", "svg_target": "Create", "code_ref": "src/tasks/task01_first_task.c:285", "snapshot_ref": "task01.create-call", "description": "Na xTaskCreate+0 rejestry niosą entry, &workerA i &workerA.handle.", "evidence": "a0=sum_task_entry, a3=&g_worker_a, a5=&g_worker_a.handle."}, {"id": "entry-abi", "number": 3, "label": "pvParameters arrives in RV32 a0", "mode": "RUN", "event_id": "E06", "strategy_ref": "run.dispatch", "svg_label": "03", "svg_target": "Entry", "code_ref": "src/tasks/task01_first_task.c:143", "snapshot_ref": "task01.entry", "description": "Stop jest na sum_task_entry+0, zanim wywołanie checkpointu nadpisze a0.", "evidence": "a0 == &g_worker_a."}, {"id": "typed-context", "number": 4, "label": "typed pointer recovers WorkerContext", "mode": "RUN", "event_id": "E07", "strategy_ref": "run.dispatch", "svg_label": "04", "svg_target": "Cast", "code_ref": "src/tasks/task01_first_task.c:145", "snapshot_ref": "task01.work", "description": "Jawny cast dokumentuje zamiar, lecz nie sprawdza typu.", "evidence": "worker i pvParameters mają ten sam adres."}, {"id": "work", "number": 5, "label": "entry executes typed calculation", "mode": "RUN", "event_id": "E09", "strategy_ref": "run.dispatch", "svg_label": "05", "svg_target": "Work", "code_ref": "src/tasks/task01_first_task.c:179", "snapshot_ref": "task01.result", "description": "Obliczenie zapisuje wynik w polu kontekstu.", "evidence": "result=200010000, iterations=20000."}, {"id": "wrong-cast", "number": 6, "label": "wrong context cast is accepted by C", "mode": "CODE", "strategy_ref": "code.structure", "svg_label": "06", "svg_target": "Hazard", "code_ref": "tests/context_contract.c:10", "description": "Fixture kompiluje się, ale nigdy nie jest linkowany ani wykonywany.", "evidence": "C nie zapewnia runtime type check dla void*."} ]}] } }] }, { "title": "A5 — Flow", "order": 40, "content_kind": "prose", "asset_page_mode": "one-per-page", "page_orientation": "landscape", "spread_group": "fc02-first-task-lifecycle", "spread_label": "FC02 · raw C task lifecycle", "spread_columns": 2, "content_tex": "E01--E12: od statycznego kontekstu do self-delete i PASS supervisora.", "assets": [ { "path": "assets/a5-flow-a.png", "html_path": "assets/a5-flow-a.svg", "source_path": "assets/a5-flow-a.puml", "caption": "A5 część 1/2 — context, create, handle i scheduler.", "label": "fig:a5-flow-a", "alt": "Pierwszy segment sekwencji raw C task.", "kind": "diagram", "width": 1.0, "page_grid": {"columns": 1, "rows": 1, "page_width": 940, "page_height": 560, "overview": true, "step_tiles": {"contexts": 1, "create-request": 1, "create-call": 1, "ready": 1, "scheduler": 1}}, "interactive": { "kind": "uml-sequence", "storage_key": "fc02-a5-flow-a", "title": "część 1/2 · context do READY", "task": {"id": "task01", "label": "Task01 · raw C task"}, "block": {"id": "a5-flow", "label": "A5 FLOW", "description": "Jeden blok i wspólni uczestnicy obejmują E01–E12."}, "phases": [{"id": "create-start", "label": "CREATE / START", "steps": [ {"id": "contexts", "number": 1, "label": "static contexts prepared", "mode": "RUN", "event_id": "E01", "strategy_ref": "run.create", "svg_label": "01", "code_ref": "src/tasks/task01_first_task.c:313", "snapshot_ref": "task01.contexts", "description": "workerA istnieje przed TCB.", "evidence": "PREPARED, handle=NULL, result=0."}, {"id": "create-request", "number": 2, "label": "first worker create request", "mode": "RUN", "event_id": "E02", "strategy_ref": "run.create", "svg_label": "02", "code_ref": "src/tasks/task01_first_task.c:277", "snapshot_ref": "task01.create-request", "description": "create_worker otrzymuje &workerA.", "evidence": "Jest to pierwsze żądanie uruchomienia."}, {"id": "create-call", "number": 3, "label": "xTaskCreate(entry, &workerA)", "mode": "RUN", "event_id": "E03", "strategy_ref": "run.create", "svg_label": "03", "code_ref": "src/tasks/task01_first_task.c:285", "snapshot_ref": "task01.create-call", "description": "ABI C przekazuje funkcję i kontekst osobno.", "evidence": "a0/a3/a5 wskazują entry/context/handle field."}, {"id": "ready", "number": 4, "label": "handle non-null; diagnostic READY", "mode": "RUN", "event_id": "E04", "strategy_ref": "run.create", "svg_label": "04", "code_ref": "src/tasks/task01_first_task.c:303", "snapshot_ref": "task01.ready", "description": "Historyczna wartość handle zostaje zachowana.", "evidence": "created_handle == handle != NULL."}, {"id": "scheduler", "number": 5, "label": "vTaskStartScheduler", "mode": "RUN", "event_id": "E05", "strategy_ref": "run.create", "svg_label": "05", "code_ref": "src/tasks/task01_first_task.c:333", "snapshot_ref": "task01.scheduler", "description": "Ostatni stop na startup stack.", "evidence": "A, B i supervisor mają utworzone handle."} ]}] } }, { "path": "assets/a5-flow-b.png", "html_path": "assets/a5-flow-b.svg", "source_path": "assets/a5-flow-b.puml", "caption": "A5 część 2/2 — callback, time slicing, wynik, delete i PASS.", "label": "fig:a5-flow-b", "alt": "Drugi segment sekwencji raw C task.", "kind": "diagram", "width": 1.0, "page_grid": {"columns": 1, "rows": 1, "page_width": 940, "page_height": 560, "overview": true, "step_tiles": {"entry": 1, "work": 1, "timeslice": 1, "result": 1, "completed": 1, "delete": 1, "pass": 1}}, "interactive": { "kind": "uml-sequence", "storage_key": "fc02-a5-flow-b", "title": "część 2/2 · RUNNING do PASS", "task": {"id": "task01", "label": "Task01 · raw C task"}, "block": {"id": "a5-flow", "label": "A5 FLOW", "description": "Kontynuacja tego samego diagramu i kontekstów."}, "phases": [{"id": "dispatch-finish", "label": "DISPATCH / FINISH", "steps": [ {"id": "entry", "number": 6, "label": "sum_task_entry(&workerA)", "mode": "RUN", "event_id": "E06", "strategy_ref": "run.dispatch", "svg_label": "06", "code_ref": "src/tasks/task01_first_task.c:143", "snapshot_ref": "task01.entry", "description": "Callback entry zachowuje pierwszy argument w a0.", "evidence": "a0 == &g_worker_a na wejściu symbolu."}, {"id": "work", "number": 7, "label": "typed context; RUNNING", "mode": "RUN", "event_id": "E07", "strategy_ref": "run.dispatch", "svg_label": "07", "code_ref": "src/tasks/task01_first_task.c:157", "snapshot_ref": "task01.work", "description": "Kontekst jest typowany, a SP należy do stosu taska.", "evidence": "created_handle==tcb_address i stack_low<=sp<=stack_high."}, {"id": "timeslice", "number": 8, "label": "tick: A -> B -> A", "mode": "RUN", "event_id": "E08", "strategy_ref": "run.scheduler", "svg_label": "08", "code_ref": "src/tasks/task01_first_task.c:172", "snapshot_ref": "task01.timeslice", "description": "Checkpoint powstaje dopiero po wykryciu podciągu, niezależnie od pierwszego taska.", "evidence": "g_aba_task={0,1,0}; observed changes>=2."}, {"id": "result", "number": 9, "label": "result published", "mode": "RUN", "event_id": "E09", "strategy_ref": "run.dispatch", "svg_label": "09", "code_ref": "src/tasks/task01_first_task.c:179", "snapshot_ref": "task01.result", "description": "Wynik i liczba iteracji są zapisane w context.", "evidence": "200010000 i 20000."}, {"id": "completed", "number": 10, "label": "COMPLETED; public handle NULL", "mode": "RUN", "event_id": "E10", "strategy_ref": "run.state", "svg_label": "10", "code_ref": "src/tasks/task01_first_task.c:185", "snapshot_ref": "task01.completed", "description": "created_handle zachowuje forensic address, public handle zostaje wyczyszczony.", "evidence": "Static context nadal istnieje."}, {"id": "delete", "number": 11, "label": "vTaskDelete(NULL)", "mode": "RUN", "event_id": "E11", "strategy_ref": "run.state", "svg_label": "11", "code_ref": "src/tasks/task01_first_task.c:189", "snapshot_ref": "task01.delete", "description": "Stop jest przed niepowracającym self-delete.", "evidence": "Adresy TCB/stack po delete są tylko forensic."}, {"id": "pass", "number": 12, "label": "supervisor verifies PASS", "mode": "RUN", "event_id": "E12", "strategy_ref": "run.pass", "svg_label": "12", "code_ref": "src/tasks/task01_first_task.c:231", "snapshot_ref": "task01.pass", "description": "Supervisor sprawdza oba workery i wspólne inwarianty pary.", "evidence": "PASS=1, dwa wyniki, A/B/A, ticks i stack bounds."} ]}] } } ] }, { "title": "A6 — State", "order": 50, "content_kind": "prose", "asset_page_mode": "one-per-page", "content_tex": "Statyczny lifetime context, diagnostyczny trace_state i rzeczywiste stany taska kernela to trzy różne osie.", "assets": [{ "path": "assets/a6-state.png", "html_path": "assets/a6-state.svg", "source_path": "assets/a6-state.puml", "caption": "A6 STATE — korelacja stanu kontekstu z Ready, Running, time slice i Deleted.", "label": "fig:a6-state", "alt": "Oddzielne tory stanu diagnostycznego i stanu FreeRTOS.", "kind": "diagram", "width": 1.0, "page_grid": {"columns": 1, "rows": 1, "page_width": 660, "page_height": 760, "overview": true, "step_tiles": {"lifetime": 1, "prepared": 1, "running": 1, "kernel-running": 1, "timeslice": 1, "deleted": 1}}, "interactive": { "kind": "uml-state", "storage_key": "fc02-a6-state", "title": "A6 · dwa modele stanu", "task": {"id": "task01", "label": "Task01 · raw C task"}, "block": {"id": "a6-state", "label": "A6 STATE", "description": "Nie utożsamiaj trace_state z eTaskState."}, "phases": [ {"id": "context-diagnostic", "label": "CONTEXT / DIAGNOSTIC", "steps": [ {"id": "lifetime", "number": 1, "label": "static WorkerContext lifetime", "mode": "CODE", "strategy_ref": "code.structure", "svg_label": "01", "svg_target": "ObjectLifetime", "code_ref": "src/tasks/task01_first_task.c:28", "description": "Context istnieje przed taskiem i po jego self-delete.", "evidence": "Adres static storage jest stały."}, {"id": "prepared", "number": 2, "label": "PREPARED -> STARTING -> READY", "mode": "RUN", "event_id": "E04", "strategy_ref": "run.state", "svg_label": "02", "svg_target": "Starting", "code_ref": "src/tasks/task01_first_task.c:279", "snapshot_ref": "task01.ready", "description": "Stan diagnostyczny opisuje aplikację.", "evidence": "READY współistnieje z handle != NULL."}, {"id": "running", "number": 3, "label": "RUNNING -> COMPLETED", "mode": "RUN", "event_id": "E10", "strategy_ref": "run.state", "svg_label": "03", "svg_target": "RunningWrapper", "code_ref": "src/tasks/task01_first_task.c:185", "snapshot_ref": "task01.completed", "description": "COMPLETED jest zapisane przed delete.", "evidence": "Static context nie znika."} ]}, {"id": "kernel", "label": "KERNEL", "steps": [ {"id": "kernel-running", "number": 4, "label": "Ready <-> Running", "mode": "RUN", "event_id": "E07", "strategy_ref": "run.state", "svg_label": "04", "svg_target": "RunningKernel", "code_ref": "src/tasks/task01_first_task.c:157", "snapshot_ref": "task01.work", "description": "CPU-bound worker nie przechodzi przez Blocked.", "evidence": "Scheduler wybiera równorzędne Ready taski."}, {"id": "timeslice", "number": 5, "label": "equal-priority time slicing", "mode": "RUN", "event_id": "E08", "strategy_ref": "run.scheduler", "svg_label": "05", "svg_target": "TimeSlice", "code_ref": "src/tasks/task01_first_task.c:172", "snapshot_ref": "task01.timeslice", "description": "Podciąg A/B/A dowodzi wznowienia kontekstu.", "evidence": "Ticki są niemalejące."}, {"id": "deleted", "number": 6, "label": "Deleted does not destroy static context", "mode": "RUN", "event_id": "E11", "strategy_ref": "run.state", "svg_label": "06", "svg_target": "DeletedKernel", "code_ref": "src/tasks/task01_first_task.c:189", "snapshot_ref": "task01.delete", "description": "E11 jest przed delete; karta nie dereferencjonuje forensic TCB później.", "evidence": "Context/result pozostają obserwowalne dla supervisora."} ]} ] } }] }, { "title": "A7 — Runtime", "order": 60, "content_kind": "prose", "asset_page_mode": "one-per-page", "page_orientation": "landscape", "content_tex": "Dowód runtime wiąże source i ELF z adresem context, polem handle, TCB, stosem, SP, PC, tickiem i wynikiem.", "assets": [{ "path": "assets/a7-runtime.png", "html_path": "assets/a7-runtime.svg", "source_path": "assets/a7-runtime.puml", "caption": "A7 RUNTIME — context, handle/TCB, osobny stack, ABI i dowód końcowy.", "label": "fig:a7-runtime", "alt": "Mapa pamięci i dowodów runtime pierwszego taska C.", "kind": "diagram", "width": 1.0, "page_grid": {"columns": 1, "rows": 1, "page_width": 940, "page_height": 560, "overview": true, "step_tiles": {"context": 1, "handle": 1, "tcb-stack": 1, "abi": 1, "schedule": 1, "evidence": 1}}, "interactive": { "kind": "uml-object", "storage_key": "fc02-a7-runtime", "title": "A7 · mapa wykonania", "task": {"id": "task01", "label": "Task01 · raw C task"}, "block": {"id": "a7-runtime", "label": "A7 RUNTIME", "description": "Minimalny zestaw pomiarów dobrany do pytania."}, "phases": [ {"id": "memory", "label": "MEMORY", "steps": [ {"id": "context", "number": 1, "label": "context address is not TCB", "mode": "RUN", "event_id": "E04", "strategy_ref": "run.runtime", "svg_label": "01", "svg_target": "Context", "code_ref": "src/tasks/task01_first_task.c:28", "snapshot_ref": "task01.ready", "description": "&g_worker_a ma static storage.", "evidence": "Adres nie leży w ucHeap."}, {"id": "handle", "number": 2, "label": "field address, handle value and TCB", "mode": "RUN", "event_id": "E07", "strategy_ref": "run.runtime", "svg_label": "02", "svg_target": "Handle", "code_ref": "include/task01_first_task.h:25", "snapshot_ref": "task01.work", "description": "&handle jest adresem pola, handle wartością opaque.", "evidence": "created_handle == tcb_address, ale &handle różni się od obu."}, {"id": "tcb-stack", "number": 3, "label": "TCB and stack are separate heap_4 blocks", "mode": "RUN", "event_id": "E07", "strategy_ref": "run.runtime", "svg_label": "03", "svg_target": "TCB", "code_ref": "src/tasks/task01_first_task.c:126", "snapshot_ref": "task01.work", "description": "TaskStatus_t dostarcza publiczną obserwację handle i stack bounds.", "evidence": "SP należy do zakresu stack, nie do context/TCB."} ]}, {"id": "cpu-scheduler", "label": "CPU / SCHEDULER", "steps": [ {"id": "abi", "number": 4, "label": "pvParameters in a0 at callback entry", "mode": "RUN", "event_id": "E06", "strategy_ref": "run.dispatch", "svg_label": "04", "svg_target": "ABI", "code_ref": "src/tasks/task01_first_task.c:143", "snapshot_ref": "task01.entry", "description": "Stop bezpośrednio na symbolu zachowuje ABI evidence.", "evidence": "a0 == &g_worker_a."}, {"id": "schedule", "number": 5, "label": "PC, tick and A/B/A trace", "mode": "RUN", "event_id": "E08", "strategy_ref": "run.scheduler", "svg_label": "05", "svg_target": "Schedule", "code_ref": "src/tasks/task01_first_task.c:172", "snapshot_ref": "task01.timeslice", "description": "Trace liczy obserwowane zmiany workera, nie wszystkie przełączenia kernela.", "evidence": "A/B/A, ticks i PC są powiązane z E08."}, {"id": "evidence", "number": 6, "label": "result, source and checkpoint identity", "mode": "RUN", "event_id": "E12", "strategy_ref": "run.pass", "svg_label": "06", "svg_target": "Evidence", "code_ref": "src/tasks/task01_first_task.c:231", "snapshot_ref": "task01.pass", "description": "Końcowy dowód wiąże wynik ze źródłem, ELF i timestampem.", "evidence": "snapshot_ref, event_id, source blob, image hash i PASS."} ]} ] } }] }, {"title": "Task01 — Raw C task", "order": 70, "content_kind": "tasks", "task_refs": ["task01"]} ], "tasks": { "task01": { "title": "Pierwszy task FreeRTOS — callback, context, TCB i stos", "uuid": "a2538a1a-3c37-4c14-a6ea-db5aba8fd038", "prompt_tex": "Przejdź po aktywnych perspektywach A1, A2, A3, A5, A6 i A7. Dla kroków RUN użyj Enter lub F2 i udowodnij w Hazard3/GDB przepływ \\texttt{xTaskCreate -> sum_task_entry -> WorkerContext -> vTaskDelete}.", "criterion": "Program wypisuje PASS; oba wyniki wynoszą 200010000; E06 pokazuje a0=&workerA; trace zawiera A-B-A; context, TCB i stack są rozdzielone.", "conclusion_tex": "Surowe API C przekazuje zachowanie i dane oddzielnie: \\texttt{TaskFunction_t} wybiera kod, a \\texttt{void*} niesie adres jawnego kontekstu. Scheduler, TCB i stos pozostają własnością FreeRTOS.", "flow": [ {"kind": "block", "id": "c-model", "title": "A — model C i granica ABI", "content_tex": "Najpierw czytaj A1--A3 bez uruchamiania programu.", "steps": [ {"id": "read-context", "title": "Odczytaj WorkerContext.", "content_tex": "Rozróżnij static context, adres pola handle, wartość handle, TCB i stack."}, {"id": "prove-c-abi", "title": "Udowodnij callback ABI.", "content_tex": "Na E03 zbadaj argumenty xTaskCreate, a na E06 rejestr a0 przed prologiem sum_task_entry."} ]}, {"kind": "block", "id": "runtime-trace", "title": "B — sekwencja i scheduler", "content_tex": "Każdy RUN replay zaczyna się od czystej RAM.", "steps": [ {"id": "follow-context", "title": "Śledź jeden adres context.", "content_tex": "Porównaj &g_worker_a w main, xTaskCreate i sum_task_entry."}, {"id": "follow-stack", "title": "Śledź osobny stos.", "content_tex": "Potwierdź stack_low <= sp <= stack_high i created_handle == tcb_address."}, {"id": "follow-scheduler", "title": "Śledź A-B-A.", "content_tex": "Zapisz triplet workerów, ticki i liczbę obserwowanych zmian."} ]}, {"kind": "exercise", "id": "raw-c-debug-report", "title": "Ćwiczenie — timestampowany ślad taska C", "prompt_tex": "Wybierz E01, E03, E06, E08, E10 i E12. Dla każdego zapisz timestamp, PC, SP, adres context, wartość handle/TCB i stan. Wyjaśnij, których adresów po E11 nie wolno dereferencjonować.", "evidence_tex": "Timestampowane snapshoty Hazard3/GDB powiązane z kotwami UML oraz końcowy PASS.", "criterion": "Raport zachowuje tożsamość context, rozdziela TCB od stack i nie myli trace_state z eTaskState.", "based_on": ["c-model", "runtime-trace"]} ], "educational_requirement_refs": ["FC02.WE01"], "learning_effect_refs": ["FC02.EN01", "FC02.EK01"], "assessment_criterion_ref": "FC02.KW01" } }, "tasks_order": ["task01"] }