ocarina/core/idle.c

109 lines
2.0 KiB
C

/*
* Copyright 2013 (c) Anna Schumaker.
*/
#include <core/idle.h>
#include <glib.h>
struct idle_task {
bool (*idle_func)(void *);
void *idle_data;
enum idle_sync_t idle_sync;
};
static GThreadPool *idle_pool = NULL;
static GQueue idle_queue = G_QUEUE_INIT;
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()
{
idle_pool = g_thread_pool_new(__idle_thread, NULL, 1, true, NULL);
}
#ifdef CONFIG_TESTING
void idle_init_sync()
{
}
#endif /* CONFIG_TESTING */
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, false);
queued = 0;
serviced = 0;
}
void idle_schedule(enum idle_sync_t sync, bool (*func)(void *), void *data)
{
struct idle_task *task = g_malloc(sizeof(struct idle_task));
task->idle_func = func;
task->idle_data = data;
task->idle_sync = sync;
g_queue_push_tail(&idle_queue, task);
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 (task->idle_sync == IDLE_ASYNC) {
if (idle_pool)
g_thread_pool_push(idle_pool, task, NULL);
else
__idle_free_task(task);
} else 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;
}