library: the harness keeps the subscribers, and an id belongs to whoever opened it
Three services had each written the same thing and got it three different ways: input polled the process list to notice a dead subscriber, and only when someone else subscribed; the power service never noticed at all; the device manager noticed drivers but not subscribers. The harness owns the table now, driven by the events a protocol declares — it registers on the reserved verb, frames each event once, posts to everyone interested without waiting on any of them, and reclaims a slot when the kernel says its owner died. Interest masks moved to the envelope, so a subscriber that wants only mice asks the same way everywhere. Two consequences the plan had not foreseen. The device manager now hears a supervised child's death twice, once as its supervisor and once as a subscriber, so restart backoff counted every crash twice and gave up after half as many; it retires the id before counting. And the kernel's published exit table had eight slots for what is now six subscriptions in a plain boot, so it holds sixteen. The other half is a hole the design named early and left standing: a backend handed out a small integer and then honoured it from anyone. A process that guessed a file's node id read another client's file; a display layer had no owner at all, so any client could reconfigure or destroy any layer; a USB device token was never checked against the client that opened it. Each is now bound to the task that opened it, and a wrong owner gets exactly what an unknown id gets — the refusal must not become the oracle the identical answers elsewhere were designed to remove. Closing a file changed with it: it used to succeed unconditionally, which would have told a caller which ids existed. Suite 111/111, with a new case in which one process holds a file and a layer, hands both ids to a second process, and finds them untouched after that process has tried everything with them.
This commit is contained in:
@@ -46,8 +46,12 @@ asked once at connect time rather than out of every packet's budget.
|
||||
|
||||
Events are published, not polled: like the input service, the service holds
|
||||
subscriber endpoints as capabilities and `ipc_send`s each event as a buffered
|
||||
packet, so a slow or dead subscriber can never wedge the source. **The kind is
|
||||
the packet's operation** — one declared event per named kind, exactly as the
|
||||
packet, so a slow or dead subscriber can never wedge the source. The table, the
|
||||
reserved `subscribe`/`unsubscribe` verbs and the fan-out are the **service
|
||||
harness's** (`service.Subscribers`), shared with input and the device manager, so
|
||||
the acpi service's own code is the ACPI half only — and a subscriber that dies is
|
||||
now swept on its exit notification, where before this service had no sweep at
|
||||
all. **The kind is the packet's operation** — one declared event per named kind, exactly as the
|
||||
input service delivers one per device class — so a subscriber reads *what
|
||||
happened* out of the header rather than out of a tag inside the payload. The
|
||||
vocabulary is hardware-neutral:
|
||||
@@ -69,7 +73,10 @@ sequence over everything else. The acpi service implements this as a **soft
|
||||
gate** — it honors `shutdown` only from a process that is a *subscriber*, and
|
||||
init is the one subscriber. That stands in for "only the system supervisor may
|
||||
power off" without hard-coding a pid, so it still holds under tests where PID 1
|
||||
is not init.
|
||||
is not init. The question is asked of the harness's table now
|
||||
(`Subscribers.has(sender)`), which is why the harness exposes it: the gate is
|
||||
unchanged, including the badge being the whole of it — the badge is
|
||||
kernel-stamped, so nothing inside a packet can claim to be init.
|
||||
|
||||
## Orderly shutdown
|
||||
|
||||
|
||||
Reference in New Issue
Block a user