From 7a283dbb2ef34dc24492029f39ba182c3fee1326 Mon Sep 17 00:00:00 2001 From: Volodymyr Brynza Date: Mon, 19 Dec 2016 22:22:14 +0200 Subject: Implement thread cretaion. Add mutex to prevent data races in callback Change-Id: Ic2aad19a9bf9269955e825c8b77af75ffeb96efa Signed-off-by: Volodymyr Brynza --- packaging/murphy.spec | 2 +- src/common/glib-glue.c | 108 +++++++++++++++++++++++++++++++++++++++++++++---- src/common/mainloop.c | 19 ++++++--- 3 files changed, 114 insertions(+), 15 deletions(-) diff --git a/packaging/murphy.spec b/packaging/murphy.spec index 8151e22..3a61976 100644 --- a/packaging/murphy.spec +++ b/packaging/murphy.spec @@ -29,7 +29,7 @@ Summary: Resource policy framework Name: murphy Version: 0.0.74 -Release: 4 +Release: 5 License: BSD-2.0 Group: System/Service URL: http://01.org/murphy/ diff --git a/src/common/glib-glue.c b/src/common/glib-glue.c index bea7f98..e2097d5 100644 --- a/src/common/glib-glue.c +++ b/src/common/glib-glue.c @@ -36,8 +36,13 @@ #include +static GMutex g_murphy_glue_callback_lock; +static GMutex g_murphy_glue_internal_lock; + + typedef struct { GMainLoop *gml; + GThread *worker; } glib_glue_t; @@ -136,6 +141,7 @@ static void remove_source(void *glue_data, guint id) static gboolean io_cb(GIOChannel *ioc, GIOCondition cond, gpointer user_data) { + g_mutex_lock(&g_murphy_glue_callback_lock); io_t *io = (io_t *)user_data; mrp_io_event_t events = MRP_IO_EVENT_NONE; int fd = g_io_channel_unix_get_fd(ioc); @@ -151,6 +157,7 @@ static gboolean io_cb(GIOChannel *ioc, GIOCondition cond, gpointer user_data) io->cb(io->glue_data, io, fd, events, io->user_data); + g_mutex_unlock(&g_murphy_glue_callback_lock); return TRUE; } @@ -164,10 +171,13 @@ static void *add_io(void *glue_data, int fd, mrp_io_event_t events, GIOChannel *ioc; io_t *io; + g_mutex_lock(&g_murphy_glue_internal_lock); ioc = g_io_channel_unix_new(fd); - if (ioc == NULL) + if (ioc == NULL) { + g_mutex_unlock(&g_murphy_glue_internal_lock); return NULL; + } io = mrp_allocz(sizeof(*io)); @@ -187,6 +197,7 @@ static void *add_io(void *glue_data, int fd, mrp_io_event_t events, io->user_data = user_data; io->glue_data = glue_data; + g_mutex_unlock(&g_murphy_glue_internal_lock); return io; } else { @@ -195,6 +206,7 @@ static void *add_io(void *glue_data, int fd, mrp_io_event_t events, } } + g_mutex_unlock(&g_murphy_glue_internal_lock); return NULL; } @@ -203,24 +215,31 @@ static void del_io(void *glue_data, void *id) { io_t *io = (io_t *)id; + g_mutex_lock(&g_murphy_glue_internal_lock); remove_source(glue_data, io->gl_iow); g_io_channel_unref(io->gl_ioc); mrp_free(io); + g_mutex_unlock(&g_murphy_glue_internal_lock); } static gboolean timer_cb(gpointer user_data) { - if (user_data == NULL) + if (user_data == NULL) { return FALSE; + } + g_mutex_lock(&g_murphy_glue_callback_lock); tmr_t *t = (tmr_t *)user_data; - if (t->cb == NULL) + if (t->cb == NULL) { + g_mutex_unlock(&g_murphy_glue_callback_lock); return FALSE; + } t->cb(t->glue_data, t, t->user_data); + g_mutex_unlock(&g_murphy_glue_callback_lock); return TRUE; } @@ -231,6 +250,7 @@ static void *add_timer(void *glue_data, unsigned int msecs, { tmr_t *t; + g_mutex_lock(&g_murphy_glue_internal_lock); t = mrp_allocz(sizeof(*t)); if (t != NULL) { @@ -241,12 +261,14 @@ static void *add_timer(void *glue_data, unsigned int msecs, t->user_data = user_data; t->glue_data = glue_data; + g_mutex_unlock(&g_murphy_glue_internal_lock); return t; } else mrp_free(t); } + g_mutex_unlock(&g_murphy_glue_internal_lock); return NULL; } @@ -255,8 +277,10 @@ static void del_timer(void *glue_data, void *id) { tmr_t *t = (tmr_t *)id; + g_mutex_lock(&g_murphy_glue_internal_lock); remove_source(glue_data, t->gl_t); mrp_free(t); + g_mutex_unlock(&g_murphy_glue_internal_lock); } @@ -264,25 +288,32 @@ static void mod_timer(void *glue_data, void *id, unsigned int msecs) { tmr_t *t = (tmr_t *)id; + g_mutex_lock(&g_murphy_glue_internal_lock); if (t != NULL) { remove_source(glue_data, t->gl_t); t->gl_t = add_timeout(glue_data, (GSourceFunc)timer_cb, msecs, t); } + g_mutex_unlock(&g_murphy_glue_internal_lock); } static gboolean defer_cb(void *user_data) { - if (user_data == NULL) + if (user_data == NULL) { return FALSE; + } + g_mutex_lock(&g_murphy_glue_callback_lock); dfr_t *d = (dfr_t *)user_data; - if (d->cb == NULL) + if (d->cb == NULL) { + g_mutex_unlock(&g_murphy_glue_callback_lock); return FALSE; + } d->cb(d->glue_data, d, d->user_data); + g_mutex_unlock(&g_murphy_glue_callback_lock); return TRUE; } @@ -293,6 +324,7 @@ static void *add_defer(void *glue_data, { dfr_t *d; + g_mutex_lock(&g_murphy_glue_internal_lock); d = mrp_allocz(sizeof(*d)); if (d != NULL) { @@ -303,12 +335,14 @@ static void *add_defer(void *glue_data, d->user_data = user_data; d->glue_data = glue_data; + g_mutex_unlock(&g_murphy_glue_internal_lock); return d; } else mrp_free(d); } + g_mutex_unlock(&g_murphy_glue_internal_lock); return NULL; } @@ -317,10 +351,12 @@ static void del_defer(void *glue_data, void *id) { dfr_t *d = (dfr_t *)id; + g_mutex_lock(&g_murphy_glue_internal_lock); if (d->gl_t != 0) remove_source(glue_data, d->gl_t); mrp_free(d); + g_mutex_unlock(&g_murphy_glue_internal_lock); } @@ -328,9 +364,11 @@ static void mod_defer(void *glue_data, void *id, int enabled) { dfr_t *d = (dfr_t *)id; - if (d == NULL) + if (d == NULL) { return; + } + g_mutex_lock(&g_murphy_glue_internal_lock); if (enabled && !d->gl_t) { d->gl_t = add_timeout(glue_data, (GSourceFunc)defer_cb, 0, d); } @@ -338,14 +376,32 @@ static void mod_defer(void *glue_data, void *id, int enabled) remove_source(glue_data, d->gl_t); d->gl_t = 0; } + g_mutex_unlock(&g_murphy_glue_internal_lock); } static void unregister(void *data) { glib_glue_t *glue = (glib_glue_t *)data; + GMainContext *def_ctx = g_main_context_default(); + GMainContext *loop_ctx = g_main_loop_get_context(glue->gml); + if (loop_ctx && def_ctx != loop_ctx) { + GSource *idle = g_idle_source_new(); + + g_source_set_callback(idle, (GSourceFunc) g_main_loop_quit, + glue->gml, NULL); + + g_source_attach(idle, g_main_loop_get_context(glue->gml)); + g_source_unref(idle); + g_thread_join(glue->worker); + g_thread_unref(glue->worker); + glue->worker = NULL; + } - g_main_loop_unref(glue->gml); + if (glue->gml) { + g_main_loop_unref(glue->gml); + glue->gml = NULL; + } mrp_free(glue); } @@ -363,6 +419,21 @@ static mrp_superloop_ops_t glib_ops = { .unregister = unregister, }; +static gpointer +thread_main (gpointer data) +{ + glib_glue_t *glue = (glib_glue_t *)data; + GMainContext *thread_main_context = g_main_loop_get_context(glue->gml); + + /* Set up the thread’s context and run it. */ + g_main_context_push_thread_default (thread_main_context); + + g_main_loop_run (glue->gml); + + g_main_context_pop_thread_default (thread_main_context); + + return NULL; +} int mrp_mainloop_register_with_glib(mrp_mainloop_t *ml, GMainLoop *gml) { @@ -373,8 +444,15 @@ int mrp_mainloop_register_with_glib(mrp_mainloop_t *ml, GMainLoop *gml) if (glue != NULL) { glue->gml = g_main_loop_ref(gml); - if (mrp_set_superloop(ml, &glib_ops, glue)) + if (mrp_set_superloop(ml, &glib_ops, glue)) { + /* Create new thread for context iteration only in case when + * glue context isn't default */ + GMainContext *def_ctx = g_main_context_default(); + GMainContext *loop_ctx = g_main_loop_get_context(glue->gml); + if (loop_ctx && def_ctx != loop_ctx) + glue->worker = g_thread_new(NULL, thread_main, glue); return TRUE; + } else { g_main_loop_unref(gml); mrp_free(glue); @@ -408,3 +486,17 @@ mrp_mainloop_t *mrp_mainloop_glib_get(GMainLoop *gml) return NULL; } + + +MRP_INIT static void mrp_main_loop_init_lock() +{ + g_mutex_init(&g_murphy_glue_callback_lock); + g_mutex_init(&g_murphy_glue_internal_lock); +} + + +MRP_EXIT static void mrp_main_loop_clear_lock() +{ + g_mutex_clear(&g_murphy_glue_callback_lock); + g_mutex_clear(&g_murphy_glue_internal_lock); +} diff --git a/src/common/mainloop.c b/src/common/mainloop.c index 5702c15..bf46cd8 100644 --- a/src/common/mainloop.c +++ b/src/common/mainloop.c @@ -1291,13 +1291,20 @@ static void super_work_cb(void *super_data, void *id, void *user_data) ops->mod_defer(ml->super_data, ml->work, FALSE); } else { - ops->del_io(ml->super_data, ml->iow); - ops->del_timer(ml->super_data, ml->timer); - ops->del_defer(ml->super_data, ml->work); + if (ml->iow != NULL) { + ops->del_io(ml->super_data, ml->iow); + ml->iow = NULL; + } + + if (ml->work != NULL) { + ops->del_defer(ml->super_data, ml->work); + ml->work = NULL; + } - ml->iow = NULL; - ml->timer = NULL; - ml->work = NULL; + if (ml->timer != NULL) { + ops->del_timer(ml->super_data, ml->timer); + ml->timer = NULL; + } } } -- cgit v1.2.3