From e7fff1a3fecb076806a7b9c45fdecf3a7f450a84 Mon Sep 17 00:00:00 2001 From: Joonbum Ko Date: Wed, 4 Jan 2023 16:29:57 +0900 Subject: [PATCH] utils_gthread: cancel pause when wait_idle failed - If the tpl_gthread_wait_idle fails with timeout, it should be unlock pause_mutex immediately. Change-Id: If33cc3c0b617ca34bb63d110d927e0dd7c022526 Signed-off-by: Joonbum Ko --- src/tpl_utils_gthread.c | 56 ++++++++++++++++++++++++++++++++++++------------- src/tpl_utils_gthread.h | 8 +++++-- 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/src/tpl_utils_gthread.c b/src/tpl_utils_gthread.c index bdc1109..68c2faf 100644 --- a/src/tpl_utils_gthread.c +++ b/src/tpl_utils_gthread.c @@ -481,33 +481,30 @@ _thread_idle_cb(gpointer data) /* If the caller thread of tpl_gthread_wait_idle locked the pause_mutex, * thread will be paused here until unlock */ g_mutex_lock(>hread->pause_mutex); + gthread->paused = TPL_FALSE; g_mutex_unlock(>hread->pause_mutex); return G_SOURCE_REMOVE; } -void +tpl_result_t tpl_gthread_wait_idle(tpl_gthread *gthread) { - TPL_CHECK_ON_NULL_RETURN(gthread); - GSource *idle_source = NULL; gint64 end_time; gboolean ret = TRUE; + tpl_result_t res = TPL_ERROR_NONE; TPL_DEBUG("[WAIT IDLE] BEGIN"); g_mutex_lock(>hread->idle_mutex); - if (gthread->is_idle) { - g_mutex_unlock(>hread->idle_mutex); - return; - } idle_source = g_idle_source_new(); if (idle_source == NULL) { TPL_WARN("Failed to create and attach idle source"); + res = TPL_ERROR_INVALID_OPERATION; g_mutex_unlock(>hread->idle_mutex); - return; + return res; } g_source_set_priority(idle_source, G_PRIORITY_LOW); @@ -526,6 +523,7 @@ tpl_gthread_wait_idle(tpl_gthread *gthread) end_time); if (!ret) { TPL_ERR("wait_idle timeout!"); + res = TPL_ERROR_TIME_OUT; break; } } while (!gthread->is_idle); @@ -535,16 +533,47 @@ tpl_gthread_wait_idle(tpl_gthread *gthread) g_mutex_unlock(>hread->idle_mutex); TPL_DEBUG("[WAIT IDLE] END"); + + return res; } -void +tpl_bool_t tpl_gthread_pause_in_idle(tpl_gthread *gthread) { - TPL_CHECK_ON_NULL_RETURN(gthread); + TPL_CHECK_ON_NULL_RETURN_VAL(gthread, TPL_FALSE); + + tpl_result_t res; + int cnt = 0; + + /* Assume three threads. (M, C, wl-egl-thread) + * C thread : already locked pause_mutex and doing their own job. + * M thread : call pause_in_idle and trying to lock pause_mutex. + * wl-egl-thread : trying to lock pause_mutex in _thread_idle_cb. + * + * When C thread calls tpl_gthread_continue and unlock pause_mutex, + * M thread may receive schedule and lock pause_mutex. + * In that case, M thread should yield to wl-egl-thread, which is + * paused in thread_idle_cb(). */ + do { + g_mutex_lock(>hread->pause_mutex); + if (gthread->paused) { + g_mutex_unlock(>hread->pause_mutex); + sched_yield(); + } else { + break; + } + } while (++cnt <= 100); - g_mutex_lock(>hread->pause_mutex); - tpl_gthread_wait_idle(gthread); - gthread->paused = TPL_TRUE; + res = tpl_gthread_wait_idle(gthread); + if (res != TPL_ERROR_NONE) { + TPL_ERR("Failed to wait idle. | res(%d)", res); + gthread->paused = TPL_FALSE; + g_mutex_unlock(>hread->pause_mutex); + } else { + gthread->paused = TPL_TRUE; + } + + return gthread->paused; } void @@ -553,6 +582,5 @@ tpl_gthread_continue(tpl_gthread *gthread) TPL_CHECK_ON_NULL_RETURN(gthread); if (!gthread->paused) return; - gthread->paused = TPL_FALSE; g_mutex_unlock(>hread->pause_mutex); } \ No newline at end of file diff --git a/src/tpl_utils_gthread.h b/src/tpl_utils_gthread.h index 66552c4..c6ae5a4 100644 --- a/src/tpl_utils_gthread.h +++ b/src/tpl_utils_gthread.h @@ -205,16 +205,20 @@ tpl_gcond_signal(tpl_gcond *gcond); * attach idle source and waiting for idle callback * * @param gthread Pointer to tpl_gthread + * + * @return tpl_result_t result of wait_idle */ -void +tpl_result_t tpl_gthread_wait_idle(tpl_gthread *gthread); /** * pause thread when idle callback is called * * @param gthread Pointer to tpl_gthread + * + * @return TPL_TRUE if succeed to pause, TPL_FALSE otherwise. */ -void +tpl_bool_t tpl_gthread_pause_in_idle(tpl_gthread *gthread); /** -- 2.7.4