Fix thread suspend logic for pkgmgr_thread 83/302283/1
authorSuyeon Hwang <stom.hwang@samsung.com>
Tue, 24 Oct 2023 06:33:44 +0000 (15:33 +0900)
committerSuyeon Hwang <stom.hwang@samsung.com>
Tue, 5 Dec 2023 05:56:15 +0000 (14:56 +0900)
- Issue:
If pkgmgr_client_new() is continously failed, pkgmgr_thread can sleep
very long time and this can cause deadlock when the app tries to destroy
the handle.

- Solution:
To reduce the error log, gradually increased suspend time logic was
added in pkgmgr thread. However, the suspend time could increase
without limitation and this long suspend time might cause critical
deadlock.
To solve this problem, this patch changes the suspend logic with
conditional variable. Using conditional variable, the framework will be
able to resume the thread and properly terminate it even if the suspend
time is too long. And also this patch adds a limitation for the suspend
time. So, even if the thread termination logic is failed, the thread
will be exited in a reasonable time.

Change-Id: I6e126464032a70dbf1d5f63a03c7a85c01ef0a8d
Signed-off-by: Suyeon Hwang <stom.hwang@samsung.com>
client/tts_core.c

index e2a1ebe4a2ae83cfc8abef4a682d0ca2ebc90a9a..a571aa954d0bbb8a8603fd7a9313058517c5596b 100644 (file)
@@ -29,8 +29,6 @@ static const int TTS_ERROR_FAIL_TO_SEND_HELLO = TIZEN_ERROR_TTS | 0xFF;
 
 
 /* Static variables */
-static atomic_bool g_is_thread_canceled = false;
-
 static char* g_engine_name = NULL;
 static int g_engine_update_status = 0;
 static atomic_bool g_is_engine_name_changed = false;
@@ -41,6 +39,7 @@ static char* g_pkgmgr_status = NULL;
 static pkgmgr_client* g_pkgmgr = NULL;
 static Ecore_Thread* g_pkgmgr_thread = NULL;
 static pthread_mutex_t g_pkgmgr_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t g_pkgmgr_cond = PTHREAD_COND_INITIALIZER;
 
 static char* g_language = NULL;
 static int g_voice_type = -1;
@@ -238,13 +237,14 @@ static int __pkgmgr_status_cb(uid_t target_uid, int req_id, const char *type, co
 static void __create_pkgmgr_thread(void* data, Ecore_Thread* thread)
 {
        SLOG(LOG_INFO, TAG_TTSC, "[DEBUG] create pkgmgr thread");
+       static const long long MAX_TIME_DELAY = 60000000000ll;
+       long long time_delay = 10000000ll;
+       int cnt = 0;
 
        pthread_mutex_lock(&g_pkgmgr_mutex);
-       int time_delay = 10000;
-       int cnt = 0;
        while (NULL == g_pkgmgr) {
                /* Checking the thread is canceled or not */
-               if (g_is_thread_canceled) {
+               if (EINA_TRUE == ecore_thread_check(g_pkgmgr_thread)) {
                        SLOG(LOG_INFO, TAG_TTSC, "[INFO] g_pkgmgr_thread is canceled. Exit");
                        break;
                }
@@ -259,7 +259,6 @@ static void __create_pkgmgr_thread(void* data, Ecore_Thread* thread)
                if (NULL == g_pkgmgr) {
                        if (0 == cnt % 5) {
                                SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to create pkgmgr handle");
-                               time_delay *= 2;
                        }
                } else {
                        int ret = pkgmgr_client_set_status_type(g_pkgmgr, PKGMGR_CLIENT_STATUS_INSTALL | PKGMGR_CLIENT_STATUS_UNINSTALL | PKGMGR_CLIENT_STATUS_UPGRADE);
@@ -268,8 +267,6 @@ static void __create_pkgmgr_thread(void* data, Ecore_Thread* thread)
                                        SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to listen pkgmgr status. remove and recreate client");
                                        pkgmgr_client_free(g_pkgmgr);
                                        g_pkgmgr = NULL;
-                                       if (0 == cnt % 5)
-                                               time_delay *= 2;
                                } else {
                                        SLOG(LOG_ERROR, TAG_TTSC, "[INFO] Succeed to register pkgmgr cb");
                                        break;
@@ -278,12 +275,19 @@ static void __create_pkgmgr_thread(void* data, Ecore_Thread* thread)
                                SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to set status type on pkgmgr, ret(%d)", ret);
                                pkgmgr_client_free(g_pkgmgr);
                                g_pkgmgr = NULL;
-                               if (0 == cnt % 5)
-                                       time_delay *= 2;
                        }
                }
 
-               usleep(time_delay);
+               if (MAX_TIME_DELAY > time_delay && 0 == cnt % 5) time_delay *= 2;
+
+               struct timespec time_sleep;
+               timespec_get(&time_sleep, TIME_UTC);
+               time_sleep.tv_nsec += time_delay % 1000000000;
+               int quotient = time_sleep.tv_nsec / 1000000000;
+               time_sleep.tv_nsec = time_sleep.tv_nsec % 1000000000;
+               time_sleep.tv_sec += time_delay / 1000000000 + quotient;
+
+               pthread_cond_timedwait(&g_pkgmgr_cond, &g_pkgmgr_mutex, &time_sleep);
                cnt++;
        }
        pthread_mutex_unlock(&g_pkgmgr_mutex);
@@ -294,7 +298,6 @@ static void __create_pkgmgr_thread(void* data, Ecore_Thread* thread)
 static void __finish_pkgmgr_thread(void* data, Ecore_Thread* thread)
 {
        SLOG(LOG_INFO, TAG_TTSC, "[DEBUG] Finish pkgmgr thread");
-       g_is_thread_canceled = false;
        g_pkgmgr_thread = NULL;
 }
 
@@ -302,7 +305,6 @@ static void __finish_pkgmgr_thread(void* data, Ecore_Thread* thread)
 static void __cancel_pkgmgr_thread(void* data, Ecore_Thread* thread)
 {
        SLOG(LOG_INFO, TAG_TTSC, "[DEBUG] Cancel pkgmgr thread");
-       g_is_thread_canceled = false;
        g_pkgmgr_thread = NULL;
 }
 //LCOV_EXCL_STOP
@@ -699,12 +701,21 @@ int tts_core_deinitialize()
        if (NULL != g_reprepare_thread && EINA_FALSE == ecore_thread_check(g_reprepare_thread)) {
                SLOG(LOG_INFO, TAG_TTSC, "[INFO] Cancel reprepare thread");
                ecore_thread_cancel(g_reprepare_thread);
-               ecore_thread_wait(g_reprepare_thread, 0.5);             // wait g_reprepare_thread is terminated.
+
+               ecore_thread_wait(g_reprepare_thread, 1.0);             // wait g_reprepare_thread is terminated.
+               g_reprepare_thread = NULL;
        }
 
        if (NULL != g_pkgmgr_thread) {
                SLOG(LOG_INFO, TAG_TTSC, "[INFO] Cancel pkgmgr thread");
-               g_is_thread_canceled = true;
+               ecore_thread_cancel(g_pkgmgr_thread);
+
+               pthread_mutex_lock(&g_pkgmgr_mutex);
+               pthread_cond_broadcast(&g_pkgmgr_cond);
+               pthread_mutex_unlock(&g_pkgmgr_mutex);
+
+               ecore_thread_wait(g_pkgmgr_thread, 1.0);                // wait g_reprepare_thread is terminated.
+               g_pkgmgr_thread = NULL;
        }
 
        if (NULL != g_language) {