Implement thread cretaion. Add mutex to prevent data races in callback 85/100285/5 accepted/tizen/common/20161220.191025 accepted/tizen/ivi/20161220.223829 accepted/tizen/mobile/20161220.223700 accepted/tizen/tv/20161220.223733 accepted/tizen/wearable/20161220.223800 submit/tizen/20161220.104958
authorVolodymyr Brynza <v.brynza@samsung.com>
Mon, 19 Dec 2016 20:22:14 +0000 (22:22 +0200)
committerJeongmo Yang <jm80.yang@samsung.com>
Tue, 20 Dec 2016 08:27:22 +0000 (17:27 +0900)
Change-Id: Ic2aad19a9bf9269955e825c8b77af75ffeb96efa
Signed-off-by: Volodymyr Brynza <v.brynza@samsung.com>
packaging/murphy.spec
src/common/glib-glue.c
src/common/mainloop.c

index 8151e228a74fffa08aa7abf1840fa3866fbcb136..3a61976662f820653a4b8a597fe893a00004afa8 100644 (file)
@@ -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/
index bea7f98e98a0a7cfe73455a960718098336cbc1b..e2097d51ac40c02bd100ed5937660f607016bdb7 100644 (file)
 #include <murphy/common/mainloop.h>
 
 
+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);
+}
index 5702c1580360d840ae497713488a707360d1e058..bf46cd877fedf45b13333cb34fa2c9cfe3e62f46 100644 (file)
@@ -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;
+        }
     }
 }