Add finalizer source to tpl_gsource 69/254769/1
authorJoonbum Ko <joonbum.ko@samsung.com>
Mon, 28 Dec 2020 12:10:00 +0000 (21:10 +0900)
committerJoonbum Ko <joonbum.ko@samsung.com>
Tue, 9 Mar 2021 08:44:53 +0000 (17:44 +0900)
  - The finalizer source can only be had when
   the type of tpl_gsource is SOURCE_TYPE_NORMAL.
  - The finalizer allows a source of NORMAL type
   to be safely finalized inside a thread.

Change-Id: I143b9fe52bc38b65f7649115b3a757b572ce1cd0
Signed-off-by: Joonbum Ko <joonbum.ko@samsung.com>
src/tpl_utils_gthread.c

index 6d84137..5678755 100644 (file)
@@ -25,6 +25,7 @@ struct _tpl_gsource {
        tpl_gsource_functions *gsource_funcs;
 
        tpl_gsource_type_t     type;
+       tpl_gsource           *finalizer;
 
        void                  *data;
 };
@@ -139,6 +140,7 @@ tpl_gthread_destroy(tpl_gthread *thread, tpl_gthread_func deinit_func)
        thread->func = NULL;
 
        free(thread);
+       thread = NULL;
 }
 
 static gboolean
@@ -147,7 +149,10 @@ _thread_source_prepare(GSource *source, gint *time)
        tpl_gsource *gsource = (tpl_gsource *)source;
        tpl_bool_t ret       = TPL_FALSE;
 
-       if (gsource->gsource_funcs->prepare)
+       if (gsource->type != SOURCE_TYPE_NORMAL)
+               return ret;
+
+       if (gsource->gsource_funcs && gsource->gsource_funcs->prepare)
                ret = gsource->gsource_funcs->prepare(gsource);
 
        *time = -1;
@@ -161,7 +166,10 @@ _thread_source_check(GSource *source)
        tpl_gsource *gsource = (tpl_gsource *)source;
        tpl_bool_t ret       = TPL_FALSE;
 
-       if (gsource->gsource_funcs->check)
+       if (gsource->type != SOURCE_TYPE_NORMAL)
+               return ret;
+
+       if (gsource->gsource_funcs && gsource->gsource_funcs->check)
                ret = gsource->gsource_funcs->check(gsource);
 
        return ret;
@@ -175,11 +183,24 @@ _thread_source_dispatch(GSource *source, GSourceFunc cb, gpointer data)
        GIOCondition cond    = g_source_query_unix_fd(source, gsource->tag);
 
        TPL_IGNORE(cb);
-       TPL_IGNORE(data);
 
        if (cond & G_IO_IN) {
-               if (gsource->gsource_funcs->dispatch)
+               if (gsource->gsource_funcs && gsource->gsource_funcs->dispatch)
                        ret = gsource->gsource_funcs->dispatch(gsource);
+
+               if (gsource->type == SOURCE_TYPE_FINALIZER) {
+                       tpl_gsource *del_source = (tpl_gsource *)data;
+                       if (!g_source_is_destroyed(&del_source->gsource)) {
+                               g_mutex_lock(&del_source->thread->thread_mutex);
+
+                               g_source_remove_unix_fd(&del_source->gsource, del_source->tag);
+                               g_source_destroy(&del_source->gsource);
+                               g_source_unref(&del_source->gsource);
+
+                               g_cond_signal(&del_source->thread->thread_cond);
+                               g_mutex_unlock(&del_source->thread_mutex);
+                       }
+               }
        } else {
                /* When some io errors occur, it is not considered as a critical error.
                 * There may be problems with the screen, but it does not affect the operation. */
@@ -187,8 +208,13 @@ _thread_source_dispatch(GSource *source, GSourceFunc cb, gpointer data)
                                 gsource, gsource->fd, cond);
        }
 
-       if (gsource->type == SOURCE_TYPE_DISPOSABLE)
+       if (gsource->type == SOURCE_TYPE_DISPOSABLE ||
+               gsource->type == SOURCE_TYPE_FINALIZER) {
+               g_source_remove_unix_fd(&gsource->gsource, gsource->tag);
+               g_source_destroy(&gsource->gsource);
+               g_source_unref(&gsource->gsource);
                ret = TPL_GSOURCE_REMOVE;
+       }
 
        return ret;
 }
@@ -198,7 +224,7 @@ _thread_source_finalize(GSource *source)
 {
        tpl_gsource *gsource = (tpl_gsource *)source;
 
-       if (gsource->gsource_funcs->finalize)
+       if (gsource->gsource_funcs && gsource->gsource_funcs->finalize)
                gsource->gsource_funcs->finalize(gsource);
 
        if (gsource->is_eventfd)
@@ -208,6 +234,7 @@ _thread_source_finalize(GSource *source)
        gsource->thread = NULL;
        gsource->gsource_funcs = NULL;
        gsource->data = NULL;
+       gsource->finalizer = NULL;
 }
 
 static GSourceFuncs _thread_source_funcs = {
@@ -249,6 +276,13 @@ tpl_gsource_create(tpl_gthread *thread, void *data, int fd,
        new_gsource->data          = data;
        new_gsource->type          = type;
 
+       if (new_gsource->type == SOURCE_TYPE_NORMAL) {
+               tpl_gsource *finalizer = tpl_gsource_create(thread, new_gsource, -1,
+                                                                                                       NULL, SOURCE_TYPE_FINALIZER);
+               new_gsource->finalizer = finalizer;
+       } else
+               new_gsource->finalizer = NULL;
+
        new_gsource->tag = g_source_add_unix_fd(&new_gsource->gsource,
                                                                                        new_gsource->fd,
                                                                                        G_IO_IN | G_IO_ERR);
@@ -261,9 +295,30 @@ tpl_gsource_create(tpl_gthread *thread, void *data, int fd,
 void
 tpl_gsource_destroy(tpl_gsource *source)
 {
-       g_source_remove_unix_fd(&source->gsource, source->tag);
-       g_source_destroy(&source->gsource);
-       g_source_unref(&source->gsource);
+       if (g_source_is_destroyed(&source->gsource)) {
+               TPL_WARN("gsource(%p) already has been destroyed.",
+                                source);
+               return;
+       }
+
+       if (source->type == SOURCE_TYPE_NORMAL &&
+               source->finalizer != NULL) {
+               g_mutex_lock(&source->thread->thread_mutex);
+
+               tpl_gsource_send_event(source->finalizer, 1);
+
+               g_cond_wait(&source->thread->thread_cond, &source->thread->thread_mutex);
+               g_mutex_unlock(&source->thread->thread_mutex);
+       }
+
+
+       if (!g_source_is_destroyed(&source->gsource) &&
+               !(source->type == SOURCE_TYPE_DISPOSABLE ||
+                 source->type == SOURCE_TYPE_FINALIZER)) {
+               g_source_remove_unix_fd(&source->gsource, source->tag);
+               g_source_destroy(&source->gsource);
+               g_source_unref(&source->gsource);
+       }
 }
 
 void
@@ -272,7 +327,7 @@ tpl_gsource_send_event(tpl_gsource *source, uint64_t message)
        uint64_t value = message;
        int ret;
 
-       ret = write(del_source->event_fd, &value, sizeof(uint64_t));
+       ret = write(source->event_fd, &value, sizeof(uint64_t));
        if (ret == -1) {
                TPL_ERR("failed to send devent. tpl_gsource(%p)",
                                source);