Contur 2
Educational OS kernel simulator
Loading...
Searching...
No Matches
main.cpp
Go to the documentation of this file.
1
7
8#include <cstddef>
9#include <iostream>
10#include <memory>
11#include <string>
12#include <vector>
13
14#include "contur/core/clock.h"
15
16#include "contur/arch/block.h"
20#include "contur/cpu/cpu.h"
23#include "contur/fs/simple_fs.h"
31#include "contur/memory/mmu.h"
44
45using namespace contur;
46
47namespace {
48
49 class SharedBufferTraceSink final : public ITraceSink
50 {
51 public:
52 explicit SharedBufferTraceSink(std::shared_ptr<BufferSink> sink)
53 : sink_(std::move(sink))
54 {}
55
56 void write(const TraceEvent &event) override
57 {
58 sink_->write(event);
59 }
60
61 private:
62 std::shared_ptr<BufferSink> sink_;
63 };
64
65 struct DemoKernelBuild
66 {
67 Result<std::unique_ptr<IKernel>> kernelResult;
68 std::shared_ptr<BufferSink> traceSink;
69 };
70
71} // namespace
72
73static std::vector<Block> makeProgramAddOnePlusOne()
74{
75 return {
76 {Instruction::Mov, 0, 1, 0},
77 {Instruction::Add, 0, 1, 0},
78 {Instruction::Halt, 0, 0, 0},
79 };
80}
81
82static std::vector<Block> makeProgramCounterLoop()
83{
84 return {
85 {Instruction::Mov, 0, 0, 0},
86 {Instruction::Add, 0, 1, 0},
87 {Instruction::Compare, 0, 16, 0},
88 {Instruction::JumpLess, 0, 1, 0},
89 {Instruction::Halt, 0, 0, 0},
90 };
91}
92
93static std::vector<Block> makeProgramCpuHeavy()
94{
95 return {
96 {Instruction::Mov, 1, 2, 0},
97 {Instruction::Mov, 2, 3, 0},
98 {Instruction::Mul, 1, 2, 1},
99 {Instruction::Add, 1, 7, 0},
100 {Instruction::Sub, 1, 1, 0},
101 {Instruction::Compare, 1, 20, 0},
102 {Instruction::JumpLess, 0, 2, 0},
103 {Instruction::Halt, 0, 0, 0},
104 };
105}
106
107static std::vector<Block> makeProgramLongNop(std::size_t nops)
108{
109 std::vector<Block> code;
110 code.reserve(nops + 1);
111 for (std::size_t i = 0; i < nops; ++i)
112 {
113 code.push_back({Instruction::Nop, 0, 0, 0});
114 }
115 code.push_back({Instruction::Halt, 0, 0, 0});
116 return code;
117}
118
119static std::string formatTraceEventLine(const TraceEvent &event)
120{
121 std::string line = "[" + std::to_string(event.timestamp) + "]";
122 line += "[" + std::string(traceLevelToString(event.level)) + "] ";
123 line += event.subsystem + "." + event.operation;
124 if (!event.details.empty())
125 {
126 line += " :: " + event.details;
127 }
128 return line;
129}
130
131static std::vector<std::string> formatKernelLogs(const BufferSink &sink)
132{
133 const auto events = sink.snapshot();
134 std::vector<std::string> lines;
135 lines.reserve(events.size());
136 for (const auto &event : events)
137 {
138 lines.push_back(formatTraceEventLine(event));
139 }
140
141 return lines;
142}
143
144static std::string renderKernelTraceDump(const BufferSink &sink)
145{
146 const auto events = sink.snapshot();
147
148 std::string dump;
149 dump.reserve(events.size() * 64 + 128);
150 dump += "\n=== Kernel Trace Dump ===\n";
151 for (const auto &event : events)
152 {
153 dump += formatTraceEventLine(event);
154 dump += '\n';
155 }
156 dump += "=== End Kernel Trace Dump (";
157 dump += std::to_string(events.size());
158 dump += " entries) ===\n";
159 return dump;
160}
161
162static DemoKernelBuild buildDemoKernel()
163{
164 auto traceSink = std::make_shared<BufferSink>();
165
166 auto clock = std::make_unique<SimulationClock>();
167 auto tracerSink = std::make_unique<SharedBufferTraceSink>(traceSink);
168 auto tracer = std::make_unique<Tracer>(std::move(tracerSink), *clock);
169 auto memory = std::make_unique<PhysicalMemory>(64);
170 auto replacement = std::make_unique<FifoReplacement>();
171 auto mmu = std::make_unique<Mmu>(*memory, std::move(replacement), *tracer);
172 auto virtualMem = std::make_unique<VirtualMemory>(*mmu, 1024);
173 auto cpu = std::make_unique<Cpu>(*memory);
174 auto engine = std::make_unique<InterpreterEngine>(*cpu, *memory);
175 auto policy = std::make_unique<RoundRobinPolicy>(4);
176 auto scheduler = std::make_unique<Scheduler>(std::move(policy), *tracer);
177 auto syscallTable = std::make_unique<SyscallTable>();
178 auto dispatcher = std::make_unique<Dispatcher>(*scheduler, *engine, *virtualMem, *clock, *tracer, *syscallTable);
179 auto fs = std::make_unique<SimpleFS>(128);
180 auto deviceManager = std::make_unique<DeviceManager>();
181 auto ioManager = std::make_unique<IoManager>(*fs, *deviceManager);
182 auto ipc = std::make_unique<IpcManager>();
183
184 auto kernelResult = KernelBuilder{}
185 .withClock(std::move(clock))
186 .withMemory(std::move(memory))
187 .withMmu(std::move(mmu))
188 .withVirtualMemory(std::move(virtualMem))
189 .withCpu(std::move(cpu))
190 .withExecutionEngine(std::move(engine))
191 .withScheduler(std::move(scheduler))
192 .withDispatcher(std::move(dispatcher))
193 .withTracer(std::move(tracer))
194 .withFileSystem(std::move(fs))
195 .withDeviceManager(std::move(deviceManager))
196 .withIoManager(std::move(ioManager))
197 .withIpcManager(std::move(ipc))
198 .withSyscallTable(std::move(syscallTable))
200 .build();
201
202 return DemoKernelBuild{std::move(kernelResult), std::move(traceSink)};
203}
204
205static void spawnDemoProcesses(IKernel &kernel)
206{
207 struct Demo
208 {
209 const char *name;
210 PriorityLevel pri;
211 std::int32_t nice;
212 std::vector<Block> code;
213 };
214
215 const std::vector<Demo> demos = {
216 {"calc-1-plus-1", PriorityLevel::Realtime, 0, makeProgramAddOnePlusOne()},
218 {"worker-1", PriorityLevel::Normal, 0, makeProgramCpuHeavy()},
219 {"worker-2", PriorityLevel::Normal, 5, makeProgramLongNop(24)},
220 {"background", PriorityLevel::Low, 10, makeProgramLongNop(48)},
221 {"idle-task", PriorityLevel::Idle, 19, makeProgramLongNop(96)},
222 };
223
224 for (const auto &d : demos)
225 {
226 ProcessConfig cfg;
227 cfg.name = d.name;
228 cfg.priority = Priority{d.pri, d.pri, d.nice};
229 cfg.code = d.code;
230 (void)kernel.createProcess(cfg);
231 }
232}
233
234int main()
235{
236 // Build kernel
237 auto build = buildDemoKernel();
238 if (build.kernelResult.isError())
239 {
240 std::cerr << "Failed to build kernel\n";
241 return 1;
242 }
243
244 auto kernel = std::move(build.kernelResult).value();
245
246 // Spawn demo processes
247 spawnDemoProcesses(*kernel);
248
249 // Wire up TUI stack
250 KernelDiagnostics diagnostics(*kernel);
251 KernelReadModel readModel(diagnostics);
252
253 TuiController controller(readModel, [&kernel](std::size_t step) { return kernel->runForTicks(step); }, 512);
254
255 // Launch interactive app
256 FtxuiApp app(
257 controller,
259 .defaultIntervalMs = 300,
260 .defaultStep = 1,
261 .frameIntervalMs = 33,
262 .minIntervalMs = 50,
263 .maxIntervalMs = 2000,
264 .logProvider = [traceSink = build.traceSink] { return formatKernelLogs(*traceSink); },
265 }
266 );
267
268 app.run();
269
270 std::cout << renderKernelTraceDump(*build.traceSink);
271
272 return 0;
273}
Block — the fundamental unit of simulated memory.
In-memory trace sink implementation for tests and diagnostics.
Trace sink that stores events in memory.
Definition buffer_sink.h:16
std::vector< TraceEvent > snapshot() const
Returns a copy of all captured trace events.
Full interactive TUI application using FTXUI ScreenInteractive.
Definition ftxui_app.h:62
void run()
Starts the interactive event loop. Blocks until the user quits.
Top-level kernel facade.
Definition i_kernel.h:145
virtual Result< ProcessId > createProcess(const ProcessConfig &config)=0
Creates and admits a process.
Sink interface that receives structured trace events.
Definition trace_sink.h:12
Fluent builder that assembles Kernel dependencies.
KernelBuilder & withClock(std::unique_ptr< IClock > clock)
Injects simulation clock dependency.
KernelBuilder & withFileSystem(std::unique_ptr< IFileSystem > fileSystem)
Injects filesystem dependency.
KernelBuilder & withMmu(std::unique_ptr< IMMU > mmu)
Injects MMU dependency.
Result< std::unique_ptr< IKernel > > build()
Builds a kernel instance from explicitly injected dependencies.
KernelBuilder & withVirtualMemory(std::unique_ptr< IVirtualMemory > virtualMemory)
Injects virtual memory dependency.
KernelBuilder & withCpu(std::unique_ptr< ICPU > cpu)
Injects CPU dependency.
KernelBuilder & withExecutionEngine(std::unique_ptr< IExecutionEngine > executionEngine)
Injects execution-engine dependency.
KernelBuilder & withTracer(std::unique_ptr< ITracer > tracer)
Injects tracing dependency.
KernelBuilder & withDeviceManager(std::unique_ptr< DeviceManager > deviceManager)
Injects device manager dependency.
KernelBuilder & withScheduler(std::unique_ptr< IScheduler > scheduler)
Injects scheduler dependency.
KernelBuilder & withDispatcher(std::unique_ptr< IDispatcher > dispatcher)
Injects dispatcher dependency.
KernelBuilder & withDefaultTickBudget(std::size_t ticks)
Configures default dispatcher tick budget used by Kernel::tick(0).
KernelBuilder & withIoManager(std::unique_ptr< IIoManager > ioManager)
Injects unified I/O manager dependency.
KernelBuilder & withSyscallTable(std::unique_ptr< SyscallTable > syscallTable)
Injects syscall table dependency.
KernelBuilder & withMemory(std::unique_ptr< IMemory > memory)
Injects physical memory dependency.
KernelBuilder & withIpcManager(std::unique_ptr< IpcManager > ipcManager)
Injects IPC manager dependency.
Diagnostics adapter that captures snapshots from IKernel facade.
Default implementation that adapts kernel snapshot data into TUI models.
Default MVC controller implementation.
IClock interface and SimulationClock implementation.
Cpu — concrete implementation of the ICPU interface.
DeviceManager — registry and dispatcher for I/O devices.
Dispatcher implementation.
FIFO page replacement policy — evicts the oldest loaded page.
Full interactive TUI application built on FTXUI ScreenInteractive.
IKernel facade interface for top-level kernel operations.
Read-model adapter interface that maps kernel state to TUI snapshots.
TUI controller contracts and default controller implementation.
Instruction enum class — all opcodes for the bytecode interpreter.
InterpreterEngine — bytecode interpreter execution engine.
Interrupt enum class — hardware and software interrupt codes.
IoManager implementation of the unified I/O layer.
IpcManager registry for IPC channels.
KernelBuilder dependency-injection assembler.
Default IKernelDiagnostics adapter implementation.
static std::vector< Block > makeProgramAddOnePlusOne()
Definition main.cpp:73
static std::string formatTraceEventLine(const TraceEvent &event)
Definition main.cpp:119
static std::vector< Block > makeProgramCpuHeavy()
Definition main.cpp:93
static std::string renderKernelTraceDump(const BufferSink &sink)
Definition main.cpp:144
static std::vector< std::string > formatKernelLogs(const BufferSink &sink)
Definition main.cpp:131
static DemoKernelBuild buildDemoKernel()
Definition main.cpp:162
static void spawnDemoProcesses(IKernel &kernel)
Definition main.cpp:205
static std::vector< Block > makeProgramCounterLoop()
Definition main.cpp:82
static std::vector< Block > makeProgramLongNop(std::size_t nops)
Definition main.cpp:107
int main()
Definition main.cpp:234
MMU implementation — translates virtual addresses to physical addresses.
Definition block.h:15
PriorityLevel
Discrete priority levels, from highest (Realtime) to lowest (Idle).
Definition priority.h:20
@ Low
Background tasks.
Definition priority.h:26
@ High
Above-normal urgency.
Definition priority.h:22
@ Normal
Default priority for user processes.
Definition priority.h:24
@ Realtime
Highest — time-critical, preempts everything.
Definition priority.h:21
@ Idle
Lowest — runs only when nothing else is ready.
Definition priority.h:27
@ Mov
Move immediate/register → register.
Definition instruction.h:18
@ JumpLess
Jump if less.
Definition instruction.h:32
@ Halt
Halt execution.
Definition instruction.h:42
@ Mul
Multiply: dst = dst * src.
Definition instruction.h:21
@ Compare
Compare two registers (sets flags).
Definition instruction.h:28
@ Nop
No operation.
Definition instruction.h:17
@ Sub
Subtract: dst = dst - src.
Definition instruction.h:20
@ Add
Add: dst = dst + src.
Definition instruction.h:19
constexpr std::string_view traceLevelToString(TraceLevel level) noexcept
Converts TraceLevel to a human-readable string.
Definition trace_level.h:21
PhysicalMemory — RAM simulation backed by std::vector<Block>.
Register enum class and RegisterFile — the CPU's register bank.
Round Robin scheduling policy.
Scheduler implementation hosting a pluggable policy.
Simple in-memory inode-based filesystem implementation.
Configuration for FtxuiApp behaviour.
Definition ftxui_app.h:38
Composite priority descriptor for a process.
Definition priority.h:46
Configuration payload used to create a process.
Definition i_kernel.h:31
std::vector< Block > code
Program code segment. Required for interpreter-backed processes.
Definition i_kernel.h:42
Priority priority
Initial scheduling priority.
Definition i_kernel.h:45
std::string name
Human-readable process name.
Definition i_kernel.h:36
Structured trace event record.
Definition trace_event.h:21
std::string details
Optional human-readable details payload.
Definition trace_event.h:32
Tick timestamp
Simulation timestamp when the event was emitted.
Definition trace_event.h:23
TraceLevel level
Event severity level.
Definition trace_event.h:35
SyscallTable registry and dispatch for system calls.
Trace severity levels used by the tracing subsystem.
Trace sink interface for trace event consumers.
Active tracer implementation writing events to a sink.
VirtualMemory — manages virtual address slots for processes.