Skip to content

Take up openkal 0.11's unit: a handle the caller holds, not a flag - #23

Merged
Sunrisepeak merged 5 commits into
mainfrom
spawn-is-one-operation
Aug 30, 2026
Merged

Take up openkal 0.11's unit: a handle the caller holds, not a flag#23
Sunrisepeak merged 5 commits into
mainfrom
spawn-is-one-operation

Conversation

@Sunrisepeak

Copy link
Copy Markdown
Member

The identity is established at the first start --- the first member forms the group and its identifier is reported --- so
nothing has to be remembered and no registry appears. `kal_process_terminate'
is one program again; the unit has its own operations.

…eaches

⭐ THE SAVING IS NOT ONLY IN THE HEADER. This file held THREE bodies of sixty
lines that differed by four: every fix to the shared part --- the exec-report pipe
among them --- had to be made three times, or be made once and be wrong twice.
They are one function now, and the modifiers are positions in `kal_spawn'.

Two of those positions are new work rather than rearrangement:

`work' --- the directory the started program runs in, an `fchdir' in the duplicate
before the replacement. `execveat' takes `base' as a dirfd, but that RESOLVES the
name, and resolving a name is not entering a directory --- which is what the
comment here used to claim and the code never did. ⚠️ A failed `fchdir' does NOT
reach `execveat': running the right program in the wrong directory is precisely
the silent wrongness this exists to remove, so it goes back through the pipe an
exec failure uses.

`KAL_SPAWN_OWN_JOB' --- `setpgid(0, 0)' in the duplicate, asked for there and not
from the parent, whose own call races the replacement and loses.

⭐ AND `kal_process_terminate' NOW REACHES THE WHOLE JOB, WITHOUT THE HANDLE
CARRYING ANY STATE TO SAY SO. A program that formed its own job has a group
identifier equal to its own pid; one that did not inherited this
implementation's, which is some other process. `getpgid(pid) == pid'
distinguishes them exactly. ⚠️ Without this half the flag would do nothing a
caller could see --- forming the job matters only because terminating then reaches
what the started program itself started.

Conformance against openkal 0.11: 140 held, 0 did not hold.
The identity is established at the first start --- the first member forms the group and its identifier is reported --- so
nothing has to be remembered and no registry appears. `kal_process_terminate'
is one program again; the unit has its own operations.
…t report

`kal_process_job_enter' is `setpgid(0, join)': a program joins a unit or forms
one and learns its identity. It exists because `kal_spawn.job' cannot say it ---
that field places a program the caller STARTS, and a copy wishing to lead a unit
must say so about ITSELF before it replaces itself, which is what every shell and
every runner with a timeout is written as.

⚠️⚠️ `kal_process_job_terminate' NOW USES THE SIGNAL THAT CANNOT BE DECLINED, and
that is a decision. A unit exists because its members include programs the caller
never held a handle to; a request any one of them may ignore does not terminate
the unit, it terminates the part that agreed. Measured with a consumer's own
test: a shell that traps the polite signal and loops outlived every deadline, and
the caller's escalation could not help --- openkal has no vocabulary for "and this
time I mean it". What it costs is stated at the call: a member gets no chance to
clean up, and a caller that wants that still has `kal_process_terminate' upon a
member it holds.

⭐⭐ AND SIGPIPE IS IGNORED AT STARTUP, WHICH IS THE OTHER HALF OF THE SAME IDEA.
openkal defines no signals. `kal_stream_write' is required to REPORT that a
stream's far end has gone --- and this kernel instead delivers SIGPIPE, whose
default action ends the program. So a program that wrote to a closed stream was
not told; it stopped, with a status no operation here produced.

⚠️ A C library above answers `signal(SIGPIPE, SIG_IGN)' and TRUTHFULLY reports
success, because openkal has no signals and there is nothing for it to set. The
program is killed anyway, four layers below the call it made to prevent exactly
that. Measured: a consumer's test exited 141 having printed none of its own
assertions. Ignored here because here is the only place that can; the write then
fails with EPIPE, which is what the interface said would happen all along.

The earlier `getpgid(pid) == pid' trick is gone with the flag it served:
`kal_process_terminate' means one program again, always.
A disposition for the two polite signals, storing a word and waking whoever
waits on it --- both of which are safe to do from one. `kal_task_wait' is what a
caller waits with, so the wake is the raw call rather than the library one.

⚠️ A DISPOSITION AND NOT A WAITING CONTEXT. Consuming these from a context of
its own needs them blocked in EVERY context, and blocking is per-context and
inherited: a program that already had contexts running would have some that
still take the default action, and blocking at startup would make a program that
never asks unkillable. A disposition is per PROGRAM and can be installed at any
moment --- so it is armed on the first enquiry, and a program that never asks is
unaffected.

⚠️ THE RESTORER IS SUPPLIED HERE ON x86_64 AND BY THE KERNEL ON aarch64. Without
SA_RESTORER the return from a handler faults; the C library normally supplies
those three instructions and this implementation has none beneath it.
⚠️ Missed on the first pass because I updated src/ and grepped src/. The tests
call kal_process_spawn too, and CI is what said so.
@Sunrisepeak
Sunrisepeak merged commit 3872aa4 into main Aug 30, 2026
2 checks passed
@Sunrisepeak
Sunrisepeak deleted the spawn-is-one-operation branch August 30, 2026 20:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant