From 12c8bfcc7d33e8f39afe845bc47f53414d0be5f9 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 17 Sep 2026 00:25:59 +0200 Subject: [PATCH] Let the prohibition on a late call stand on its own MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Section 4 forbade any host call that begins after `cultmesh_quic_runtime_close` starts, and promised in the same sentence that such a call is refused with -1; section 6 repeated the promise for `cultmesh_quic_next_event`. The refusal lives behind the runtime's own gate, so once the close has returned there is nothing left to read it: the case the sentence describes is exactly the case where the promise cannot hold. The prohibition stands alone. The refusal is stated for what it is — a call that races the start of a close, while the close is still running, is refused and touches nothing — and no longer as a guarantee covering the call the section forbids. Co-Authored-By: Claude Opus 5 --- .../include/cultmesh_quic_native.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/native/GameCult.Mesh.Quic.Native/include/cultmesh_quic_native.h b/native/GameCult.Mesh.Quic.Native/include/cultmesh_quic_native.h index 4715e266..bf30d7eb 100644 --- a/native/GameCult.Mesh.Quic.Native/include/cultmesh_quic_native.h +++ b/native/GameCult.Mesh.Quic.Native/include/cultmesh_quic_native.h @@ -198,10 +198,12 @@ enum cultmesh_quic_stream_kind { * `cultmesh_quic_runtime_close` quiesces before it tears anything down. It marks * the runtime closing, wakes every blocked `cultmesh_quic_next_event`, and waits * for every in-flight export to return before it closes a handle or frees a - * byte. No host call may begin after `cultmesh_quic_runtime_close` starts: a - * call that arrives during or after it is refused with -1 and touches nothing. - * The host is responsible for that ordering; the refusal is a guard rail, not a - * licence to race. + * byte. No host call may begin after `cultmesh_quic_runtime_close` starts. That + * ordering is the host's, and it is a prohibition rather than a race the bridge + * arbitrates: once the close returns, the handle names freed memory, and a call + * made with it has nothing left to refuse it. A call that races the start of the + * close, while it is still running, is refused with -1 and touches nothing; that + * narrows one mis-ordering and does not make the prohibition optional. * --------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------- @@ -280,8 +282,9 @@ CULTMESH_QUIC_API void cultmesh_quic_stream_shutdown( /* The one blocking crossing. * * 0 nothing within `timeout_ms`. A poller already blocked here when - * `cultmesh_quic_runtime_close` starts is woken and returns 0; one that - * arrives after it starts is refused with -1 like any other call. + * `cultmesh_quic_runtime_close` starts is woken and returns 0. A poll that + * begins after the close starts is forbidden by section 4, and is not a + * case this return code covers. * 1 `*out_event` filled and up to `payload_capacity` payload bytes copied; * `*out_required` is the payload size * 2 `payload_capacity` is too small. Nothing is consumed and nothing is