tpl_wayland_egl_thread: Modified the procedure of finalizing disp_source. 83/145283/4
authorjoonbum.ko <joonbum.ko@samsung.com>
Tue, 22 Aug 2017 02:50:07 +0000 (11:50 +0900)
committerSooChan Lim <sc1.lim@samsung.com>
Tue, 22 Aug 2017 04:57:48 +0000 (04:57 +0000)
 - Added twe_wl_disp_del_source, an event gsource to delete twe_wl_disp_source.
 - When delete twe_wl_disp_source, calling _twe_thread_wl_disp_del_trigger()
  wakes up twe_wl_disp_del_source and removes twe_wl_disp_source in the thread.

Change-Id: I6a9ab462e8ab464663ee60db1548d822c50d7f00
Signed-off-by: joonbum.ko <joonbum.ko@samsung.com>
src/tpl_wayland_egl_thread.c

index 6f5f608..f16063d 100644 (file)
@@ -21,10 +21,11 @@ static int buffer_info_key;
 
 #define CLIENT_QUEUE_SIZE 3
 
-typedef struct _twe_wl_disp_source     twe_wl_disp_source;
-typedef struct _twe_wl_surf_source     twe_wl_surf_source;
-typedef struct _twe_wl_buffer_info     twe_wl_buffer_info;
-typedef struct _twe_tdm_source         twe_tdm_source;
+typedef struct _twe_wl_disp_source             twe_wl_disp_source;
+typedef struct _twe_wl_surf_source             twe_wl_surf_source;
+typedef struct _twe_wl_buffer_info             twe_wl_buffer_info;
+typedef struct _twe_tdm_source                 twe_tdm_source;
+typedef struct _twe_wl_disp_del_source twe_wl_disp_del_source;
 
 struct _twe_thread_context {
        int ref_cnt;
@@ -55,11 +56,19 @@ struct _twe_wl_disp_source {
        struct wayland_tbm_client *wl_tbm_client;
        struct tizen_surface_shm *tss; /* used for surface buffer_flush */
        tpl_bool_t prepared;
+       twe_wl_disp_del_source *disp_del_source;
        twe_thread *thread;
        tpl_object_t obj;
        /* TODO : surface list */
 };
 
+struct _twe_wl_disp_del_source {
+       GSource gsource;
+       gpointer tag;
+       int event_fd;
+       twe_wl_disp_source* disp_source;
+};
+
 struct _twe_wl_surf_source {
        GSource gsource;
        gpointer tag;
@@ -400,9 +409,12 @@ _twe_thread_wl_disp_finalize(GSource *source)
        twe_wl_disp_source *disp_source = (twe_wl_disp_source *)source;
 
        TPL_OBJECT_LOCK(&disp_source->obj);
+
        /* If disp_source is in prepared state, cancel it */
-       if (disp_source->prepared)
+       if (disp_source->prepared) {
                wl_display_cancel_read(disp_source->disp);
+               disp_source->prepared = TPL_FALSE;
+       }
 
        if (wl_display_dispatch_queue_pending(disp_source->disp,
                                                                                  disp_source->ev_queue) == -1) {
@@ -553,6 +565,135 @@ _twe_display_shm_fini(twe_wl_disp_source *disp_source)
        }
 }
 
+static void
+_twe_thread_wl_disp_del(twe_wl_disp_source *disp_source)
+{
+       if (g_source_is_destroyed(&disp_source->gsource)) {
+               TPL_ERR("disp_source(%p) already destroyed.", disp_source);
+               return;
+       }
+
+       g_source_remove_poll(&disp_source->gsource, &disp_source->gfd);
+       g_source_destroy(&disp_source->gsource);
+       g_source_unref(&disp_source->gsource);
+
+       TPL_LOG_T("WL_EGL", "[DEL] twe_display(%p) wl_display(%p)",
+                         disp_source, disp_source->disp);
+}
+
+static gboolean
+_twe_thread_wl_disp_del_dispatch(GSource *source, GSourceFunc cb, gpointer data)
+{
+       twe_wl_disp_del_source *disp_del_source = (twe_wl_disp_del_source *)source;
+       GIOCondition cond;
+
+       if (g_source_is_destroyed(source)) {
+               TPL_ERR("disp_del source(%p) already destroyed.", source);
+               return G_SOURCE_REMOVE;
+       }
+
+       cond = g_source_query_unix_fd(source, disp_del_source->tag);
+
+       if (cond & G_IO_IN) {
+               ssize_t s;
+               uint64_t u;
+
+               s = read(disp_del_source->event_fd, &u, sizeof(uint64_t));
+               if (s != sizeof(uint64_t))
+                       TPL_ERR("Failed to read from event_fd(%d)",
+                                       disp_del_source->event_fd);
+
+               _twe_thread_wl_disp_del(disp_del_source->disp_source);
+       }
+
+       return G_SOURCE_CONTINUE;
+}
+
+static void
+_twe_thread_wl_disp_del_finalize(GSource *source)
+{
+       twe_wl_disp_del_source *disp_del_source =
+               (twe_wl_disp_del_source *)source;
+
+       TPL_LOG_T("WL_EGL", "gsource(%p) event_fd(%d)",
+                         source, disp_del_source->event_fd);
+
+       g_source_remove_unix_fd(source, disp_del_source->tag);
+
+       close(disp_del_source->event_fd);
+
+       disp_del_source->tag = NULL;
+       disp_del_source->event_fd = -1;
+
+       return;
+}
+
+static GSourceFuncs _twe_wl_disp_del_funcs = {
+       .prepare = NULL,
+       .check = NULL,
+       .dispatch = _twe_thread_wl_disp_del_dispatch,
+       .finalize = _twe_thread_wl_disp_del_finalize,
+};
+
+static void
+_twe_thread_wl_disp_del_trigger(twe_wl_disp_source *disp_source)
+{
+       twe_wl_disp_del_source *disp_del_source = disp_source->disp_del_source;
+       uint64_t value = 1;
+       int ret;
+
+       ret = write(disp_del_source->event_fd, &value, sizeof(uint64_t));
+       if (ret == -1) {
+               TPL_ERR("failed to send acquirable event. twe_wl_disp_del_source(%p)",
+                               disp_del_source);
+               return;
+       }
+}
+
+twe_wl_disp_del_source *
+_twe_display_del_source_init(twe_thread *thread,
+                                                        twe_wl_disp_source *disp_source)
+{
+       twe_thread_context *ctx = thread->ctx;
+       twe_wl_disp_del_source *source = NULL;
+
+       if (!disp_source) {
+               TPL_ERR("Invalid parameter. disp_source is NULL");
+               return NULL;
+       }
+
+       source = (twe_wl_disp_del_source *)g_source_new(&_twe_wl_disp_del_funcs,
+                                                                                               sizeof(twe_wl_disp_del_source));
+       if (!source) {
+               TPL_ERR("[THREAD] Failed to create GSource");
+               return NULL;
+       }
+
+       source->event_fd = eventfd(0, EFD_CLOEXEC);
+       if (source->event_fd < 0) {
+               TPL_ERR("[THREAD] Failed to create eventfd. errno(%d)", errno);
+               g_source_unref(&source->gsource);
+               return NULL;
+       }
+
+       source->tag = g_source_add_unix_fd(&source->gsource,
+                                                                          source->event_fd,
+                                                                          G_IO_IN);
+       source->disp_source = disp_source;
+
+       g_source_attach(&source->gsource, g_main_loop_get_context(ctx->twe_loop));
+       g_source_unref(&source->gsource);
+
+       return source;
+}
+
+void
+_twe_display_del_source_fini(twe_wl_disp_del_source *source)
+{
+       g_source_destroy(&source->gsource);
+       g_source_unref(&source->gsource);
+}
+
 twe_display_h
 twe_display_add(twe_thread* thread, struct wl_display *display)
 {
@@ -587,6 +728,8 @@ twe_display_add(twe_thread* thread, struct wl_display *display)
 
        _twe_display_shm_init(source);
 
+       source->disp_del_source = _twe_display_del_source_init(thread, source);
+
        g_source_set_callback(&source->gsource, NULL, display, NULL);
        g_source_add_poll(&source->gsource, &source->gfd);
        g_source_attach(&source->gsource, g_main_loop_get_context(ctx->twe_loop));
@@ -603,6 +746,8 @@ twe_display_del(twe_display_h twe_display)
 {
        gboolean is_destroyed = FALSE;
        twe_wl_disp_source *source = (twe_wl_disp_source *)twe_display;
+       twe_wl_disp_del_source *disp_del_source = NULL;
+
        if (!source ||
                        (is_destroyed = g_source_is_destroyed(&source->gsource))) {
                TPL_ERR("twe_display(%p) is invalid. | is_destroyed(%s)",
@@ -610,16 +755,19 @@ twe_display_del(twe_display_h twe_display)
                return TPL_ERROR_INVALID_PARAMETER;
        }
 
+       disp_del_source = source->disp_del_source;
+
        _twe_display_shm_fini(source);
        _twe_display_fini_wl_tbm_client(source->wl_tbm_client);
        source->wl_tbm_client = NULL;
 
-       g_source_remove_poll(&source->gsource, &source->gfd);
-       g_source_destroy(&source->gsource);
-       g_source_unref(&source->gsource);
+       _twe_thread_wl_disp_del_trigger(source);
+
+       while (!g_source_is_destroyed(&source->gsource)) {
+               /* Waiting for destroying disp_source */
+       }
 
-       TPL_LOG_T("WL_EGL", "del| twe_display(%p) wl_display(%p)",
-                         source, source->disp);
+       _twe_display_del_source_fini(disp_del_source);
 
        return TPL_ERROR_NONE;
 }