Skip to content

Inherit host hooks when creating Lua threads and coroutines - #355

Merged
akeit0 merged 1 commit into
mainfrom
codex/coroutine-host-hook-inheritance
Oct 10, 2026
Merged

akeit0 merged 1 commit into
mainfrom
codex/coroutine-host-hook-inheritance

Conversation

@akeit0

@akeit0 akeit0 commented Oct 10, 2026

Copy link
Copy Markdown
Collaborator

Installing a host count hook on a parent left loops in its child coroutines unmonitored. Copy host hook settings when creating a thread/coroutine through either C# or Lua, so a child's instructions invoke the same callback with that child's execution context.

The inheritance contract follows native Lua's creation-time snapshot:

  • Copy callback, mask, and base interval from the creating thread, including nested coroutine creation.
  • Start a fresh instruction counter and independent hook suppression state.
  • Parent/child replacement or removal is independent; existing children are not updated retroactively.
  • Track installation through Lua debug.sethook separately: its callback stays thread-local. Children inherit observable mask/count metadata without dispatching the parent's Lua callback.

Native C probes compiled from official Lua 5.2.4 and 5.4.9 confirmed callback inheritance, fresh counters, independent replacement/removal, and Lua callback/metadata behavior through grandchildren. Relevant source: 5.2 lua_newthread, 5.2 hookf, 5.4 lua_newthread, 5.4 hookf.

Document the shared callback/context.State contract and sandbox limits in both READMEs and API/source comments. A hook must be installed before children are created or explicitly set on existing children. Exposed debug.sethook can still remove it; LuaRuntimeException can still be caught by pcall/protected coroutine.resume. This is inherited instrumentation, not an uncatchable VM-wide execution budget.

Validation:

  • 24 new coroutine-hook cases pass; unchanged main fails 23 of these (the existing explicit per-child Lua-hook case passes).
  • All 488 runtime cases excluding ExpectedFailure and 69 Source Generator cases pass.
  • All four runtime Release targets build with zero warnings/errors; CSharpier checks 250 files; git diff --check passes.
  • Synchronous/asynchronous count/line/call/return callbacks, all four creation routes, grandchildren, yield/resume, fresh counters, independent overrides/removal, budget aborts and cancellation propagation are covered. No Unity execution was needed for this runtime-only change.

BenchmarkDotNet ShortRun, .NET 8.0.31 CoreCLR, main a2c3934 versus this change:

Workload main change Allocation
CreateThread without hook 123.2 ns 120.7 ns 688 B on both
CreateCoroutine without hook 122.2 ns 122.0 ns 864 B on both
Precompiled 200,000-iteration child loop without hook 0.945 ms 0.937 ms approximately 864 B
Same child loop, explicit empty hook at count=4 2.788 ms 2.778 ms approximately 868 B

These short measurements show no material regression for equal monitoring; they do not establish a general speedup. Newly inherited monitoring necessarily adds the existing hook-dispatch cost to previously unmonitored children (about 3x for this count=4 loop). The per-instruction VM dispatch is unchanged.

Refs #338; lightweight delegate/budget APIs remain deferred.

@akeit0
akeit0 merged commit 5ec0ad1 into main Oct 10, 2026
2 checks passed
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