mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 19:19:58 -04:00
Check that a thaw fetches the armed ranges of its regions without the freeze lock, which the review found untested.
memory.c mem_thaw calls lazy_release_regions before it takes frz_lock, so the copy a file read's thaw needs (the buffer's armed ranges with stale bytes) no longer holds up the other threads' faults, freezes, thaws and arms. All 20 scenarios of tests/lazy_fetch_check.py passed with that call taken out: the thaw scenario reaches the same end state through thaw_begin_locked's lazy_drop_region_locked under the lock. The new thaw_unlocked scenario has a thread thaw a page of a range armed with stale bytes while the fetch takes 300 ms, and freezes another region meanwhile: the freeze returns at once, and took 300 ms with the call taken out. locked_thaw runs it with NX2NAVI_WB_LAZY_UNLOCKED=0, where the freeze waits for the fetch as in 0.10.1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -694,8 +694,9 @@ which builds memory.c with the Windows fault handler and a fetch that only waits
|
||||
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, 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
|
||||
touches of its range: freezes, thaws, arms, releases and copies of other ranges return at once meanwhile, also while
|
||||
a thaw fetches the armed ranges of its own regions, 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,
|
||||
releases of its buffer, arms and freezes see it. The same with `wb_lazy_chunk = 1`, and with `wb_lazy_unlocked = 0`
|
||||
the fetch holds the freeze lock again. The "mem: lazy write-back" lines give the longest fetch, the longest wait of a
|
||||
|
||||
@@ -155,6 +155,8 @@ static void releaser(void *arg) {
|
||||
// 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); }
|
||||
// a file read's thaw of the page at arg (fs_host.c, romfs.c: before the kernel writes the buffer)
|
||||
static void thawer(void *arg) { mem_thaw((uint64_t)(uintptr_t)arg, 0x1000); }
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
@@ -292,6 +294,21 @@ int main(int argc, char **argv) {
|
||||
CHECK(page_rw(s + 0x1000), "the page is not read-write after the thaw");
|
||||
plat_thread_join(ta);
|
||||
CHECK(fetch_calls == 1, "%d fetches", fetch_calls);
|
||||
} else if (!strcmp(what, "thaw_unlocked")) {
|
||||
// A thaw (a file read into a buffer) of a range armed with stale bytes fetches them before it takes frz_lock
|
||||
// (memory.c lazy_release_regions): a freeze of another region meanwhile does not wait for the copy. With
|
||||
// NX2NAVI_WB_LAZY_UNLOCKED=0 the thaw fetches under the lock, and the freeze waits.
|
||||
uint64_t s = heap + 124 * M, frz_at = heap + 16 * M;
|
||||
CHECK(arm_buf(s, K64, 1) == K64 && stale(s, K64, 1) == 1, "arm");
|
||||
void *th = plat_thread_new(thawer, (void *)(uintptr_t)(s + 0x1000), "thawer");
|
||||
wait_fetch();
|
||||
uint64_t t0 = plat_now_ns();
|
||||
int f = mem_freeze(frz_at);
|
||||
double d = ms(t0);
|
||||
if (lz_unlocked) CHECK(d < 50 && f == 1, "mem_freeze during the thaw's fetch took %.1f ms", d);
|
||||
else CHECK(d > 200, "mem_freeze took %.1f ms, not the fetch's time", d);
|
||||
plat_thread_join(th);
|
||||
CHECK(fetch_calls == 1 && page_rw(s) && !armed(s, K64), "%d fetches, pages %d", fetch_calls, page_rw(s));
|
||||
} else if (!strcmp(what, "mapping")) {
|
||||
// a mapping change (a commit, decommit or protect: thaw_range_locked under frz_lock) in a region with a range
|
||||
// in flight and another armed: the armed one is fetched under the lock, the flight ends first, both given back
|
||||
|
||||
@@ -29,6 +29,8 @@ SCENARIOS = {
|
||||
'loser': ('loser', {}),
|
||||
'concurrent': ('concurrent', {}),
|
||||
'thaw': ('thaw', {}),
|
||||
'thaw_unlocked': ('thaw_unlocked', {}),
|
||||
'locked_thaw': ('thaw_unlocked', LOCKED),
|
||||
'mapping': ('mapping', {}),
|
||||
'release': ('release', {}),
|
||||
'release_join': ('release_join', {}),
|
||||
|
||||
Reference in New Issue
Block a user