static GSList *module_list;
+static GCond module_worker_thread_cond;
+static GMutex module_worker_thread_mutex;
+
API void module_add(struct module *module)
{
switch (module->priority) {
g_slist_foreach(module_list, func, user_data);
}
+static gboolean module_worker_source_check(GSource *source)
+{
+ const char *name = NULL;
+ struct module *module = NULL;
+
+ name = g_source_get_name(source);
+ g_assert(name);
+
+ module = module_find(name);
+ g_assert(module);
+ g_assert(module->worker.queue);
+
+ if (g_async_queue_length(module->worker.queue) <= 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+/**
+ * @brief Run callback with popped event
+ */
+static gboolean module_worker_source_dispatch(GSource *source,
+ GSourceFunc callback, gpointer user_data)
+{
+ struct module_worker *worker = user_data;
+ int *event;
+ gboolean ret;
+
+ if (!callback || !worker) {
+ _E("Invalid parameter");
+ return G_SOURCE_REMOVE;
+ }
+
+ event = g_async_queue_pop(worker->queue);
+ ret = callback(event);
+
+ g_slice_free(int, event);
+
+ return ret;
+}
+
+static GSourceFuncs module_worker_source_funcs = {
+ NULL,
+ module_worker_source_check,
+ module_worker_source_dispatch,
+ NULL
+};
+
+/**
+ * @brief Make mainloop and register event_callback in this thread
+ */
+static gpointer module_worker_thread_func(gpointer data)
+{
+ struct module *module = (struct module *)data;
+ struct module_worker *worker = NULL;
+ g_autoptr(GSource) event_source = NULL;
+
+ if (!module) {
+ _E("Invalid parameter");
+ return NULL;
+ }
+ worker = &(module->worker);
+
+ worker->context = g_main_context_new();
+ if (!worker->context) {
+ _E("Failed to make the context of %s module", module->name);
+ goto cleanup;
+ }
+
+ g_main_context_push_thread_default(worker->context);
+ if (g_main_context_get_thread_default() != worker->context) {
+ _E("Failed to set the thread-default context of %s module", module->name);
+ goto cleanup;
+ }
+
+ worker->queue = g_async_queue_new();
+ if (!worker->queue) {
+ _E("Failed to make the queue of %s module", module->name);
+ goto cleanup;
+ }
+
+ event_source = g_source_new(&module_worker_source_funcs, sizeof(GSource));
+ if (!event_source) {
+ _E("Failed to make the event source of %s module", module->name);
+ goto cleanup;
+ }
+ g_source_set_name(event_source, module->name);
+ g_source_set_callback(event_source, module->event_handler, worker, NULL);
+ g_source_attach(event_source, worker->context);
+
+ worker->loop = g_main_loop_new(worker->context, FALSE);
+
+ _D("Start to run %s thread", module->name);
+ g_cond_signal(&module_worker_thread_cond);
+ g_main_loop_run(worker->loop);
+
+cleanup:
+ _D("Start to stop %s thread", module->name);
+ if (worker->queue)
+ g_async_queue_unref(worker->queue);
+
+ return NULL;
+}
+
static void module_init(gpointer data, gpointer user_data)
{
struct module *module = data;
int *num_successful = (int *)user_data;
int ret;
- if (!module || !module->init)
+ if (!module)
return;
_D("Initialize [%s] module", module->name);
- ret = module->init();
- if (ret < 0) {
- _E("Failed to initialize %s module (%d)", module->name, ret);
- module_remove(module);
- return;
+ if (module->init) {
+ ret = module->init();
+ if (ret < 0) {
+ _E("Failed to initialize %s module (%d)", module->name, ret);
+ module_remove(module);
+ return;
+ }
+ }
+
+ if (module->event_handler) {
+ g_cond_init(&module_worker_thread_cond);
+ g_mutex_init(&module_worker_thread_mutex);
+ g_mutex_lock(&module_worker_thread_mutex);
+
+ _D("Register [%s] worker", module->name);
+
+ module->worker.thread = g_thread_new(module->name, module_worker_thread_func, module);
+ if (!module->worker.thread) {
+ _E("Failed to create %s thread", module->name);
+ if (module->init && module->exit)
+ module->exit();
+ module_remove(module);
+ return;
+ }
+
+ /* Wait for thread to ready maximum 5 seconds */
+ if (!g_cond_wait_until(&module_worker_thread_cond, &module_worker_thread_mutex,
+ g_get_monotonic_time() + 5000000)) {
+ _E("Failed for worker thread to run main loop");
+ g_mutex_unlock(&module_worker_thread_mutex);
+ if (module->init && module->exit)
+ module->exit();
+ module_remove(module);
+ return;
+ }
+
+ g_mutex_unlock(&module_worker_thread_mutex);
}
(*num_successful)++;
struct module *module = data;
int ret;
+ if (module->event_handler) {
+ _D("Unregister [%s] worker", module->name);
+
+ g_main_loop_quit(module->worker.loop);
+ }
+
if (module->exit) {
_D("Finalize [%s] module", module->name);