#include "twn_util.h" #include "twn_workers_c.h" #include "rendering/twn_draw_c.h" SDL_sem *workers_job_semaphore; static SDL_Thread *workers_pool[MAX_WORKERS]; static size_t workers_pool_size; static SDL_mutex *workers_mutex; static bool workers_should_exit; /* 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; if (model_load_workers_thread()) continue; } 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); workers_mutex = SDL_CreateMutex(); return true; } void workers_deinit(void) { SDL_LockMutex(workers_mutex); workers_should_exit = true; SDL_UnlockMutex(workers_mutex); /* TODO: that's not correct */ SDL_DestroyMutex(workers_mutex); SDL_DestroySemaphore(workers_job_semaphore); workers_pool_size = 0; }