Fix thread unsafety issue when preparing 47/206747/2 submit/tizen/20190524.110156
authorwn.jang <wn.jang@samsung.com>
Fri, 24 May 2019 07:07:23 +0000 (16:07 +0900)
committerwn.jang <wn.jang@samsung.com>
Fri, 24 May 2019 10:53:26 +0000 (19:53 +0900)
Change-Id: Idafff2ce66490ceade64919f37ad1918ad9be899

client/vc_widget.c
server/vcd_server.c

index fafdda2..c185aba 100644 (file)
@@ -42,7 +42,8 @@ static Ecore_Timer* g_w_notify_result_timer = NULL;
 static pthread_mutex_t g_w_init_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 static Ecore_Thread* g_w_prepare_thread = NULL;
-static int g_w_prepare_canceled = 0;
+static bool g_ask_to_cancel_preparing = false;
+static bool g_is_prepare_thread_alive = false;
 
 static int g_daemon_pid = 0;
 
@@ -269,7 +270,7 @@ int vc_widget_deinitialize(vc_h vc_w)
                return VC_ERROR_INVALID_STATE;
        }
 
-       g_w_prepare_canceled = 1;
+       g_ask_to_cancel_preparing = true;
 
        vc_state_e state;
        vc_widget_client_get_state(vc_w, &state);
@@ -476,17 +477,22 @@ static void __start_prepare_thread(void *data, Ecore_Thread *thread)
        SLOG(LOG_INFO, TAG_VCW, "@@@ Start prepare thread");
        int ret = -1, retry_count = 0;
        vc_h vc_w = (vc_h)data;
+       g_is_prepare_thread_alive = true;
 
        /* Send hello */
        while (0 != ret) {
-               if (g_w_prepare_canceled) {
+               if (g_ask_to_cancel_preparing) {
                        SLOG(LOG_WARN, TAG_VCW, "[WARNING] Thread is canceled.");
+                       __vc_widget_internal_unprepare(vc_w);
+                       ecore_main_loop_thread_safe_call_async(__vc_widget_delete_focus_event_handler, NULL);
+                       g_is_prepare_thread_alive = false;
                        return;
                }
 
                if (retry_count == 30) {
                        SLOG(LOG_ERROR, TAG_VCW, "[ERROR] Fail to request hello !!");
                        ecore_main_loop_thread_safe_call_async(__vc_widget_delete_focus_event_handler, NULL);
+                       g_is_prepare_thread_alive = false;
                        return;
                }
 
@@ -502,14 +508,19 @@ static void __start_prepare_thread(void *data, Ecore_Thread *thread)
        ret = -1;
        retry_count = 0;
        while (0 != ret) {
-               if (g_w_prepare_canceled) {
+               if (g_ask_to_cancel_preparing) {
                        SLOG(LOG_WARN, TAG_VCW, "[WARNING] Thread is canceled.");
+                       __vc_widget_internal_unprepare(vc_w);
+                       ecore_main_loop_thread_safe_call_async(__vc_widget_delete_focus_event_handler, NULL);
+                       g_is_prepare_thread_alive = false;
                        return;
                }
 
                if (retry_count == 10) {
                        SLOG(LOG_ERROR, TAG_VCW, "[ERROR] Fail to connect daemon !!");
+                       __vc_widget_internal_unprepare(vc_w);
                        ecore_main_loop_thread_safe_call_async(__vc_widget_delete_focus_event_handler, NULL);
+                       g_is_prepare_thread_alive = false;
                        return;
                }
                ret = __vc_widget_connect_daemon((void*)vc_w);
@@ -520,21 +531,20 @@ static void __start_prepare_thread(void *data, Ecore_Thread *thread)
        }
 
        SLOG(LOG_DEBUG, TAG_VCW, "@@@");
-
+       g_is_prepare_thread_alive = false;
        return;
 }
 
 static void __end_prepare_thread(void *data, Ecore_Thread *thread)
 {
-       g_w_prepare_thread = NULL;
        SLOG(LOG_DEBUG, TAG_VCW, "@@@ End prepare thread");
+       g_w_prepare_thread = NULL;
 }
 
 static void __cancel_prepare_thread(void *data, Ecore_Thread *thread)
 {
        SLOG(LOG_DEBUG, TAG_VCW, "@@@ Cancel prepare thread");
        g_w_prepare_thread = NULL;
-       g_w_prepare_canceled = 1;
 }
 
 int vc_widget_prepare(vc_h vc_w)
@@ -546,10 +556,12 @@ int vc_widget_prepare(vc_h vc_w)
                return VC_ERROR_NONE;
        }
 
+       pthread_mutex_lock(&g_w_init_mutex);
        vc_state_e state;
        if (0 != vc_widget_client_get_state(vc_w, &state)) {
                SLOG(LOG_ERROR, TAG_VCW, "[ERROR] A handle is not available");
                SLOG(LOG_DEBUG, TAG_VCW, "@@@");
+               pthread_mutex_unlock(&g_w_init_mutex);
                return VC_ERROR_INVALID_STATE;
        }
 
@@ -557,6 +569,7 @@ int vc_widget_prepare(vc_h vc_w)
        if (state != VC_STATE_INITIALIZED) {
                SLOG(LOG_ERROR, TAG_VCW, "[ERROR] Invalid State: Current state is not 'Initialized'");
                SLOG(LOG_DEBUG, TAG_VCW, "@@@");
+               pthread_mutex_unlock(&g_w_init_mutex);
                return VC_ERROR_INVALID_STATE;
        }
 
@@ -564,6 +577,7 @@ int vc_widget_prepare(vc_h vc_w)
        if (NULL == widget) {
                SLOG(LOG_ERROR, TAG_VCW, "[ERROR] Fail to get widget handle");
                SLOG(LOG_DEBUG, TAG_VCW, "@@@");
+               pthread_mutex_unlock(&g_w_init_mutex);
                return VC_ERROR_INVALID_STATE;
        }
 
@@ -572,14 +586,15 @@ int vc_widget_prepare(vc_h vc_w)
 
        // Check ecore thread
        if (g_w_prepare_thread && !ecore_thread_check(g_w_prepare_thread)) {
-               ecore_thread_cancel(g_w_prepare_thread);
-               g_w_prepare_thread = NULL;
+               SLOG(LOG_INFO, TAG_VCW, "[INFO] prepare_thread is already runnning");
+               pthread_mutex_unlock(&g_w_init_mutex);
+               return VC_ERROR_NONE;
        }
-       g_w_prepare_canceled = 0;
+       g_ask_to_cancel_preparing = false;
        g_w_prepare_thread = ecore_thread_run(__start_prepare_thread, __end_prepare_thread, __cancel_prepare_thread, (void*)vc_w);
 
        SLOG(LOG_DEBUG, TAG_VCW, "@@@");
-
+       pthread_mutex_unlock(&g_w_init_mutex);
        return VC_ERROR_NONE;
 }
 
@@ -592,36 +607,33 @@ int vc_widget_unprepare(vc_h vc_w)
                return VC_ERROR_NONE;
        }
 
-       int prev_thread_count = ecore_thread_active_get();
-       int curr_thread_count = prev_thread_count;
+       pthread_mutex_lock(&g_w_init_mutex);
        int count = 0;
-       SLOG(LOG_INFO, TAG_VCW, "[Widget] Current thread count(%d)", curr_thread_count);
-
+       SLOG(LOG_WARN, TAG_VCW, "[Widget] prepare_thread info(%p), check(%d)", g_w_prepare_thread, ecore_thread_check(g_w_prepare_thread));
        if (g_w_prepare_thread && !ecore_thread_check(g_w_prepare_thread)) {
-               SLOG(LOG_WARN, TAG_VCW, "[WARNING] Thread is alive. Call cancel thread.");
-               ecore_thread_cancel(g_w_prepare_thread);
+               bool ret = ecore_thread_cancel(g_w_prepare_thread);
+               g_ask_to_cancel_preparing = true;
+               SLOG(LOG_WARN, TAG_VCW, "[WARNING] Thread is alive. The cancel_thread is called, ret(%d)", ret);
        }
 
-       SLOG(LOG_WARN, TAG_VCW, "[Widget] thread info %d %d %d", curr_thread_count, prev_thread_count - curr_thread_count, !ecore_thread_check(g_w_prepare_thread));
-       SLOG(LOG_WARN, TAG_VCW, "[Widget] thread count %d", count);
-       while (0 < curr_thread_count && 1 != prev_thread_count - curr_thread_count && !ecore_thread_check(g_w_prepare_thread)) {
+       while (g_is_prepare_thread_alive) {
                usleep(50000);
 
                if (100 == count) {
-                       SLOG(LOG_WARN, TAG_VCW, "[WARNING!!] Thread is blocked, cnt(%d), thread count(%d)", count, curr_thread_count);
+                       SLOG(LOG_WARN, TAG_VCW, "[WARNING!!] Thread is blocked, cnt(%d)", count);
                        break;
-               } else if (0 == count % 5) {
-                       SLOG(LOG_WARN, TAG_VCW, "[WARNING!!] Thread is alive, cnt(%d), thread count(%d)", count, curr_thread_count);
+               } else if (0 != count && 0 == count % 5) {
+                       SLOG(LOG_WARN, TAG_VCW, "[WARNING!!] Thread is alive, cnt(%d)", count);
                }
                count++;
-               curr_thread_count = ecore_thread_active_get();
        }
-       g_w_prepare_thread = NULL;
+       SLOG(LOG_WARN, TAG_VCW, "[Widget] prepare_thread is terminated");
 
        vc_state_e state;
        if (0 != vc_widget_client_get_state(vc_w, &state)) {
                SLOG(LOG_ERROR, TAG_VCW, "[ERROR] A handle is not available");
                SLOG(LOG_DEBUG, TAG_VCW, "@@@");
+               pthread_mutex_unlock(&g_w_init_mutex);
                return VC_ERROR_INVALID_STATE;
        }
 
@@ -629,6 +641,7 @@ int vc_widget_unprepare(vc_h vc_w)
        if (state != VC_STATE_READY) {
                SLOG(LOG_ERROR, TAG_VCW, "[ERROR] Invalid State: Current state is not 'READY', state(%d)", state);
                SLOG(LOG_DEBUG, TAG_VCW, "@@@");
+               pthread_mutex_unlock(&g_w_init_mutex);
                return VC_ERROR_INVALID_STATE;
        }
 
@@ -638,7 +651,7 @@ int vc_widget_unprepare(vc_h vc_w)
        g_w_notify_state_timer = ecore_timer_add(0, __vc_widget_notify_state_changed, vc_w);
 
        SLOG(LOG_DEBUG, TAG_VCW, "@@@");
-
+       pthread_mutex_unlock(&g_w_init_mutex);
        return VC_ERROR_NONE;
 }
 
index 41deae9..e74003f 100644 (file)
@@ -1439,6 +1439,10 @@ Eina_Bool vcd_cleanup_client_all(void *data)
        __vcd_cleanup_client(VCD_CLIENT_TYPE_WIDGET);
        __vcd_cleanup_client(VCD_CLIENT_TYPE_MANAGER);
 
+       if (0 == vcd_client_get_ref_count()) {
+               SLOG(LOG_DEBUG, TAG_VCD, "[Server] Connected client list is empty");
+               ecore_timer_add(0, __finalize_quit_ecore_loop, NULL);
+       }
 #if 0
        if (0 == vcd_client_get_list(&client_list, &client_count)) {
                SLOG(LOG_DEBUG, TAG_VCD, "@@@ Clean up client ");
@@ -2849,6 +2853,11 @@ int vcd_server_widget_finalize(int pid)
        /* check if pid is valid */
        if (false == vcd_client_widget_is_available(pid)) {
                SLOG(LOG_ERROR, TAG_VCD, "[Server ERROR] pid is NOT valid ");
+               if (0 == vcd_client_get_ref_count()) {
+                       SLOG(LOG_ERROR, TAG_VCD, "[Server] connected client list is empty, vc-service will be terminated");
+                       ecore_timer_add(0, __finalize_quit_ecore_loop, NULL);
+                       return 0;
+               }
                return VCD_ERROR_INVALID_PARAMETER;
        }
 
@@ -2858,7 +2867,7 @@ int vcd_server_widget_finalize(int pid)
        }
 
        if (0 == vcd_client_get_ref_count()) {
-               SLOG(LOG_ERROR, TAG_VCD, "[Server] connected client list is empty");
+               SLOG(LOG_ERROR, TAG_VCD, "[Server] connected client list is empty, vc-service will be terminated");
                ecore_timer_add(0, __finalize_quit_ecore_loop, NULL);
                return 0;
        }