[Testing] mcrfpy.lock() / FrameLock has near-zero coverage — stress, fuzz, and soak the #219 barrier #395
Labels
No labels
Alpha Release Requirement
Bugfix
Demo Target
Documentation
Major Feature
Minor Feature
priority:tier1-active
priority:tier2-foundation
priority:tier3-future
priority:tier4-deferred
Refactoring & Cleanup
system:animation
system:documentation
system:grid
system:input
system:performance
system:procgen
system:python-binding
system:rendering
system:ui-hierarchy
Tiny Feature
workflow:blocked
workflow:needs-benchmark
workflow:needs-documentation
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
john/McRogueFace#395
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
The
#219thread-synchronization path is well-designed but effectively untested.grep -rl "mcrfpy.lock" tests/returns exactly one file —tests/fuzz/fuzz_property_types.py— and that reference is incidental, not a test of the barrier itself.The implementation under test:
src/PyLock.cpp— themcrfpy._LockContextcontext manager;__enter__no-ops on the main thread viaisMainThread()(PyLock.cpp:72-76), otherwise blocks inFrameLock::acquire()src/GameEngine.cpp:28-45—FrameLock::acquire()/release(), waiting on a condvar with the GIL releasedsrc/GameEngine.cpp:508-516— the safe window: afterdisplay(), before the next frame's processing,openWindow()then a GIL-releasedcloseWindow()that blocks the main thread until every lock holder completesThat last property is the one that needs evidence. The render thread's frame time is a direct function of how long background handlers hold the lock, and nothing currently measures or bounds that.
Why now
This stops being theoretical the moment a background thread services a real event stream — an in-process NATS/asyncio client mutating entities under
mcrfpy.lock()while the grid renders live (#55, #154, #156). That is a far heavier use than anything the suite exercises: a handler on every inbound event, sustained for hours, against a render loop that must stay smooth. If the barrier has a rare deadlock, a starvation case, or an unbounded-hold failure mode, it will surface there as "the engine is slow" rather than as a test failure.What to cover
Correctness
__enter__is a genuine no-op — same code path works from a timer callback, script init, and a background threadwithblock releases the lock and propagates (__exit__returnsFalse,PyLock.cpp:87-96)PyLock.cpp:56-62) — construct a holder and drop it without__exit__activeis a plain counter and re-entry is not obviously handledStress / soak
Fuzz
#312crash-corpus workflow is the right vehicle; the entity collection andPythonObjectCacheidentity-pin paths (#266/#373) are the interesting targets, since they were designed single-threadedDocumentation deliverable
The two usage rules should end up written down somewhere durable, because both fail silently rather than loudly:
await, no network calls —closeWindow()blocks the render thread until all holders finish, so a slow handler is indistinguishable from engine stutter.Notes
Free-threading (
#336) is explicitly not in scope here — this is the GIL-holding model, which is the correct one for an I/O-bound background thread.#220(subinterpreters) is likewise separate.Blocks
Prerequisite for using McRogueFace as a live simulation environment driven by an external event bus (#55, #154). Along with #394, should land before that work starts.
runtimeis wall clock #396