/* * Copyright 2013 (c) Anna Schumaker. */ #include #include 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; }