Skip to content

feat(libkernel): implement SIGEV_NONE POSIX timers - #9314

Merged
oneandonlydean merged 3 commits into
boykopovar:mainfrom
DavidSamir:feat/libkernel-sys-ktimer
Oct 23, 2026
Merged

oneandonlydean merged 3 commits into
boykopovar:mainfrom
DavidSamir:feat/libkernel-sys-ktimer

Conversation

@DavidSamir

@DavidSamir DavidSamir commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

What

Implements the POSIX timer syscalls ktimer_create, ktimer_settime, ktimer_gettime, ktimer_getoverrun and ktimer_delete in libkernel, in a new libkernel/Time/Ktimer.cpp, following FreeBSD 11 sys/kern/kern_time.c (kern_ktimer_create, realtimer_settime, realtimer_gettime, realtimer_expire, itimespecfix). They replace five discovery stubs that threw.

Moved to libkernel so libkernel imports reach it on Windows. The PS5 3.20 export lists have ktimer_* in libkernel as well as libkernel_sys, and on Windows a libkernel import never searches libkernel_sys (WindowsEntryStubBuilder.cpp:175 only falls back from libkernel_sys and libkernel_web to libkernel). The libkernel_sys stubs are removed, so both imports reach the libkernel exports and the duplicate-export rule holds. The code is unchanged by the move.

  • ktimer_create:
    • Only CLOCK_REALTIME (0) and CLOCK_MONOTONIC (4) have timers; any other clock gives EINVAL.
    • A sigev_notify other than SIGEV_NONE, SIGEV_SIGNAL or SIGEV_THREAD_ID gives EINVAL, and for the two signal forms so does a sigev_signo outside 1..128.
    • Ids are the lowest free slot from 3 to 31, as FreeBSD reserves 0..2 for setitimer; EAGAIN when all are in use. A NULL timerid gives EFAULT and keeps no timer.
  • ktimer_settime:
    • A NULL value gives EFAULT, and an id that isn't live gives EINVAL.
    • itimespecfix applies to it_value, and to it_interval only when the timer is being armed; a disarming value clears the interval.
    • A non-zero value under one tick rounds up to the tick.
    • TIMER_ABSTIME (1) takes it_value as absolute on the timer's clock.
    • The old value is reported as ktimer_gettime would report it.
  • ktimer_gettime: returns the remaining time, or 1 ns for an expiry that is due but not yet processed.
  • Expiry: a one-shot timer disarms, and a periodic one moves forward by whole intervals past the current time.
  • ktimer_getoverrun: returns 0, because FreeBSD reports it_overrun_last, which only changes when the timer's signal is accepted (itimer_accept).
  • ktimer_delete: EINVAL for an id that isn't live.

Why expiry is computed on read: a SIGEV_NONE timer delivers nothing (itimer_fire does nothing for it), so expiry is worked out from the guest clock_gettime whenever the timer is read, and no thread or callout is needed.

What throws: a SIGEV_SIGNAL or SIGEV_THREAD_ID timer, and one created with a NULL sigevent (which FreeBSD turns into SIGEV_SIGNAL with SIGALRM), throws after validation, because delivering a guest signal from a timer is not modelled.

The tick: sub-tick values round to 1 ms, FreeBSD's tick at hz 1000. The console's hz is not measured, since kern.clockrate is unanswered. A debt line records both gaps.

Ktimer.cpp is added to libkernel's source list. The debt line is in libkernel.md, under Functional.

Tested

Windows 11 Pro 26200, WinLibs GCC 15.2.0 r7, Release. This is a CPU-side export, so no GPU is involved.

New test guest_kernel_sys_ktimer, which covers:

  • the creation errors, EAGAIN after 29 timers, and a deleted id being reused;
  • ids -1, 0, 2, a deleted id and 32 on all four other calls;
  • the itimerspec EINVAL fields, and a disarming value clearing the interval;
  • 1 ns rounding to 1 ms, as seen in the old value;
  • one-shot expiry;
  • a periodic timer catching up over missed periods, with getoverrun 0;
  • TIMER_ABSTIME in the future, in the past, and in the past on a periodic timer, on both clocks.

Results:

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Fixes: none
  • Unblocks: none
  • GPUs tested: n/a
  • AI-assisted: yes

@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Progress report (0c6a5bd → 642c0d5)

📈 System libraries: 42.14% (+0.04%, +4 implemented, +1 declared, -5 removed functions)

✅ 4 implemented
Library Name
libkernel ktimer_delete_nid_postfix
libkernel ktimer_getoverrun_nid_postfix
libkernel ktimer_gettime_nid_postfix
libkernel ktimer_settime_nid_postfix
🆕 1 declared as stubs
Library Name
libkernel ktimer_create_nid_postfix
🗑️ 5 removed
Library Name
libkernel_sys ktimer_create_nid_postfix
libkernel_sys ktimer_delete_nid_postfix
libkernel_sys ktimer_getoverrun_nid_postfix
libkernel_sys ktimer_gettime_nid_postfix
libkernel_sys ktimer_settime_nid_postfix

@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.

Pull request Shared files not compared
PR 4563 core/libs/prx/libkernel/CMakeLists.txt
PR 5021 core/libs/CMakeLists.txt
core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 6044 core/libs/CMakeLists.txt
core/libs/prx/libkernel/CMakeLists.txt
PR 6149 docs/dev/debt/libkernel.md
PR 6469 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 6740 docs/dev/debt/libkernel.md
PR 6830 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 6936 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 7049 docs/dev/debt/libkernel.md
PR 7088 docs/dev/debt/libkernel.md
PR 7105 docs/dev/debt/libkernel.md
PR 7121 docs/dev/debt/libkernel.md
PR 7149 docs/dev/debt/libkernel.md
PR 7201 core/libs/CMakeLists.txt
core/libs/prx/libkernel/CMakeLists.txt
PR 7275 core/libs/CMakeLists.txt
PR 7509 docs/dev/debt/libkernel.md
PR 7565 docs/dev/debt/libkernel.md
PR 7622 core/libs/CMakeLists.txt
PR 7653 docs/dev/debt/libkernel.md
PR 7780 core/libs/CMakeLists.txt
PR 8010 docs/dev/debt/libkernel.md
PR 8264 core/libs/CMakeLists.txt
PR 8285 core/libs/CMakeLists.txt
PR 8520 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 8553 docs/dev/debt/libkernel.md
PR 8650 core/libs/CMakeLists.txt
PR 9019 core/libs/CMakeLists.txt
core/libs/prx/libkernel_sys/Export.Discovery.cpp
PR 9040 core/libs/prx/libkernel_sys/Export.Discovery.cpp
PR 9103 core/libs/prx/libkernel_sys/Export.Discovery.cpp
PR 9133 docs/dev/debt/libkernel.md
PR 9161 core/libs/CMakeLists.txt
core/libs/prx/libkernel_sys/Export.Discovery.cpp
PR 9162 core/libs/CMakeLists.txt
core/libs/prx/libkernel_sys/Export.Discovery.cpp
PR 9172 core/libs/CMakeLists.txt
core/libs/prx/libkernel_sys/Export.Discovery.cpp
PR 9173 core/libs/CMakeLists.txt
PR 9208 core/libs/CMakeLists.txt
PR 9212 core/libs/CMakeLists.txt
PR 9221 core/libs/CMakeLists.txt
PR 9442 core/libs/prx/libkernel_sys/Export.Discovery.cpp
PR 9571 core/libs/CMakeLists.txt
PR 9669 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 9693 core/libs/prx/libkernel/CMakeLists.txt
core/libs/prx/libkernel_sys/Export.Discovery.cpp
docs/dev/debt/libkernel.md
PR 9713 core/libs/prx/libkernel_sys/Export.Discovery.cpp
PR 9802 core/libs/CMakeLists.txt
PR 9924 core/libs/CMakeLists.txt
PR 9933 core/libs/CMakeLists.txt

The PS5 3.20 export lists have ktimer_* in libkernel as well as
libkernel_sys, and on Windows a libkernel import never reaches
libkernel_sys. The implementation moves unchanged to
libkernel/Time/Ktimer.cpp.
@DavidSamir DavidSamir changed the title feat(libkernel_sys): implement SIGEV_NONE POSIX timers feat(libkernel): implement SIGEV_NONE POSIX timers Oct 21, 2026
@DavidSamir

Copy link
Copy Markdown
Contributor Author

Linux: Ubuntu 24.04.1 LTS (WSL2), GCC 13.3.0, Release; head 642c0d56a merged onto main 8c26eac3c.

  • guest_kernel_sys_ktimer passes 3/3.
  • Link control: with ktimer_create_nid_postfix renamed in Ktimer.cpp (instead of removing the file from the sources), the test fails to link: undefined reference to ktimer_create_nid_postfix, as listed.
  • Negative control: with the tick rounding removed (TickNanoseconds = 1), it fails at line 140. The PR text says line 142; the control fails, but at a different line on this head. I did not run the expiry-processing control.

Run from the PC (Windows host, Linux in WSL2), not from the PR author's machine.

@harisibrar1 harisibrar1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Checked against main 8b3e398 and FreeBSD releng/11.4 sys/kern/kern_time.c (kern_ktimer_create, kern_ktimer_settime/gettime/getoverrun/delete, realtimer_settime/gettime/expire, itimespecfix, itimer_accept):

  • Main still has only the five throwing ktimer_* stubs in libkernel_sys/Export.Discovery.cpp, and this head merges onto main cleanly.
  • The clock set (0 and 4), the sigevent checks (NONE, SIGNAL and THREAD_ID, signo 1..128), and ids 3..31 with EAGAIN all match kern_ktimer_create. So does the EAGAIN-before-EFAULT order for a NULL timerid, since FreeBSD only fails at the copyout.
  • The settime order (EFAULT for a NULL value before the id check), the interval being fixed only when armed, the old value taken before the store, and the absolute conversion all match realtimer_settime. Gettime checks the id before EFAULT, as kern_ktimer_gettime + copyout do.
  • The closed-form periodic catch-up gives the same next expiry as the while (cts >= value) loop in realtimer_expire, and getoverrun returning 0 is right because it_overrun_last only changes in itimer_accept.
  • Signal-delivering timers (including NULL sigevent → SIGEV_SIGNAL/SIGALRM) throw after validation, before a slot is taken, and are in the debt file. Good.
  • Small nit, not blocking: in Remaining, Expire always leaves value == 0 or value > now, so the GuestTimespec{0, 1} branch at Ktimer.cpp:98 can't be reached. It could be dropped, and the PR text adjusted to match.

Reviewed with AI assistance (Claude Code); the checks above were run locally on my machine.

@oneandonlydean oneandonlydean self-assigned this Oct 22, 2026
@oneandonlydean
oneandonlydean merged commit f075f91 into boykopovar:main Oct 23, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants