Destroy tts handle always on the main thread 49/288549/1 accepted/tizen/unified/20230221.085046
authorSuyeon Hwang <stom.hwang@samsung.com>
Mon, 20 Feb 2023 02:13:24 +0000 (11:13 +0900)
committerSuyeon Hwang <stom.hwang@samsung.com>
Mon, 20 Feb 2023 02:13:24 +0000 (11:13 +0900)
- Issue:
In C# application, the garbage colletor can destroy tts handle on a sub
thread, and this behavior can make thread safety issues.

- Solution:
The C# garbage collector can release the instance on a sub thread, so
this can make race condition issues. To prevent this kind of issues,
this patch adds a new logic to tts_destroy() function. Through this
change, the handle destruction logic of tts_destroy() will always be
run on a main thread. This change will prevent race condition issues
because the logic insures that every handle destructions are run on a
main thread and they are not destroyed at the same time.

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

index 3df546b..a7b67f3 100644 (file)
@@ -292,12 +292,9 @@ int tts_create(tts_h* tts)
        return TTS_ERROR_NONE;
 }
 
-int tts_destroy(tts_h tts)
+static int destroy_tts_handle(tts_h tts)
 {
-       RETV_IF(TTS_ERROR_NONE != __tts_get_feature_enabled(), TTS_ERROR_NOT_SUPPORTED);
-
-       SLOG(LOG_INFO, TAG_TTSC, "@@@ Destroy TTS");
-
+       SLOG(LOG_INFO, TAG_TTSC, "Destroy TTS handle");
        tts_client_s* client = tts_client_get(tts);
        RETVM_IF(NULL == client, TTS_ERROR_INVALID_PARAMETER, "[ERROR] A handle is not valid. tts(%p)", tts);
 
@@ -367,10 +364,32 @@ int tts_destroy(tts_h tts)
                }
        }
 
-       SLOG(LOG_DEBUG, TAG_TTSC, "@@@");
        return TTS_ERROR_NONE;
 }
 
+static void *destroy_tts_handle_on_main_thread(void* data)
+{
+       SLOG(LOG_INFO, TAG_TTSC, "Destroy on main thread synchronously");
+       tts_h tts = (tts_h)data;
+
+       int ret = destroy_tts_handle(tts);
+       intptr_t p_ret = (intptr_t)ret;
+
+       return (void *)p_ret;
+}
+
+int tts_destroy(tts_h tts)
+{
+       RETV_IF(TTS_ERROR_NONE != __tts_get_feature_enabled(), TTS_ERROR_NOT_SUPPORTED);
+       SLOG(LOG_INFO, TAG_TTSC, "@@@ Destroy TTS");
+
+       intptr_t ret = (intptr_t)ecore_main_loop_thread_safe_call_sync(destroy_tts_handle_on_main_thread, (void *)tts);
+       SLOG(LOG_INFO, TAG_TTSC, "Return value: (%d/%s)", (int)ret, get_error_message((int)ret));
+
+       SLOG(LOG_DEBUG, TAG_TTSC, "@@@");
+       return (int)ret;
+}
+
 int tts_set_mode(tts_h tts, tts_mode_e mode)
 {
        RETV_IF(TTS_ERROR_NONE != __tts_get_feature_enabled(), TTS_ERROR_NOT_SUPPORTED);