Skip to content

fix(timekeeping): restore monotonic clock and clocksource semantics#2145

Merged
fslongjin merged 12 commits into
DragonOS-Community:masterfrom
fslongjin:codex/fix-timekeeping-phase-0a
Jul 20, 2026
Merged

fix(timekeeping): restore monotonic clock and clocksource semantics#2145
fslongjin merged 12 commits into
DragonOS-Community:masterfrom
fslongjin:codex/fix-timekeeping-phase-0a

Conversation

@fslongjin

Copy link
Copy Markdown
Member

Summary

  • separate realtime, monotonic, monotonic-raw, boottime, and coarse clock semantics
  • make clocksource registration, selection, watchdog updates, switching, and rollback transactional
  • preserve elapsed time and fractional state across clocksource changes
  • initialize KVM clock state per CPU and roll back failed AP bring-up without publishing partial state
  • guarantee timekeeper writer progress and track hardirq/softirq context explicitly
  • align nanosleep restart, signal wait, and futex timeout consumers with Linux clock domains
  • add kernel selftests, dunitest coverage, and fail-closed host/guest calibration tooling

Root cause

The previous timekeeper used the realtime epoch for clocks that must remain independent of wall-clock changes. Clocksource cycle state also had multiple owners, so updates and source changes could lose elapsed time or recurse through the timekeeper lock. Continuous readers could starve writers, and KVM clock/AP initialization could expose partially initialized per-CPU state after a failure.

Timeout consumers inherited these clock-domain errors, making relative waits and restart handling sensitive to realtime behavior.

Implementation

The timekeeper now owns independent monotonic and raw read bases. Realtime and boottime are derived through explicit offsets, while coarse clocks expose committed bases without performing a hardware read.

Clocksource control operations use a single serialized transaction with validation and rollback. A switch forwards the old source before installing the new source, retains fractional time, and publishes one coherent generation. KVM clock setup preallocates per-CPU state and only marks an AP online after initialization succeeds.

RwLock writer preference provides bounded writer progress. Explicit interrupt-context guards keep blocking lock paths out of hardirq and softirq execution. POSIX clock syscalls and timeout users now select the clock domain required by Linux semantics.

User-visible impact

  • CLOCK_REALTIME remains an epoch clock while monotonic/raw/boottime report uptime domains.
  • Wall-clock changes no longer alter monotonic timeout behavior.
  • Relative nanosleep, signal waits, and futex waits use stable monotonic deadlines.
  • Clocksource changes no longer discard the elapsed interval before the switch.
  • Failed KVM AP initialization no longer leaves partially published clock state.

This PR establishes the trustworthy Timekeeping baseline for later scheduler latency investigation; it does not claim to fix the separate lat_ctx scheduling/wakeup performance issue.

Validation

  • make kernel — x86_64 build and link passed
  • make -C kernel all ARCH=riscv64 — Rust build and kernel ELF links passed; final local packaging could not run because the optional DragonStub checkout was unavailable
  • python3 -m unittest tools.timekeeping.test_calibrate — 31/31 passed
  • make -C user/apps/timekeeping_calibration test-host — passed with static linking and warnings-as-errors
  • Python syntax checks and bash -n tools/run-qemu.sh — passed
  • KVM 2-vCPU Timekeeping/restart validation — 19/19 relevant tests passed
  • fixed-CPU monotonic/raw stress — 10,000,000 reads without regression
  • migrating monotonic/raw stress — 10,000,000 reads without regression

@github-actions github-actions Bot added the Bug fix A bug is fixed in this pull request label Jul 18, 2026
@fslongjin

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a4fcef6048

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tools/run-qemu.sh Outdated
@fslongjin

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fc6035d031

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread kernel/src/libs/rwlock_selftest.rs Outdated
Comment thread tools/timekeeping/calibrate.py Outdated
@fslongjin

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Swish!

Reviewed commit: 1a26ad275c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@fslongjin

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 10d4cdf03c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread kernel/src/driver/net/mod.rs
@fslongjin

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 789969b9b5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread kernel/src/arch/x86_64/init/mod.rs
@fslongjin

Copy link
Copy Markdown
Member Author

Fixed the Dunitest PTY hang in 9343de6.\n\nRoot causes addressed:\n- nanosleep could lose a timer wakeup before the task entered the blocked state;\n- N_TTY recursively acquired the writer-preferred termios lock and synchronously re-entered the line discipline while holding receive-path locks.\n\nValidation on 2 vCPUs:\n- ByteStream PTY regression: 200/200 passes;\n- CubeSandbox PTY suite: 27/27 passes;\n- timekeeping semantics: 15/15 passes (2 opt-in stress tests skipped);\n- restart syscall semantics: 3/3 passes;\n- ClockNanosleepRelativeAndAbsoluteDomains: 10/10 passes.\n\n@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9343de6c14

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

match clockid {
Realtime | Monotonic | Boottime | ProcessCPUTimeID | ThreadCPUTimeID => {}
Realtime | Monotonic | Boottime | ProcessCPUTimeID => {}
ThreadCPUTimeID => return Err(SystemError::EINVAL),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 对线程 CPU nanosleep 返回 ENOTSUP

在绕过 libc 直接使用 SYS_clock_nanosleep(CLOCK_THREAD_CPUTIME_ID, ...) 的场景下,这个 clock id 是有效的 POSIX clock,但内核不支持对它执行 nanosleep;Linux 内核的原始 syscall 对这类“有效但无 nsleep 操作”的 clock 返回 ENOTSUP/EOPNOTSUPP,而这里返回 EINVAL 会让直接 syscall 用户和系统调用兼容性测试观察到错误的 errno(glibc 的 clock_nanosleep() 包装层可能提前返回 EINVAL,但不能替代 syscall 层语义)。

Useful? React with 👍 / 👎.

fslongjin added 11 commits July 19, 2026 05:39
DragonOS used the realtime epoch as the basis for monotonic clocks and
spread clocksource cycle state across multiple owners.  The resulting
updates could lose elapsed time, recurse through the timekeeper lock, and
make timeout consumers depend on wall-clock adjustments.  KVM clock CPU
bring-up and interrupt-context locking also lacked transactional failure
handling.

Rework the timekeeping core around independently maintained monotonic and
raw read bases, with realtime and boottime represented as offsets.  Keep
clocksource selection, watchdog state, switching, and rollback under a
single control transaction, and preserve elapsed time and fractional state
when a source changes.

Make KVM clock setup per-CPU and transactional, including AP failure
rollback.  Add writer-preferred RwLock progress and explicit interrupt
context tracking so timekeeper writers cannot deadlock behind continuous
readers or acquire blocking paths from hardirq/softirq context.

Align POSIX clock reads, nanosleep restart handling, signal waits, and futex
timeouts with their Linux clock domains.  Add kernel selftests, dunitest
coverage, a guest calibration workload, and a fail-closed host calibration
harness for KVM and TCG evidence.

Validation:
- x86_64 kernel build and link
- RISC-V Rust build and kernel ELF link
- 31 host calibration unit tests
- guest calibration workload static build
- QEMU runner and Python syntax checks
- KVM 2-vCPU timekeeping/restart suite: 19/19 relevant tests passed
- fixed-CPU and migrating 10,000,000-read monotonicity tests passed

Signed-off-by: longjin <longjin@dragonos.org>
Serialize watchdog cleanup with clocksource registration and fully roll back partially published watchdog state. Keep hardirq nesting counters cache-line isolated and avoid the CAS loop on interrupt entry and exit.

Match Linux's settimeofday boundary after suspend, expose clocksource selftests through debugfs, and bound normal guest semantic loops while retaining the opt-in ten-million-read stress gates.

Make QEMU argv evidence fail closed, release partially initialized serial transport resources, and resolve the formatting regressions reported by CI.

Validated with make fmt, make kernel, host calibration tests, the calibration host build, and DragonOS guest timekeeping selftest and semantics suites.

Signed-off-by: longjin <longjin@dragonos.org>
Restore preemption when an already-registered rwlock writer acquisition fails, and cover the failure path in the debugfs selftest. Consolidate all selftest-only registered writer attempts behind the balanced helper.

Also preserve the underlying serial socket error in calibration diagnostics and verify both the reported detail and resource cleanup.

Validated with format and Clippy checks, the kernel build, calibration unit and host tests, and DragonOS guest timekeeping selftests.

Signed-off-by: longjin <longjin@dragonos.org>
Network polling walked the bound-socket vector by index while dropping the lock around every notification. Concurrent socket teardown could remove an earlier entry, shift the vector, and make the next index skip a poll waiter entirely.

Take one coherent Arc snapshot and reuse the shared notification path for regular polling, NAPI polling, and listener teardown. Notifications still run outside the bounds lock, preserving the required lock order, while a single read-side acquisition avoids writer-fair reacquisition stalls under close-heavy workloads.

This prevents tcp_close_semantics poll timeouts during concurrent IPv4 and dual-stack reset/close stress.

Signed-off-by: longjin <longjin@dragonos.org>
Kernel stack allocation and reclamation used try_lock_irqsave().unwrap() on their shared mapper lock. Concurrent fork and exit activity therefore converted ordinary lock contention into a kernel panic, as observed when tcp_socket_test created processes on both CPUs.

Acquire KSTACK_LOCK with the blocking irqsave spin-lock operation in both paths. This preserves the existing mapper serialization and interrupt exclusion while allowing the contending CPU to wait for the current stack operation to finish.

The gVisor tcp_socket_test now completes all 184 tests without triggering the allocation race.

Signed-off-by: longjin <longjin@dragonos.org>
Make the network interface's bound-socket table copy-on-write. Poll and notification paths now clone only the outer Arc while interrupts are disabled, while the less frequent bind and unbind paths perform any required Vec clone. This preserves a coherent notification snapshot without O(n) IRQ-off allocation or the index-shift race fixed earlier.

Use one by-value termios snapshot for each N_TTY receive batch and pass it through the nested input helpers. The previous receive path recursively acquired the same read lock; once a termios writer queued, writer-fair admission blocked the recursive reader and deadlocked both CPUs. A value snapshot preserves consistent per-batch input semantics and removes the recursive locking dependency.

Validated with make kernel, all 27 CubeSandbox PTY exec-chain tests, and all 6 TCP close semantics tests.

Signed-off-by: longjin <longjin@dragonos.org>
Apply the repository rustfmt output required by the architecture format-check jobs. No behavior changes.

Signed-off-by: longjin <longjin@dragonos.org>
Treat HPET enablement as a hardware transaction. If any validation, counter check, timer lookup, or IRQ registration step fails, restore the firmware general configuration instead of relying on the enabled flag, which is intentionally published only after IRQ setup succeeds.

Snapshot and restore each timer comparator together with its configuration. Restore timer state while the counter is disabled, then write the complete firmware general configuration last so a firmware-enabled counter resumes only after all timer registers are coherent. Normal HPET disable now reuses the same restoration path.

Validated with the repository format and Clippy checks, make kernel, and a DragonOS x86_64 fallback boot with HPET unavailable.

Signed-off-by: longjin <longjin@dragonos.org>
Use a persistent waiter notification for nanosleep timers, preserve deadline semantics across signal and restart races, and avoid recursive N_TTY termios, flow, and line-discipline wakeup locking during input processing.

This fixes the ByteStream PTY deadlocks observed in CI while keeping absolute sleeps from returning before their POSIX clock deadline.

Signed-off-by: longjin <longjin@dragonos.org>
Signed-off-by: longjin <longjin@dragonos.org>
Signed-off-by: longjin <longjin@dragonos.org>
@fslongjin
fslongjin force-pushed the codex/fix-timekeeping-phase-0a branch from f64a17f to a96bd95 Compare July 19, 2026 05:42
@fslongjin

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep it up!

Reviewed commit: a96bd956fe

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Signed-off-by: longjin <longjin@dragonos.org>
@fslongjin
fslongjin merged commit 229557c into DragonOS-Community:master Jul 20, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug fix A bug is fixed in this pull request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant