Make thread safe code 35/207835/2
authorHwankyu Jhun <h.jhun@samsung.com>
Thu, 13 Jun 2019 00:33:01 +0000 (09:33 +0900)
committerHwankyu Jhun <h.jhun@samsung.com>
Thu, 13 Jun 2019 22:34:30 +0000 (07:34 +0900)
To avoid concurrent access to the request context handle, this patch
synchronizes the launch request.

Change-Id: I54daccb570b4afc7dc3b7678185258c99148f7d9
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
src/app_control.c

index de50dad31828a1dafae7264fc62d48a1e2cc51f1..238397601c2019c8a55a9e586e8516a635994e70 100644 (file)
@@ -19,6 +19,8 @@
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
+#include <pthread.h>
+#include <glib.h>
 
 #include <bundle.h>
 #include <bundle_internal.h>
@@ -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;
 }