Generate comprehensive documentation for all 173 source units and integrate mkdocs-material into the build toolchain. Documentation covers kernel core, x86 architecture, drivers, applications, and all subsystems with a tabbed navigation structure. - Add mkdocs.yml with material theme, mermaid support, and tabbed nav - Add doc/index.md landing page - Generate doc/src/ markdown for every Pascal unit in src/ - Reorganize planning docs into doc/planning/ - Add compat, lvglh, and toolchain doc sections - Update Dockerfile to install python3 and mkdocs-material (pinned <2) - Replace pasdoc-based compile_docs.sh with mkdocs build --strict - Add compile_docs.sh to the main build pipeline in compile.sh - Add deploy-docs step in .drone.yml with host volume mount to nginx - Add site/.gitkeep for build output directory
4.7 KiB
4.7 KiB
Tracer Refactor Design
Goal
Refactor tracer.pas to eliminate all copy operations and use an O(1) ring buffer of PChar pointers. Maximize efficiency, minimize overhead, and guard against interrupt-driven corruption.
Agreed Design Decisions
1. No String Copies — Store PChar Directly
- Decision: Trust callers. Store the
PCharpointer directly in the ring buffer — noStringCopy, nokalloc, nokfree. - Contract:
push_traceMUST only be called with pointers to static/persistent data (e.g. string literals). Passing a heap-allocated or stack-allocated PChar that may later be freed is undefined behavior. - Rationale: All current callers pass string literals baked into the binary. This eliminates all heap allocation from the hot path.
2. Ring Buffer (O(1) push)
- Structure:
Traces: Array[0..MAX_TRACE-1] of PChar(static, 40 slots). - Index: Single
head: uint32variable. - head semantics:
headalways points to the most recently written slot. - Push operation:
head := (head + 1) mod MAX_TRACE; Traces[head] := t_name; - Read operations:
get_last_trace→Traces[head]get_trace_N(idx)→Traces[(head - idx + MAX_TRACE) mod MAX_TRACE]- idx=0 is the most recent trace, idx=39 is the oldest.
- No shifting loop. Current O(n) shift of 40 entries on every push is eliminated.
3. Initialization
- All 40 slots set to
nil. headinitialized toMAX_TRACE - 1(39).push_trace('kmain')is called, which advancesheadto 0 and writes'kmain'toTraces[0].- After init: head = 0, Traces[0] = 'kmain', all other slots = nil.
4. Interrupt Safety — Locked Boolean (Skip on Contention)
- Mechanism: A
Locked: Booleanreentrancy guard aroundpush_traceonly. - Behavior: If
push_traceis already executing (e.g., main code is mid-push) and an ISR callspush_trace, the ISR seesLocked = trueand silently drops its trace. - Readers are NOT locked:
get_last_traceandget_trace_Nalways proceed without checkingLocked. Sinceheadis advanced AFTER the pointer is written, readers always see a consistent state. - Race window analysis: There is a tiny window between checking
if not Lockedand settingLocked := truewhere an interrupt could cause both main code and ISR to enter the critical section. With the ring buffer design, the worst case is one trace being overwritten in the same slot — acceptable for a debug tracing tool.
5. pop_trace — No-Op Stub
pop_traceremains in the interface as an empty procedure (no-op).- This preserves ABI compatibility with all existing callers (
vmemorymanager,vterminal,kernel, etc.) without requiring changes across the codebase. - Traces are never removed from the ring buffer.
6. get_trace_count — Always Returns MAX_TRACE (40)
- No tracking of actual push count.
- Callers already handle
nilentries from unfilled slots. - This keeps the implementation simpler (one less variable to maintain atomically).
7. TRACER_ENABLE Compile-Time Guard — Kept
- All function bodies remain wrapped in
if TRACER_ENABLE then. - When
TRACER_ENABLE = false, the compiler dead-code eliminates all tracer logic for zero runtime cost. t_readyprovides orthogonal runtime enable/disable.
8. Dead Code Removal
The following unused code will be removed:
PTracerEntry/TTracerEntryrecord types (linked list — never used)head/tail:PTracerEntryvariables (shadow the newhead: uint32)c_lock: Boolean(declared, never set to true, unreachable guard)- Old
Locked: Booleanreplaced by newLocked: Booleanwith same semantics but cleaner usage
9. Uses Clause Cleanup
- Remove
lmemorymanager(no more kalloc/kfree). - Remove
serial(not used). - Keep
util,strings,stdio(used by terminal command).
Resulting push_trace (Pseudocode)
procedure push_trace(t_name: PChar);
begin
if TRACER_ENABLE then begin
if t_ready then begin
if not Locked then begin
Locked := true;
head := (head + 1) mod MAX_TRACE;
Traces[head] := t_name;
Locked := false;
end;
end;
end;
end;
Performance Summary
| Operation | Before | After |
|---|---|---|
| push_trace | O(n) shift + alloc | O(1) 2 stores |
| pop_trace | No-op | No-op |
| get_last_trace | O(1) | O(1) |
| get_trace_N | O(1) | O(1) |
| Memory alloc | kalloc per push | Zero |
| Memory free | kfree on overflow | Zero |
Files Changed
src/tracer.pas— Full rewrite of internals, interface unchanged.