ocarina/core/idle.c
Anna Schumaker 779969f28b core/idle: Let tests run without the thread pool
The thread pool is used to fetch album art in the background, but this
can slow down most tests that aren't interested in album art.  Adding a
(testing-only) function for running without the thread pool speeds
things up a bit.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-07-28 16:17:43 -04:00

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;
}