Skip to content

Report whether an interrupt was enqueued, and stop implying a forceful kill - #1846

Open
dg1sbg wants to merge 1 commit into
clasp-developers:mainfrom
dg1sbg:fix/interrupt-return-value
Open

Report whether an interrupt was enqueued, and stop implying a forceful kill#1846
dg1sbg wants to merge 1 commit into
clasp-developers:mainfrom
dg1sbg:fix/interrupt-return-value

Conversation

@dg1sbg

@dg1sbg dg1sbg commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

MP:PROCESS-KILL, MP:PROCESS-CANCEL, MP:INTERRUPT-PROCESS and MP:PROCESS-SUSPEND all answer NIL whether or not they did anything, because Process_O::interrupt returns void. The information exists and is thrown away:

case Exited: return; // we were too slow! oh well, who cares.

The caller does care. NIL currently means both "enqueued on a live process" and "the process was already gone", so the return value carries no information at all.

That is not hypothetical. A bug report reached me reasoning from exactly this — "MP:PROCESS-KILL and MP:INTERRUPT-PROCESS both answer NIL" — and concluded cancellation was broken. It wasn't; NIL is simply what success looks like too. The real defect was elsewhere, and the misleading return value is what pointed at the wrong function.

What changes

Process_O::interrupt returns true when the interrupt was enqueued on a live process and false when the process had exited and the interrupt was discarded. It propagates through MP:ENQUEUE-INTERRUPT and MP:INTERRUPT to all four entry points, each of which is a one-liner returning the next.

                      live process   exited process
  before                   NIL             NIL
  after                    T               NIL

What the docstrings now say

The four functions had no docstrings. They now state the limit the old behaviour hid: a true value does not mean the process died. Delivery is asynchronous and lands at a safepoint, so a process that reaches none may never stop, and PROCESS-ACTIVE-P / PROCESS-JOIN are how you find out whether it did.

On the FIXME

PROCESS-KILL and PROCESS-CANCEL remain the same request, and I have removed the FIXME proposing that KILL become "the more chaotic SIGKILL version" rather than leaving it standing.

There is no safe forceful thread kill in a garbage-collected runtime: terminating a thread asynchronously abandons whatever locks and heap invariants it held. SBCL's TERMINATE-THREAD is cooperative for the same reason. If you would rather keep the FIXME as an open question I will restore it — but an open FIXME implying the option is coming seems worse than documenting that the two are synonyms and why.

Also

A stray unbalanced " was leaking into MP:ENQUEUE-INTERRUPT's docstring. MP:FENCE has the same defect at mpPackage.cc:598, not touched here.

Testing

Three tests: true when enqueued on a live process, false for an already-exited one, and the same for PROCESS-CANCEL. The live-process test blocks in SLEEP rather than spinning, so it does not depend on a loop being cancellable and cannot leave a thread burning a core.

Regression suite 2026 → 2029 on macOS arm64, boehmprecise, with the same expected failures by name. Verified as a behaviour change against a build without the patch, where both cases still answer NIL.

…l kill

MP:PROCESS-KILL, MP:PROCESS-CANCEL, MP:INTERRUPT-PROCESS and MP:PROCESS-SUSPEND
all answered NIL whether or not they did anything, because Process_O::interrupt
returned void. The information existed and was discarded:

    case Exited: return; // we were too slow! oh well, who cares.

The caller does care: NIL meant both "enqueued on a live process" and "the
process was already gone". A bug report reasoning from that return value
concluded cancellation was broken when the value simply carried no information.

Process_O::interrupt now returns true when the interrupt was enqueued on a live
process and false when the process had exited and it was discarded. The value
propagates through MP:ENQUEUE-INTERRUPT and MP:INTERRUPT to all four entry
points, each of which is a one-liner returning the next.

The docstrings now state the limit the old ones did not: a true value does NOT
mean the process died. Delivery is asynchronous and lands at a safepoint, so a
process that reaches none -- a loop with no back-edge polling, or a foreign call
made without parking -- may not stop at all. PROCESS-ACTIVE-P and PROCESS-JOIN
are how you learn whether it did.

PROCESS-KILL and PROCESS-CANCEL remain the same request, and the FIXME proposing
that KILL become "the more chaotic SIGKILL version" is removed rather than left
standing. There is no safe forceful thread kill in a garbage-collected runtime:
terminating a thread asynchronously abandons whatever locks and heap invariants
it held. SBCL's TERMINATE-THREAD is cooperative for the same reason. Saying so is
better than an open FIXME implying the option is coming.

Also fixes a stray unbalanced quote leaking into MP:ENQUEUE-INTERRUPT's
docstring, the same defect MP:FENCE has.

Regression suite 2026 -> 2029.
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