mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 19:19:58 -04:00
Check that an arm keeps its region marked while a range in flight there ends, which the review found untested.
memory.c mem_lazy_arm marks the region it protects in lz_arm_r, so that lazy_flags_locked keeps lzr set when a release's flight in the same region ends during the arm's clean test. Without that mark the flight's end cleared lzr, lazy_fault let a read of the arming range go, and access_fault passed it to the crash handler. All 20 scenarios of tests/lazy_fetch_check.py passed with the mark taken out. The new arm_flight scenario has a release fetch one range for 100 ms, an arm of another range of the region wait 400 ms in its clean test, and a read of that range fault after the flight ended: it passes, and exits with an access violation when lazy_flags_locked ignores lz_arm_r. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -692,7 +692,8 @@ A change to the lazy write-back's arms, faults, releases or fetches (`runtime/me
|
||||
in flight", `runtime/vk_memory.c` `lazy_fetch`, `mirror_evict`, `hot_check`) passes `python tests\lazy_fetch_check.py`,
|
||||
which builds memory.c with the Windows fault handler and a fetch that only waits, and runs each scenario as its own
|
||||
process, so an access violation fails it. A thread that reads a range over and over while it is armed and given back
|
||||
again never reaches the crash handler, also when the arm's clean test takes 100 ms. A fetch holds up nothing but the
|
||||
again never reaches the crash handler, also when the arm's clean test takes 100 ms, and a read of a range being armed
|
||||
does not either when a range in flight in its region ends during that test. A fetch holds up nothing but the
|
||||
touches of its range: freezes, thaws, arms, releases and copies of other ranges return at once meanwhile, two ranges
|
||||
fetch at once, and more touching threads than the flight table holds all end. The touches of a range in flight wait
|
||||
for it and run again, a write among them without releasing the region's other ranges; thaws, mapping changes,
|
||||
|
||||
@@ -152,6 +152,9 @@ static void releaser(void *arg) {
|
||||
mem_lazy_release((const uint64_t (*)[3])rel_rg, 1);
|
||||
__atomic_store_n(&rel_done, 1, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
// the completion thread's arm (vk_memory.c vk_gpu_written_back) of 64 KiB at arg, written back from buffer 1
|
||||
static volatile uint64_t arm_n;
|
||||
static void armer(void *arg) { arm_n = arm_buf((uint64_t)(uintptr_t)arg, 0x10000, 1); }
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
@@ -360,6 +363,26 @@ int main(int argc, char **argv) {
|
||||
plat_thread_join(tr);
|
||||
CHECK(page_rw(s) && !lzr[r], "the range in flight was not given back");
|
||||
CHECK(arm_buf(s, K64, 1) == K64 && armed(s, K64), "the range was not armed again after its flight");
|
||||
} else if (!strcmp(what, "arm_flight")) {
|
||||
// A range in flight (a release, so no hold) in region r ends while an arm of another range in r is in its
|
||||
// clean test: the region keeps its mark (memory.c lz_arm_r), so a read of the arming range that faults after
|
||||
// that end waits for the arm instead of reaching the crash handler.
|
||||
uint64_t R = heap + 120 * M, s1 = R, s2 = R + M;
|
||||
CHECK(arm_buf(s1, K64, 1) == K64 && stale(s1, K64, 1) == 1, "arm s1");
|
||||
fetch_ns = 100000000ull;
|
||||
rel_rg[0][0] = s1, rel_rg[0][1] = s1 + K64, rel_rg[0][2] = 0;
|
||||
void *tr = plat_thread_new(releaser, NULL, "releaser");
|
||||
wait_fetch();
|
||||
clean_ns = 400000000ull;
|
||||
void *tc = plat_thread_new(armer, (void *)(uintptr_t)s2, "armer");
|
||||
while (!__atomic_load_n(&rel_done, __ATOMIC_SEQ_CST)) plat_wait_ns(1000000);
|
||||
plat_wait_ns(30000000); // the flight has ended; the arm is in its clean test
|
||||
Touch b;
|
||||
void *tb = touch(&b, s2 + 0x10, 0);
|
||||
plat_thread_join(tr);
|
||||
plat_thread_join(tc);
|
||||
plat_thread_join(tb);
|
||||
CHECK(arm_n == K64 && b.done, "armed %llu, read done %d", (unsigned long long)arm_n, b.done);
|
||||
} else if (!strcmp(what, "foreign")) {
|
||||
// a write by the replay to a range armed for another buffer (a mirror gone since) gives it back without a
|
||||
// fetch: that buffer may be gone
|
||||
|
||||
@@ -33,6 +33,7 @@ SCENARIOS = {
|
||||
'release': ('release', {}),
|
||||
'release_join': ('release_join', {}),
|
||||
'arm_busy': ('arm_busy', {}),
|
||||
'arm_flight': ('arm_flight', {}),
|
||||
'foreign': ('foreign', {}),
|
||||
'chunk': ('chunk', CHUNK),
|
||||
'locked': ('locked', LOCKED),
|
||||
|
||||
Reference in New Issue
Block a user