From: Hwankyu Jhun Date: Thu, 13 Jun 2019 00:33:01 +0000 (+0900) Subject: Make thread safe code X-Git-Tag: accepted/tizen/unified/20190618.045931~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F93%2F207793%2F4;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 b899a4f..033c570 100644 --- a/src/app_control.c +++ b/src/app_control.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -80,6 +81,7 @@ typedef struct app_control_request_context_s { } *app_control_request_context_h; struct launch_request_s { + int id; bool implicit_default_operation; app_control_request_context_h request_context; app_control_h app_control; @@ -97,9 +99,298 @@ struct app_control_action_s { void *user_data; }; +struct reply_info_s { + bundle *b; + aul_svc_result_val result; + void *user_data; +}; + +struct result_info_s { + int result; + void *user_data; +}; + +struct pending_item_s { + int id; + struct reply_info_s *reply_info; + struct result_info_s *result_info; +}; + typedef int (*launch_request_handler)(struct launch_request_s *req); static int app_control_create_reply(bundle *data, struct app_control_s **app_control); +static void app_control_request_reply_broker(bundle *appsvc_bundle, + int appsvc_request_code, aul_svc_result_val appsvc_result, + void *appsvc_data); +static void app_control_request_result_broker(int request_code, int result, + void *user_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_result_info(gpointer data) +{ + struct result_info_s *info = data; + + if (!info) + return; + + free(info); +} + +static struct result_info_s *__create_result_info(int result, + void *user_data) +{ + struct result_info_s *info; + + info = calloc(1, sizeof(struct result_info_s)); + if (!info) { + LOGE("Out of memory"); + return NULL; + } + + info->result = result; + info->user_data = user_data; + + return info; +} + +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); + + if (item->result_info) + __destroy_result_info(item->result_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 result_info_s *result_info; + struct reply_info_s *reply_info; + + if (!item) + return G_SOURCE_REMOVE; + + if (item->result_info) { + result_info = item->result_info; + app_control_request_result_broker(item->id, + result_info->result, result_info->user_data); + __destroy_result_info(result_info); + item->result_info = NULL; + return G_SOURCE_CONTINUE; + } + + if (item->reply_info) { + reply_info = item->reply_info; + app_control_request_reply_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 && !item->result_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 int __pending_item_set_result_info(int id, struct result_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->result_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) { @@ -163,10 +454,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) @@ -212,12 +505,28 @@ static void app_control_request_reply_broker(bundle *appsvc_bundle, int appsvc_r 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; @@ -1032,6 +1341,21 @@ static void app_control_request_result_broker(int request_code, int result, app_control_request_context_h request_context; app_control_error_e error = APP_CONTROL_ERROR_NONE; app_control_h app_control; + struct result_info_s *info; + int ret; + + if (__exist_pending_item(request_code)) { + info = __create_result_info(result, user_data); + if (info) { + ret = __pending_item_set_result_info(request_code, + info); + if (ret == 0) { + LOGW("Result info is pending"); + return; + } + __destroy_result_info(info); + } + } request_context = (app_control_request_context_h)user_data; if (request_context == NULL) { @@ -1133,14 +1457,16 @@ static int __launch_request_send(struct launch_request_s *req) APP_CONTROL_OPERATION_DEFAULT); } + if (req->request_context) + __add_pending_item(req->id); + if (req->result_cb) { ret = aul_svc_send_launch_request_for_uid(app_control->data, - app_control->id, reply_cb, result_cb, + req->id, reply_cb, result_cb, req->request_context, getuid()); - } else { ret = aul_svc_run_service_for_uid(app_control->data, - app_control->id, reply_cb, + req->id, reply_cb, req->request_context, getuid()); } @@ -1148,6 +1474,8 @@ static int __launch_request_send(struct launch_request_s *req) bundle_del(req->app_control->data, BUNDLE_KEY_OPERATION); if (ret < 0) { + if (req->request_context) + __remove_pending_item(req->id); return app_control_error(__launch_request_convert_error(ret), __FUNCTION__, NULL); } @@ -1185,14 +1513,17 @@ static int __launch_request_complete(struct launch_request_s *req) if (request_context) __copy_callee_info(request_context->app_control, app_control); - if (req->result_cb) + if (req->result_cb) { + __flush_pending_item(req->id); return APP_CONTROL_ERROR_NONE; + } if (!request_context) return APP_CONTROL_ERROR_NONE; __handle_app_started_result(app_control, request_context->reply_cb ? request_context : NULL); + __flush_pending_item(req->id); return APP_CONTROL_ERROR_NONE; } @@ -1226,6 +1557,7 @@ static int __send_launch_request(app_control_h app_control, __FUNCTION__, NULL); } + req.id = __generate_request_id(); for (i = 0; i < ARRAY_SIZE(handlers); i++) { if (handlers[i]) { ret = handlers[i](&req); @@ -1767,7 +2099,7 @@ static int __launch_request_send_sync(struct launch_request_s *req) } ret = aul_svc_send_launch_request_sync_for_uid(request->data, - request->id, &reply_bundle, &appsvc_result, getuid()); + req->id, &reply_bundle, &appsvc_result, getuid()); if (req->implicit_default_operation) bundle_del(request->data, BUNDLE_KEY_OPERATION); @@ -1814,6 +2146,7 @@ static int __send_launch_request_sync(app_control_h request, __FUNCTION__, NULL); } + req.id = __generate_request_id(); for (i = 0; i < ARRAY_SIZE(handlers); i++) { if (handlers[i]) { ret = handlers[i](&req);