| name | project-linux-userspace-time-domain | ||||||
|---|---|---|---|---|---|---|---|
| description | Make the Linux-hosted p-kernel's notion of time match wall-clock — Linux can delay SIGALRM delivery so naïve tick-counting drifts. Two complementary fixes plus a debug-friendly CPU-time mode. | ||||||
| metadata |
|
The problem. On arch/linux/aarch64, T-Kernel's internal time advances when the SIGALRM handler increments a tick counter. Linux can withhold scheduling from the p-kernel process arbitrarily long (other processes get the CPU), and POSIX standard signals collapse — N missed expirations of the 10 ms timer arrive as a single SIGALRM when we next run. Result: T-Kernel time drifts behind wall-clock by the amount of CPU we did not get.
Two complementary fixes; together they make the hosted port indistinguishable from bare metal in user-visible timing:
POSIX exposes the missed-expiration count directly. Replay them on each delivery:
static timer_t tid; /* exported from preempt.c */
static void sigalrm_handler(int sig) {
int missed = timer_getoverrun(tid); /* 0 if none, N otherwise */
if (arch_irq_disabled_flag) {
pending_timer_ticks += (1 + missed);
return;
}
for (int i = 0; i <= missed; i++) {
knl_timer_handler_startup();
}
}Result: tick count matches wall-clock count exactly. Bursts at signal-delivery time, but no accumulating drift.
Even with fix 1, query-the-time APIs (tk_get_tim etc.) only get a correct answer on the SIGALRM delivery moment. Between deliveries, the tick counter is stale. The fix is to make queries read the OS wall clock instead:
uint64_t arch_get_time_ms(void) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec * 1000ULL + ts.tv_nsec / 1000000ULL;
}T-Kernel's knl_current_time becomes a cached value updated on SIGALRM; queries hit clock_gettime directly. This is the same pattern Linux itself uses since NO_HZ (2007) — the tick is a scheduler hint, not a time source.
For deterministic replay and step-debugging, an opt-in mode that uses CLOCK_PROCESS_CPUTIME_ID instead:
- Time advances only while our process actually runs.
- Pausing the kernel in a debugger does not cause a flood of expired timers on resume.
- Compile-time switch (
CFN_TIME_DOMAIN_WALLvsCFN_TIME_DOMAIN_CPU) or runtime env var.
The user explicitly asked for this mode to be preserved as an option ("デバッグしづらくなりそう" — exactly why debug mode wants frozen time).
After Session 3c (LP64 allocator fix) lands and ./p-kernel produces a real boot banner. Adding time domain switching to a non-booting kernel makes no sense; it is a polish layer on a working system.
preempt.c: signal handler gainstimer_getoverrun+ replay loop. Exporttid.arch/linux/aarch64/time.c(new):arch_get_time_ms,arch_get_time_ns, mode switch.kernel/common/timer.c: whereknl_current_timeis read, replace witharch_get_time_*(gated on_TK_HOSTED_LIBC_so bare-metal stays tick-based).
Cost: roughly 20-30 lines of new code plus a handful of read-site rewrites in kernel/common/. Low risk after the allocator is healthy.