Skip to content

Fix evented exec and long-lived scope waiter retention - #65

Merged
lePereT merged 2 commits into
nextfrom
mem+backend-fixes
Jun 18, 2026
Merged

Fix evented exec and long-lived scope waiter retention#65
lePereT merged 2 commits into
nextfrom
mem+backend-fixes

Conversation

@lePereT

@lePereT lePereT commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

What type of PR is this? (check all applicable)

  • Bug Fix
  • Documentation Update
  • Code Refactor
  • Performance Improvements
  • Test

Description

This PR fixes two backend/runtime issues in lua-fibers and adds regression coverage for both.

First, it fixes unbounded memory growth in long-lived scopes caused by cancelled one-shot waiters being left as tombstones. Scope-aware blocking operations race their main operation against the scope cancellation/fault one-shots. When the main op wins, the losing one-shot waiter is cancelled. Previously, cancellation cleared the callback but left the waiter record in the one-shot waiter array. Long-lived scopes performing repeated stream operations could therefore accumulate large numbers of cancelled waiter records. This was visible during repeated upload-shaped stream transfers.

Second, it adds an event-driven luaposix process backend for LuaJIT + luaposix. The existing SIGCHLD/self-pipe backend remains appropriate for PUC Lua, but LuaJIT is unsafe with a Lua-level SIGCHLD handler in this path. The new posix_reaper backend keeps the parent scheduler fully evented by using a lightweight reaper process and a sentinel pipe, similar in shape to the existing nixio compromise.

Changes included:

  • Add exec_backend.posix_reaper for LuaJIT + luaposix.

    • Uses parent -> reaper -> child.
    • Reports child completion to the parent over a sentinel pipe.
    • Keeps the parent scheduler event-driven through the existing poller.
    • Avoids LuaJIT signal-handler instability.
  • Update exec backend selection.

    • pidfd remains preferred where available.
    • sigchld remains the PUC Lua luaposix backend.
    • posix_reaper is selected for LuaJIT when using the posix family.
    • nixio remains the nixio-family backend.
  • Fix one-shot cancellation retention.

    • Cancelled one-shot waiters are now physically unlinked rather than left as tombstones.
    • Signalling takes ownership of the waiter array before invoking callbacks, so cancellation during signalling remains safe.
  • Add backend-family cycling tests.

    • Runs relevant I/O tests in separate subprocesses for each backend family.

    • Prevents silent mixed-family fallback.

    • Covers:

      • ffi fd/poller/exec family
      • posix fd/poller/exec family
      • nixio fd/poller/exec family
  • Add one-shot waiter regression coverage.

    • Verifies cancelled one-shot waiters do not accumulate.
  • Add a small upload-shaped regression test to the standard suite.

    • Repeated UNIX-socket to stream to file transfers inside a long-lived scope.
    • Asserts scope cancellation/fault one-shot waiter arrays do not grow.
    • Kept deliberately small by default.

Related Issues, Tickets & Documents

No linked issue.

Relevant context:

  • Long-lived scope memory growth was observed during upload-shaped stream workloads.
  • The issue was traced to cancelled one-shot waiters accumulating on long-lived scope cancellation/fault one-shots.
  • LuaJIT with luaposix SIGCHLD handling was found to be unstable enough to avoid a Lua-level signal callback for process completion.

Screenshots/Recordings

Not applicable. This PR has no visual changes.

Manual test

  • yes

Manual test description

Manually tested with both LuaJIT and PUC Lua.

Commands run:

cd tests
luajit test.lua
lua test.lua

Both complete successfully, including:

  • existing unit tests
  • I/O tests
  • exec tests
  • backend-family subprocess tests
  • one-shot regression tests
  • upload-shaped regression tests
  • scope tests

Added tests?

  • yes

Added tests:

  • backend-family cycling tests
  • one-shot waiter cancellation regression
  • small upload-shaped long-lived-scope regression
  • optional larger upload stress harness

The upload-shaped test can be controlled with:

LUA_FIBERS_UPLOAD_STRESS_MB=4
LUA_FIBERS_UPLOAD_STRESS_REPEAT=3
LUA_FIBERS_SKIP_UPLOAD_STRESS=1

Added to documentation?

  • no documentation needed

README changes are not required for the public API surface.

@lePereT
lePereT merged commit 927ab7d into next Jun 18, 2026
1 check passed
@lePereT
lePereT deleted the mem+backend-fixes branch June 18, 2026 23:09
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