ocarina/core/idle.c

112 lines
2.1 KiB
C

/*
* Copyright 2013 (c) Anna Schumaker.
*/
#include <core/idle.h>
#include <glib.h>
struct idle_task {
bool (*idle_func)(void *);
void *idle_data;
};
static GThreadPool *idle_pool = NULL;
static GQueue idle_queue = G_QUEUE_INIT;
static enum idle_sync_t idle_mode = IDLE_SYNC;
static unsigned int queued = 0;
static unsigned int serviced = 0;
void __idle_free_task(struct idle_task *task)
{
g_free(task);
g_atomic_int_inc(&serviced);
}
bool __idle_run_task(struct idle_task *task)
{
bool finished = task->idle_func(task->idle_data);
if (finished)
__idle_free_task(task);
return finished;
}
void __idle_thread(gpointer task, gpointer data)
{
if (!__idle_run_task(task))
g_thread_pool_push(idle_pool, task, NULL);
}
void idle_init(enum idle_sync_t sync)
{
idle_mode = sync;
}
void idle_deinit()
{
struct idle_task *task;
while (!g_queue_is_empty(&idle_queue)) {
task = g_queue_pop_head(&idle_queue);
g_free(task);
}
if (idle_pool) {
g_thread_pool_free(idle_pool, true, true);
idle_pool = NULL;
}
queued = 0;
serviced = 0;
}
void idle_schedule(enum idle_sync_t sync, bool (*func)(void *), void *data)
{
struct idle_task *task;
if (sync == IDLE_ASYNC && idle_mode == IDLE_SYNC)
return;
task = g_malloc(sizeof(struct idle_task));
task->idle_func = func;
task->idle_data = data;
if (sync == IDLE_SYNC)
g_queue_push_tail(&idle_queue, task);
else {
if (!idle_pool)
idle_pool = g_thread_pool_new(__idle_thread, NULL, 1,
false, NULL);
g_thread_pool_push(idle_pool, task, NULL);
}
g_atomic_int_inc(&queued);
}
bool idle_run_task()
{
struct idle_task *task;
if (!g_queue_is_empty(&idle_queue)) {
task = g_queue_pop_head(&idle_queue);
if (!__idle_run_task(task))
g_queue_push_tail(&idle_queue, task);
}
if (g_atomic_int_get(&queued) != g_atomic_int_get(&serviced))
return true;
queued = 0;
serviced = 0;
return false;
}
float idle_progress()
{
if (g_atomic_int_get(&serviced) == 0 &&
g_atomic_int_get(&queued) == 0)
return 1.0;
return (float)g_atomic_int_get(&serviced) / (float)queued;
}