2025-02-07 07:19:36 +00:00
|
|
|
#include "twn_util.h"
|
|
|
|
#include "twn_workers_c.h"
|
|
|
|
#include "rendering/twn_draw_c.h"
|
|
|
|
|
|
|
|
SDL_sem *workers_job_semaphore;
|
|
|
|
|
|
|
|
static size_t workers_pool_size;
|
|
|
|
static SDL_mutex *workers_mutex;
|
|
|
|
static bool workers_should_exit;
|
2025-02-07 10:42:01 +00:00
|
|
|
static SDL_sem *workers_exit_semaphore; /* should come to count of `workers_pool_size` */
|
2025-02-07 07:19:36 +00:00
|
|
|
|
|
|
|
/* logic is such that when job is posted, worker threads attempt to grab it from any possible entry point */
|
|
|
|
/* if it did something, which is signaled by `true` return, go back to waiting on semaphore, so that it's decremented properly */
|
|
|
|
static int worker_thread(void *udata) {
|
|
|
|
(void)udata;
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
/* check whether loop should end */
|
|
|
|
SDL_LockMutex(workers_mutex);
|
|
|
|
if (workers_should_exit) {
|
|
|
|
SDL_UnlockMutex(workers_mutex);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
SDL_UnlockMutex(workers_mutex);
|
|
|
|
|
|
|
|
/* wait and occasionally go back to check whether it all should end */
|
|
|
|
if (SDL_SemWaitTimeout(workers_job_semaphore, 100) == SDL_MUTEX_TIMEDOUT)
|
|
|
|
continue;
|
|
|
|
|
2025-02-09 04:34:16 +00:00
|
|
|
/* process models, which will trigger texture loads */
|
2025-02-14 16:51:34 +00:00
|
|
|
if (models_load_workers_thread())
|
2025-02-07 07:19:36 +00:00
|
|
|
continue;
|
2025-02-09 04:34:16 +00:00
|
|
|
|
|
|
|
if (textures_load_workers_thread())
|
|
|
|
continue;
|
2025-02-07 07:19:36 +00:00
|
|
|
}
|
|
|
|
|
2025-02-07 10:42:01 +00:00
|
|
|
/* let the main thread collect it */
|
|
|
|
SDL_SemPost(workers_exit_semaphore);
|
|
|
|
|
2025-02-07 07:19:36 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* TODO: have a path for platforms without thread support? */
|
|
|
|
/* TODO: limit stack size? */
|
|
|
|
bool workers_init(size_t worker_count) {
|
|
|
|
SDL_assert(workers_pool_size == 0);
|
|
|
|
|
|
|
|
if (worker_count > MAX_WORKERS)
|
|
|
|
worker_count = MAX_WORKERS;
|
|
|
|
|
|
|
|
/* spawn a bunch of detached threads without references to them */
|
|
|
|
for (size_t i = 0; i < worker_count; ++i) {
|
|
|
|
SDL_Thread *thread = SDL_CreateThread(worker_thread, "worker", NULL);
|
|
|
|
SDL_assert_always(thread);
|
|
|
|
SDL_DetachThread(thread);
|
|
|
|
}
|
|
|
|
|
|
|
|
workers_pool_size = worker_count;
|
|
|
|
workers_job_semaphore = SDL_CreateSemaphore(0);
|
2025-02-07 10:42:01 +00:00
|
|
|
workers_exit_semaphore = SDL_CreateSemaphore(0);
|
2025-02-07 07:19:36 +00:00
|
|
|
workers_mutex = SDL_CreateMutex();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void workers_deinit(void) {
|
|
|
|
SDL_LockMutex(workers_mutex);
|
|
|
|
workers_should_exit = true;
|
|
|
|
SDL_UnlockMutex(workers_mutex);
|
|
|
|
|
2025-02-07 10:42:01 +00:00
|
|
|
for (size_t i = 0; i < workers_pool_size; ++i) {
|
|
|
|
SDL_SemWait(workers_exit_semaphore);
|
|
|
|
}
|
|
|
|
|
2025-02-07 07:19:36 +00:00
|
|
|
SDL_DestroyMutex(workers_mutex);
|
|
|
|
SDL_DestroySemaphore(workers_job_semaphore);
|
2025-02-07 10:42:01 +00:00
|
|
|
SDL_DestroySemaphore(workers_exit_semaphore);
|
2025-02-07 07:19:36 +00:00
|
|
|
workers_pool_size = 0;
|
|
|
|
}
|