diff --git a/src/main.c b/src/main.c index af0a6f4..757d270 100644 --- a/src/main.c +++ b/src/main.c @@ -94,19 +94,20 @@ void simulation_draw(struct Simulation *sim) DrawRectangle(x * CELL_WIDTH, y * CELL_WIDTH, CELL_WIDTH, CELL_WIDTH, color); - if (i == sim->p1) - { - DrawRectangleLines(x * CELL_WIDTH, y * CELL_WIDTH, CELL_WIDTH, CELL_WIDTH, - BLUE); - } - if (i == sim->p1) - { - DrawRectangleLines(x * CELL_WIDTH, y * CELL_WIDTH, CELL_WIDTH, CELL_WIDTH, - RED); - } - sv = sv_chop_left(sv, 64); } + + for (u64 i = 0; i < THREAD_POOL; ++i) + { + u64 p1 = sim->states[i].p1; + u64 p2 = sim->states[i].p2; + DrawRectangleLines((p1 / GRID_WIDTH) * CELL_WIDTH, + (p1 % GRID_WIDTH) * CELL_WIDTH, CELL_WIDTH, CELL_WIDTH, + BLUE); + DrawRectangleLines((p2 / GRID_WIDTH) * CELL_WIDTH, + (p2 % GRID_WIDTH) * CELL_WIDTH, CELL_WIDTH, CELL_WIDTH, + RED); + } } int main(void) @@ -114,16 +115,15 @@ int main(void) srand(time(NULL)); struct Simulation sim = {0}; - simulation_init(&sim); + simulation_start(&sim); - bool paused = false; InitWindow(WIDTH, HEIGHT, "CompLife"); SetTargetFPS(60); for (size_t ticks = 0; !WindowShouldClose(); ++ticks) { if (IsKeyPressed(KEY_SPACE)) { - paused = !paused; + sim.paused = !sim.paused; } if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) { @@ -143,15 +143,12 @@ int main(void) } printf("\n"); } - if (!paused) - { - simulation_update(&sim); - } BeginDrawing(); ClearBackground(BLACK); simulation_draw(&sim); EndDrawing(); } + simulation_stop(&sim); CloseWindow(); return 0; } diff --git a/src/simulation.c b/src/simulation.c index 5343b8e..ae4774a 100644 --- a/src/simulation.c +++ b/src/simulation.c @@ -5,38 +5,103 @@ */ #include +#include #include "simulation.h" -void simulation_init(struct Simulation *sim) +bool any_threads_using(const struct ThreadState *const states, u64 n) +{ + for (u64 i = 0; i < THREAD_POOL; ++i) + { + if (states[i].p1 == n || states[i].p2 == n) + { + return true; + } + } + return false; +} + +void thread_pick(struct ThreadState *state) +{ + struct Simulation *sim = state->sim; + while (true) + { + u64 p1 = rand() % (SIMULATION_SIZE / SIZEOF_PROGRAM); + if (any_threads_using(sim->states, p1)) + { + continue; + } + u64 p2 = rand() % (SIMULATION_SIZE / SIZEOF_PROGRAM); + while (p1 * 8 <= ((p2 * 8) + SIZEOF_PROGRAM) && + p2 * 8 <= ((p1 * 8) + SIZEOF_PROGRAM)) + { + p2 = rand() % (SIMULATION_SIZE / SIZEOF_PROGRAM); + } + if (any_threads_using(sim->states, p2)) + { + continue; + } + state->p1 = p1; + state->p2 = p2; + break; + } +} + +const struct timespec THREAD_DEFAULT_SLEEP = {.tv_sec = 1}; + +int thread_update(void *rawptr) +{ + struct ThreadState *state = rawptr; + struct Simulation *simulation = state->sim; + + while (!simulation->stopped) + { + while (simulation->paused) + { + thrd_sleep(&THREAD_DEFAULT_SLEEP, NULL); + } + + // We only need to lock when picking the programs + mtx_lock(&simulation->mutex); + thread_pick(state); + mtx_unlock(&simulation->mutex); + + sv_t a = SV(simulation->buffer + (state->p1 * SIZEOF_PROGRAM), 64); + sv_t b = SV(simulation->buffer + (state->p2 * SIZEOF_PROGRAM), 64); + + struct ProgramConcat prog_concat = {0}; + program_concat(&prog_concat, a, b); + program_execute(&prog_concat); + program_split(&prog_concat); + } + return 0; +} + +void simulation_start(struct Simulation *sim) { for (u64 i = 0; i < SIMULATION_SIZE / sizeof(u16); ++i) { ((u16 *)(sim->buffer))[i] = rand() % UINT16_MAX; } -} -void simulation_pick(struct Simulation *sim) -{ - sim->p1 = rand() % (SIMULATION_SIZE / SIZEOF_PROGRAM); - sim->p2 = rand() % (SIMULATION_SIZE / SIZEOF_PROGRAM); - while (sim->p1 * 8 <= ((sim->p2 * 8) + SIZEOF_PROGRAM) && - sim->p2 * 8 <= ((sim->p1 * 8) + SIZEOF_PROGRAM)) + sim->stopped = false; + sim->paused = true; + mtx_init(&sim->mutex, mtx_plain); + for (u64 i = 0; i < THREAD_POOL; ++i) { - sim->p2 = rand() % (SIMULATION_SIZE / SIZEOF_PROGRAM); + memset(&sim->states[i], 0, sizeof(sim->states[i])); + sim->states[i].sim = sim; + thrd_create(&sim->threads[i], thread_update, &sim->states[i]); } } -void simulation_update(struct Simulation *sim) +void simulation_stop(struct Simulation *sim) { - simulation_pick(sim); - sv_t a = SV(sim->buffer + (sim->p1 * SIZEOF_PROGRAM), 64); - sv_t b = SV(sim->buffer + (sim->p2 * SIZEOF_PROGRAM), 64); - - struct ProgramConcat prog_concat = {0}; - program_concat(&prog_concat, a, b); - program_execute(&prog_concat); - program_split(&prog_concat); + sim->stopped = true; + for (u64 i = 0; i < THREAD_POOL; ++i) + { + thrd_join(sim->threads[i], NULL); + } } /* Copyright (C) 2026 Aryadev Chavali diff --git a/src/simulation.h b/src/simulation.h index 89d7da7..16e46cd 100644 --- a/src/simulation.h +++ b/src/simulation.h @@ -9,21 +9,35 @@ #define SIMULATION_H #include "program_iter.h" +#include +#include #define NUM_PROGRAMS_POW_2 10 #define NUM_PROGRAMS (1LU << NUM_PROGRAMS_POW_2) #define SIMULATION_SIZE (SIZEOF_PROGRAM * NUM_PROGRAMS) +#define THREAD_POOL 8 + +struct ThreadState +{ + u64 p1, p2; + void *sim; +}; + // Simulation is simply a massive tape. We pick two 64 byte portions of this // buffer for our update procedure, which is based on program_iter. struct Simulation { char buffer[SIMULATION_SIZE]; - u64 p1, p2; + + bool paused, stopped; + mtx_t mutex; + thrd_t threads[THREAD_POOL]; + struct ThreadState states[THREAD_POOL]; }; -void simulation_init(struct Simulation *sim); -void simulation_update(struct Simulation *sim); +void simulation_start(struct Simulation *sim); +void simulation_stop(struct Simulation *sim); #endif