core/idle: Add support for running idle tasks in a new thread
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This commit is contained in:
parent
6a44f9e1a1
commit
6b52775e58
|
@ -6,6 +6,7 @@
|
|||
#include <core/collection.h>
|
||||
#include <core/filter.h>
|
||||
#include <core/history.h>
|
||||
#include <core/idle.h>
|
||||
#include <core/playlist.h>
|
||||
#include <core/tags/tags.h>
|
||||
#include <core/tempq.h>
|
||||
|
@ -13,6 +14,7 @@
|
|||
|
||||
void core_init(int *argc, char ***argv, struct core_init_data *init)
|
||||
{
|
||||
idle_init();
|
||||
filter_init();
|
||||
tags_init();
|
||||
playlist_init(init->playlist_ops);
|
||||
|
@ -31,4 +33,5 @@ void core_deinit()
|
|||
playlist_deinit();
|
||||
tags_deinit();
|
||||
filter_deinit();
|
||||
idle_deinit();
|
||||
}
|
||||
|
|
78
core/idle.c
78
core/idle.c
|
@ -8,21 +8,58 @@
|
|||
struct idle_task {
|
||||
void (*idle_func)(void *);
|
||||
void *idle_data;
|
||||
enum idle_sync_t idle_sync;
|
||||
};
|
||||
|
||||
static GQueue idle_queue = G_QUEUE_INIT;
|
||||
static float queued = 0.0;
|
||||
static float serviced = 0.0;
|
||||
static GThreadPool *idle_pool = NULL;
|
||||
static GQueue idle_queue = G_QUEUE_INIT;
|
||||
static unsigned int queued = 0;
|
||||
static unsigned int serviced = 0;
|
||||
|
||||
|
||||
void __idle_run_task(struct idle_task *task)
|
||||
{
|
||||
task->idle_func(task->idle_data);
|
||||
g_free(task);
|
||||
g_atomic_int_inc(&serviced);
|
||||
}
|
||||
|
||||
void __idle_thread(gpointer task, gpointer data)
|
||||
{
|
||||
__idle_run_task(task);
|
||||
}
|
||||
|
||||
|
||||
void idle_init()
|
||||
{
|
||||
idle_pool = g_thread_pool_new(__idle_thread, NULL, 1, true, NULL);
|
||||
}
|
||||
|
||||
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, void (*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);
|
||||
queued++;
|
||||
g_atomic_int_inc(&queued);
|
||||
}
|
||||
|
||||
bool idle_run_task()
|
||||
|
@ -31,31 +68,24 @@ bool idle_run_task()
|
|||
|
||||
if (!g_queue_is_empty(&idle_queue)) {
|
||||
task = g_queue_pop_head(&idle_queue);
|
||||
task->idle_func(task->idle_data);
|
||||
g_free(task);
|
||||
serviced++;
|
||||
if (task->idle_sync == IDLE_ASYNC)
|
||||
g_thread_pool_push(idle_pool, task, NULL);
|
||||
else
|
||||
__idle_run_task(task);
|
||||
}
|
||||
|
||||
if (g_queue_is_empty(&idle_queue)) {
|
||||
queued = 0.0;
|
||||
serviced = 0.0;
|
||||
}
|
||||
return !g_queue_is_empty(&idle_queue);
|
||||
if (g_atomic_int_get(&queued) != g_atomic_int_get(&serviced))
|
||||
return true;
|
||||
|
||||
queued = 0;
|
||||
serviced = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
float idle_progress()
|
||||
{
|
||||
if (g_queue_is_empty(&idle_queue))
|
||||
if (g_atomic_int_get(&serviced) == 0 &&
|
||||
g_atomic_int_get(&queued) == 0)
|
||||
return 1.0;
|
||||
return serviced / queued;
|
||||
}
|
||||
|
||||
void idle_cancel()
|
||||
{
|
||||
struct idle_task *task;
|
||||
|
||||
while (!g_queue_is_empty(&idle_queue)) {
|
||||
task = g_queue_pop_head(&idle_queue);
|
||||
g_free(task);
|
||||
}
|
||||
return (float)g_atomic_int_get(&serviced) / (float)queued;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ static gboolean __on_idle(gpointer data)
|
|||
|
||||
if (idle_run_task()) {
|
||||
gtk_progress_bar_set_fraction(progress, idle_progress());
|
||||
return gtk_widget_is_visible(gui_builder_widget("o_window"));
|
||||
return G_SOURCE_CONTINUE;
|
||||
} else {
|
||||
gtk_widget_hide(GTK_WIDGET(progress));
|
||||
idle_id = 0;
|
||||
|
@ -33,5 +33,4 @@ void gui_idle_disable()
|
|||
{
|
||||
if (idle_id)
|
||||
g_source_remove(idle_id);
|
||||
idle_cancel();
|
||||
}
|
||||
|
|
|
@ -17,10 +17,18 @@
|
|||
|
||||
enum idle_sync_t {
|
||||
IDLE_SYNC, /* Run task in the main thread. */
|
||||
IDLE_ASYNC, /* Run task in a separate thread. */
|
||||
};
|
||||
|
||||
#define IDLE_FUNC(x) ((void (*)(void *))x)
|
||||
|
||||
|
||||
/* Called to initialize the idle queue. */
|
||||
void idle_init();
|
||||
|
||||
/* Called to deinitialize the idle queue. */
|
||||
void idle_deinit();
|
||||
|
||||
/* Called to schedule a function to run later. */
|
||||
void idle_schedule(enum idle_sync_t, void (*)(void *), void *);
|
||||
|
||||
|
@ -33,7 +41,4 @@ bool idle_run_task();
|
|||
/* Called to find the percentage of idle tasks that have been run. */
|
||||
float idle_progress();
|
||||
|
||||
/* Called to cancel all idle tasks on the queue. */
|
||||
void idle_cancel();
|
||||
|
||||
#endif /* OCARINA_CORE_IDLE_H */
|
||||
|
|
|
@ -57,11 +57,7 @@ static void test_add()
|
|||
test_equal(lib->li_path, "tests/Music");
|
||||
|
||||
test_equal(queue_size(q), 0);
|
||||
test_equal(idle_run_task(), (bool)true); /* collection validation */
|
||||
test_equal(idle_run_task(), (bool)true); /* tests/Music/ */
|
||||
test_equal(idle_run_task(), (bool)true); /* <DIR>/Hyrule Symphony/ */
|
||||
test_equal(idle_run_task(), (bool)false); /* <DIR>/Ocarina of Time/ */
|
||||
|
||||
while (idle_run_task()) {};
|
||||
test_equal(track_db_get()->db_size, 48);
|
||||
test_equal(lib->li_size, 48);
|
||||
test_equal(queue_size(q), 48);
|
||||
|
|
|
@ -14,6 +14,7 @@ static void test_init()
|
|||
{
|
||||
struct queue *q = history_get_queue();
|
||||
|
||||
idle_init();
|
||||
filter_init();
|
||||
tags_init();
|
||||
playlist_init(NULL);
|
||||
|
|
|
@ -21,6 +21,8 @@ static void test_idle_queue(unsigned int n)
|
|||
{
|
||||
cur = -1;
|
||||
|
||||
idle_init();
|
||||
|
||||
test_equal(idle_progress(), (float)1.0);
|
||||
test_equal(idle_run_task(), (bool)false);
|
||||
|
||||
|
@ -37,11 +39,18 @@ static void test_idle_queue(unsigned int n)
|
|||
test_equal(idle_run_task(), (bool)false);
|
||||
test_equal(idle_progress(), (float)1.0);
|
||||
|
||||
for (unsigned int i = n; i < (2 * n); i++)
|
||||
idle_schedule(IDLE_ASYNC, inc_cur, GINT_TO_POINTER(i));
|
||||
while (idle_run_task()) {}
|
||||
test_equal(idle_progress(), (float)1.0);
|
||||
test_equal(func_passed, (bool)true);
|
||||
test_equal(cur, (2 * n) - 1);
|
||||
|
||||
for (unsigned int i = 0; i < n; i++)
|
||||
idle_schedule(IDLE_SYNC, inc_cur, GINT_TO_POINTER(i));
|
||||
test_equal(idle_progress(), (float)0.0);
|
||||
|
||||
idle_cancel();
|
||||
idle_deinit();
|
||||
test_equal(idle_progress(), (float)1.0);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
static void test_init()
|
||||
{
|
||||
idle_init();
|
||||
filter_init();
|
||||
tags_init();
|
||||
playlist_init(NULL);
|
||||
|
|
Loading…
Reference in New Issue