Bring compute_prebuild_queue_check's stand-ins up to lb_next's worker limit beside the game.

Since cd0b1a38, vk_pipeline.c lb_next calls lb_idle() and stops a boot builder at or above LB.bg_threads while the
builders run beside the game, so the check, which builds lb_next against a stand-in LB, failed to compile ("call to
undeclared function 'lb_idle'", "no member named 'bg_threads'"). The stand-in LB has bg_threads, and lb_idle copies
the real one with a test switch for bf_waiting. The concurrent runs now also cover two background workers and a start
that waits for the whole warm, and the explicit cases check that worker 2 of 2 stops beside the game and goes on in a
preparation. vk_pipeline.c is unchanged.

The check passes again with the ucrt64 clang.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
chrg6
2026-11-13 17:21:48 -05:00
parent 077c363f52
commit fd91f46bfb

View File

@@ -20,8 +20,10 @@ static struct {
volatile int64_t next;
volatile int32_t stop;
size_t n, n_keep;
int idle, tail_one;
int idle, tail_one, bg_threads;
} LB;
static int bf_wait_now, bg_threads = 8; // bf_waiting(): the start waits for the whole warm
static int lb_idle(void) { return LB.idle && !bf_wait_now; }
static volatile LONG seen[2000];
static HANDLE start_event;
'''
@@ -34,13 +36,14 @@ static DWORD WINAPI worker(void *arg) {
size_t i=lb_next(id);
if (i>=LB.n) break;
assert(InterlockedIncrement(&seen[i])==1);
if (LB.idle && LB.tail_one && i>=LB.n_keep) assert(id==0);
if (LB.idle && !bf_wait_now && LB.tail_one && i>=LB.n_keep) assert(id==0);
if (LB.idle && !bf_wait_now) assert(id<LB.bg_threads);
if (i%7==0) SwitchToThread();
}
return 0;
}
static void run(size_t prefix, int automatic, int idle) {
LB.next=0;LB.n=2000;LB.n_keep=prefix;LB.stop=0;LB.tail_one=automatic;LB.idle=idle;
LB.next=0;LB.n=2000;LB.n_keep=prefix;LB.stop=0;LB.tail_one=automatic;LB.idle=idle;LB.bg_threads=bg_threads;
for (int i=0;i<2000;i++) seen[i]=0;
ResetEvent(start_event);
HANDLE threads[8];
@@ -57,13 +60,21 @@ int main(void) {
run(289,1,1);run(0,1,1);run(2000,1,1);run(1,1,1);
run(289,0,1);run(289,1,0);
}
LB.next=289;LB.n_keep=289;LB.tail_one=1;LB.idle=1;
// The boot's builders (idle) beside the game: only the first bg_threads workers go on; while the start waits
// for the whole warm (bf_waiting) every worker does.
bg_threads=2;run(289,1,1);run(0,0,1);bf_wait_now=1;run(289,1,1);bf_wait_now=0;bg_threads=8;
LB.next=289;LB.n_keep=289;LB.tail_one=1;LB.idle=1;LB.bg_threads=8;
assert(lb_next(1)==LB.n && LB.next==289);
assert(lb_next(0)==289);
LB.stop=1;
assert(lb_next(0)==LB.n && LB.next==290);
LB.stop=0;LB.tail_one=0;
assert(lb_next(1)==290);
LB.bg_threads=2;LB.idle=1;
assert(lb_next(2)==LB.n && LB.next==291); // worker 2 of 2 stops beside the game
assert(lb_next(1)==291);
LB.idle=0;
assert(lb_next(2)==292); // and goes on in a preparation (idle 0)
CloseHandle(start_event);
puts("Prebuild queue: concurrent exactly-once coverage, recent/tail boundary, explicit override and stop checks passed");
return 0;