D536 - One clock, two names, and one origin
guest-observed - 2026-09-04
sceKernelClockGettime is implemented. It is the third
vendor/POSIX pair after stat (D525) and pread
(D526), and it is the first where sharing the implementation was not
optional.
Why the shared part moved down a crate
The other two pairs live in one crate: orbistoun-fs owns
both stat and sceKernelStat, so sharing the
success path was a function call. This one does not. POSIX
clock_gettime is orbistoun-libc;
sceKernelClockGettime belongs to libkernel,
which orbistoun-kernel declares - and kernel does
not depend on libc, nor should it. They are sibling
subsystems.
So the shared part went to orbistoun-hle, which both
already take: the clock identifiers, the families that can be answered,
and the monotonic origin. All three are facts about the
platform rather than about either library, which is what makes
that the right floor for them.
Copying thirty lines into the second crate would have compiled and would have drifted.
The origin is the reason it matters, not the line count
since_start measures from the first call
anywhere in the process. While one library held it that
was true by accident; now it is true by construction.
It is not cosmetic: a guest reading a monotonic clock through
clock_gettime and again through
sceKernelClockGettime must not get two different elapsed
times. Two copies of an Instant::now()
OnceLock would have given exactly that, and nothing in
either library's tests would have noticed - each is right on its
own.
Failure differs, as it does for the other two pairs
POSIX answers -1; a sceKernel* call answers
0x8002_00xx. EINVAL for a clock this has no
honest source for - the per-process and per-thread CPU clocks,
CLOCK_UPTIME - because that is what the refusal
is.
Which errno the console answers is unmeasured, so the test pins the family and the sign, which is what a caller branches on, rather than a code no run has established.
Both halves were broken and watched to fail: the unwritten second
field, and answering -1.
Refusing rather than answering the nearest thing
The families that cannot be answered are refused, and that is the older decision this inherits: a guest measuring its own CPU time and receiving wall time gets a number that looks right and is not. Answering the nearest available clock is how that happens, and it is the failure principle 3 exists to prevent.
What the tests cannot prove
The values. A wall clock and an elapsed time are not reproducible, so what is checked is which source answered - the monotonic reading is small because the process just started, the real-time one is past a date already in the past. That distinguishes them without pinning either to a number no run can repeat, and it is said in both tests rather than left to be inferred.