D610 - The count and the mode were both ignored
Status: measured Date: 2026-09-08
Two functions, four wrong answers
Reading every capture rather than five of them (D609) brought
016-syncbounds into the measurement table for the first
time. Eight measurements, and orbistoun disagreed with four.
sceKernelPollSema(semaphore, need)
ignored need
It called semaphore_wait(handle, Never), which took
one, whatever was asked for.
| asked | available | console | orbistoun |
|---|---|---|---|
| 0 | 0 | 0x80020016 invalid |
0x80020010 busy |
| 1 | 1 | ok | ok |
| 2 | 1 | 0x80020010 busy |
ok, having taken the one |
| 2 | 3 | ok | ok, having taken one of three |
The third row is the damaging one and the fourth is quietly wrong too. A caller told it holds two when it holds one goes on to release two, and from there the count runs away upward - which surfaces much later, somewhere else, as a semaphore that never blocks.
take is all-or-nothing now, which is what makes it a
counting semaphore rather than a queue: a caller that asked for two and
received one has no way to say so and no way to give it back.
sceKernelWaitSema takes the same count for the same reason
- nothing measured it, because a check that blocks forever is not
something a conformance probe can run, but the two calls differ in
whether they wait and in nothing else.
sceKernelPollEventFlag(flag, pattern, mode, …)
read one bit of the mode
It tested mode & 0x01 and treated everything else as
or.
| mode | console | orbistoun |
|---|---|---|
0x00 |
0x80020016 invalid |
ok |
0x01 and |
0x80020010 busy |
busy |
0x02 or |
ok | ok |
0x11 and | clear |
0x80020010 busy |
busy |
0x00 names neither and nor or,
and the platform refuses it. Reading it as or was right in
three cases out of four because the wrong branch usually
produces the right answer: a pattern that fails an
and normally satisfies an or, so nothing
anybody tried could tell the two apart. That is the shape of bug this
project's whole measurement apparatus exists to find.
wait_mode answers Some(true) for
and, Some(false) for or, and
None for a mode naming neither - including
0x03, which names both and which nothing has
measured. Refusing it is the honest answer rather than picking
whichever the first test happens to exercise.
The order the checks happen in is also measured
Fixing the mode broke measured_refusals, and correctly:
the console answers 0x80020003 to a poll on a handle it
never issued even when the mode is invalid as well.
So two measurements together fix something neither states on its own
- the handle is looked at before the mode. Validating
the mode first is defensible in isolation and gets exactly one of the
two cases wrong. sync::event_flag_exists exists so the
order can be written down rather than emerging from how the code happens
to be arranged.
The semaphore calls follow the same order, and that part is consistency rather than measurement: nothing has measured a bad handle together with a count of zero, and it says so where it is done.
Three tests changed their expectations, which needed saying
tests/posix.rs polled event flags with
mode = 0 throughout and called
sceKernelPollSema with the count argument omitted. Both
were reasonable against the old implementation and are argument errors
on the console, so each call now names its mode and its count
explicitly, with the reason at the call.
Changing a test's expectation to match new behaviour is the move that hides a regression, so it is worth being precise about which direction the evidence points: the console measured these, this repository did not, and the tests were written before the measurements existed.
What it cost to find
Nothing. The measurements have been in the sibling project's captures the whole time; what changed is that the generator read the directories they were in. Two of the four wrong answers were in code with a comment explaining why it was right.