From: Hwankyu Jhun Date: Thu, 13 Jun 2019 00:33:01 +0000 (+0900) Subject: Make thread safe code X-Git-Tag: submit/tizen_4.0/20190614.073337~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7f56e770bc78db94eaf98021c9268d47801f2f8f;p=platform%2Fcore%2Fapi%2Fapp-control.git Make thread safe code To avoid concurrent access to the request context handle, this patch synchronizes the launch request. Change-Id: I54daccb570b4afc7dc3b7678185258c99148f7d9 Signed-off-by: Hwankyu Jhun --- diff --git a/src/app_control.c b/src/app_control.c index de50dad..2383976 100644 --- a/src/app_control.c +++ b/src/app_control.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include @@ -73,7 +75,227 @@ typedef struct app_control_request_context_s { void *user_data; } *app_control_request_context_h; +struct reply_info_s { + bundle *b; + aul_svc_result_val result; + void *user_data; +}; + +struct pending_item_s { + int id; + struct reply_info_s *reply_info; +}; + static int app_control_create_reply(bundle *data, struct app_control_s **app_control); +static void app_control_request_result_broker(bundle *appsvc_bundle, + int appsvc_request_code, aul_svc_result_val appsvc_result, + void *appsvc_data); + +static pthread_mutex_t __mutex = PTHREAD_MUTEX_INITIALIZER; +static GList *__pending_list; + +static int __generate_request_id(void) +{ + static int id; + + g_atomic_int_inc(&id); + return id; +} + +static void __destroy_reply_info(gpointer data) +{ + struct reply_info_s *info = data; + + if (!info) + return; + + if (info->b) + bundle_free(info->b); + + free(info); +} + +static struct reply_info_s *__create_reply_info(bundle *b, + aul_svc_result_val result, void *user_data) +{ + struct reply_info_s *info; + + info = calloc(1, sizeof(struct reply_info_s)); + if (!info) { + LOGE("Out of memory"); + return NULL; + } + + info->b = bundle_dup(b); + if (!info->b) { + LOGE("Failed to duplicate bundle"); + free(info); + return NULL; + } + + info->result = result; + info->user_data = user_data; + + return info; +} + +static void __destroy_pending_item(gpointer data) +{ + struct pending_item_s *item = data; + + if (!item) + return; + + if (item->reply_info) + __destroy_reply_info(item->reply_info); + + free(item); +} + +static struct pending_item_s *__create_pending_item(int id) +{ + struct pending_item_s *item; + + item = calloc(1, sizeof(struct pending_item_s)); + if (!item) { + LOGE("Out of memory"); + return NULL; + } + + item->id = id; + + return item; +} + +static void __add_pending_item(int id) +{ + struct pending_item_s *item; + + item = __create_pending_item(id); + if (!item) + return; + + pthread_mutex_lock(&__mutex); + __pending_list = g_list_prepend(__pending_list, item); + pthread_mutex_unlock(&__mutex); +} + +static void __remove_pending_item(int id) +{ + struct pending_item_s *item; + GList *iter; + + pthread_mutex_lock(&__mutex); + iter = __pending_list; + while (iter) { + item = (struct pending_item_s *)iter->data; + iter = g_list_next(iter); + if (item->id == id) { + __pending_list = g_list_remove(__pending_list, item); + __destroy_pending_item(item); + break; + } + } + pthread_mutex_unlock(&__mutex); +} + +static struct pending_item_s *__pop_pending_item(int id) +{ + struct pending_item_s *item; + GList *iter; + + pthread_mutex_lock(&__mutex); + iter = __pending_list; + while (iter) { + item = (struct pending_item_s *)iter->data; + iter = g_list_next(iter); + if (item->id == id) { + __pending_list = g_list_remove(__pending_list, item); + pthread_mutex_unlock(&__mutex); + return item; + } + } + pthread_mutex_unlock(&__mutex); + + return NULL; +} + +static gboolean __process_pending_item(gpointer data) +{ + struct pending_item_s *item = data; + struct reply_info_s *reply_info; + + if (!item) + return G_SOURCE_REMOVE; + + if (item->reply_info) { + reply_info = item->reply_info; + app_control_request_result_broker(reply_info->b, item->id, + reply_info->result, reply_info->user_data); + __destroy_reply_info(reply_info); + item->reply_info = NULL; + } + __destroy_pending_item(item); + + return G_SOURCE_REMOVE; +} + +static void __flush_pending_item(int id) +{ + struct pending_item_s *item; + + item = __pop_pending_item(id); + if (!item) + return; + + if (!item->reply_info) { + __destroy_pending_item(item); + return; + } + + g_idle_add(__process_pending_item, item); +} + +static bool __exist_pending_item(int id) +{ + struct pending_item_s *item; + GList *iter; + + pthread_mutex_lock(&__mutex); + iter = __pending_list; + while (iter) { + item = (struct pending_item_s *)iter->data; + iter = g_list_next(iter); + if (item->id == id) { + pthread_mutex_unlock(&__mutex); + return true; + } + } + pthread_mutex_unlock(&__mutex); + + return false; +} + +static int __pending_item_set_reply_info(int id, struct reply_info_s *info) +{ + struct pending_item_s *item; + GList *iter; + + pthread_mutex_lock(&__mutex); + iter = __pending_list; + while (iter) { + item = (struct pending_item_s *)iter->data; + iter = g_list_next(iter); + if (item->id == id) { + item->reply_info = info; + pthread_mutex_unlock(&__mutex); + return 0; + } + } + pthread_mutex_unlock(&__mutex); + + return -1; +} static const char *app_control_error_to_string(app_control_error_e error) { @@ -137,10 +359,12 @@ static int app_control_validate(app_control_h app_control) return APP_CONTROL_ERROR_NONE; } -static int app_control_new_id() +static int app_control_new_id(void) { - static int sid = 0; - return sid++; + static int sid; + + g_atomic_int_inc(&sid); + return sid; } int app_control_validate_internal_key(const char *key) @@ -163,12 +387,28 @@ static void app_control_request_result_broker(bundle *appsvc_bundle, int appsvc_ app_control_result_e result; void *user_data; app_control_reply_cb reply_cb; + struct reply_info_s *info; + int ret; if (appsvc_data == NULL) { app_control_error(APP_CONTROL_ERROR_INVALID_PARAMETER, __FUNCTION__, "invalid app_control reply"); return; } + if (__exist_pending_item(appsvc_request_code)) { + info = __create_reply_info(appsvc_bundle, + appsvc_result, appsvc_data); + if (info) { + ret = __pending_item_set_reply_info(appsvc_request_code, + info); + if (ret == 0) { + LOGW("Reply info is pending"); + return; + } + __destroy_reply_info(info); + } + } + if (app_control_create_reply(appsvc_bundle, &reply) != 0) { app_control_error(APP_CONTROL_ERROR_INVALID_PARAMETER, __FUNCTION__, "failed to create app_control reply"); return; @@ -714,6 +954,7 @@ int app_control_send_launch_request(app_control_h app_control, app_control_reply bool implicit_default_operation = false; int launch_pid; app_control_request_context_h request_context = NULL; + int req_id; int ret; if (app_control_validate(app_control)) @@ -760,12 +1001,18 @@ int app_control_send_launch_request(app_control_h app_control, app_control_reply if (implicit_default_operation == true) aul_svc_set_operation(app_control->data, APP_CONTROL_OPERATION_DEFAULT); - launch_pid = aul_svc_run_service_for_uid(app_control->data, app_control->id, callback ? app_control_request_result_broker : NULL, request_context, getuid()); + req_id = __generate_request_id(); + if (request_context) + __add_pending_item(req_id); + + launch_pid = aul_svc_run_service_for_uid(app_control->data, req_id, callback ? app_control_request_result_broker : NULL, request_context, getuid()); if (implicit_default_operation == true) bundle_del(app_control->data, BUNDLE_KEY_OPERATION); if (launch_pid < 0) { if (request_context) { + __remove_pending_item(req_id); + if (request_context->app_control) app_control_destroy(request_context->app_control); @@ -804,6 +1051,9 @@ int app_control_send_launch_request(app_control_h app_control, app_control_reply aul_add_caller_cb(launch_pid, __update_launch_pid, app_control); } + if (request_context) + __flush_pending_item(req_id); + return APP_CONTROL_ERROR_NONE; }