utils_gthread: Prevent deadlock caused by wait_idle 41/286741/1
authorJoonbum Ko <joonbum.ko@samsung.com>
Fri, 2 Dec 2022 07:17:32 +0000 (16:17 +0900)
committerJoonbum Ko <joonbum.ko@samsung.com>
Thu, 12 Jan 2023 07:13:27 +0000 (16:13 +0900)
 Deadlock situation: Multi-threaded and multi surfaces for each thread

                        T2: call pause_in_idle()->wait_idle()
                            cond_wait() until idle signaled
 T1: call wait_idle()
     wait for lock idle_mutex
                        T2: _thread_idle_cb unlock idle_mutex,
                           set is_idle to TPL_TRUE
                           and wait to lock pause_mutex
 T1: change is_idle to TPL_FALSE
     cond_wait()
                        T2: cannot exit from while loop
                           still cond_wait()

 - is_idle changing should be set TPL_FALSE after cond_wait finished

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

index 208d881..bdc1109 100644 (file)
@@ -475,7 +475,7 @@ _thread_idle_cb(gpointer data)
 
        g_mutex_lock(&gthread->idle_mutex);
        gthread->is_idle = TPL_TRUE;
-       g_cond_signal(&gthread->idle_cond);
+       g_cond_broadcast(&gthread->idle_cond);
        g_mutex_unlock(&gthread->idle_mutex);
 
        /* If the caller thread of tpl_gthread_wait_idle locked the pause_mutex,
@@ -498,7 +498,10 @@ tpl_gthread_wait_idle(tpl_gthread *gthread)
        TPL_DEBUG("[WAIT IDLE] BEGIN");
 
        g_mutex_lock(&gthread->idle_mutex);
-       gthread->is_idle = TPL_FALSE;
+       if (gthread->is_idle) {
+               g_mutex_unlock(&gthread->idle_mutex);
+               return;
+       }
 
        idle_source = g_idle_source_new();
        if (idle_source == NULL) {
@@ -517,8 +520,7 @@ tpl_gthread_wait_idle(tpl_gthread *gthread)
        /* 200ms timeout */
        end_time = g_get_monotonic_time() +
                                (200 * G_TIME_SPAN_MILLISECOND);
-
-       while (!gthread->is_idle) {
+       do {
                ret = g_cond_wait_until(&gthread->idle_cond,
                                                                &gthread->idle_mutex,
                                                                end_time);
@@ -526,7 +528,10 @@ tpl_gthread_wait_idle(tpl_gthread *gthread)
                        TPL_ERR("wait_idle timeout!");
                        break;
                }
-       }
+       } while (!gthread->is_idle);
+
+       gthread->is_idle = TPL_FALSE;
+
        g_mutex_unlock(&gthread->idle_mutex);
 
        TPL_DEBUG("[WAIT IDLE] END");