Support asynchronous plugin initializer
[platform/core/connectivity/zigbee-manager.git] / zigbee-daemon / zigbee-lib / src / zblib_service.c
index 91aee37..72e26e7 100644 (file)
 #include <zblib_service.h>
 #include <zblib_plugin.h>
 #include <zblib_service_interface.h>
+#include <zblib_request.h>
+#include <zblib_driver.h>
+#include <zblib_driver_manager.h>
+
+struct _zblib_async_init_info {
+       gboolean is_initialized; /**< Does initialization succeeded? */
+       gboolean is_finished; /**< Does initialization finished? */
+
+       ZigBeePlugin *plugin; /**< ZigBee plugin */
+       void *user_data; /**< User data */
+};
 
 /**< ZigBee Service object */
 struct zblib_service_type {
@@ -30,31 +41,118 @@ struct zblib_service_type {
 
        GSList *interface_objs; /**< ZigBee Service interface objects */
        GSList *plugins; /**< ZigBee plug-ins */
+
+       GHashTable *request_table; /**< Request Hash table */
+       guint request_id; /**< Request ID */
+
+       GSList *async_initializer; /**< Hash table for asynchronous initializer */
+       zblib_plugin_init_finished_cb callback; /**< Callback */
 };
 
+static GSList *__zblib_service_ref_async_initializer(ZigBeeService* service)
+{
+       zblib_check_null_ret_error("service", service, NULL);
+
+       return service->async_initializer;
+}
+
+static void __zblib_service_set_async_initializer(ZigBeeService* service, GSList* list)
+{
+       zblib_check_null_ret("service", service);
+
+       service->async_initializer = list;
+}
+
+static void __on_zblib_init_async_finished(gboolean result, void *user_data)
+{
+       GSList *list_async = NULL;
+       ZigBeeService *service = NULL;
+       ZigBeePlugin *plugin = NULL;
+       struct _zblib_async_init_info *info = (struct _zblib_async_init_info*)user_data;
+       char *plugin_name = NULL;
+
+       int i = 0;
+       int _finished_count = 0;
+       int _succeeded_count = 0;
+
+       zblib_check_null_ret("info", info);
+
+       plugin = info->plugin;
+       service = zblib_plugin_ref_service(plugin);
+       plugin_name = zblib_plugin_get_plugin_name(plugin);
+
+       zblib_check_null_ret("service", service);
+
+       info->is_finished = TRUE;
+       if (result) {
+               Z_LOGD("Plugin [%s] succeeded async init", plugin_name);
+               info->is_initialized = TRUE;
+       } else {
+               Z_LOGE("Plugin [%s] failed to init !", plugin_name);
+       }
+       g_free(plugin_name);
+
+       /* Check all async initializer list */
+       list_async = __zblib_service_ref_async_initializer(service);
+       while (list_async != NULL) {
+               /* Initialize each plug-in */
+               struct _zblib_async_init_info *in =
+                               (struct _zblib_async_init_info *)(list_async->data);
+               i++;
+               if (G_UNLIKELY(NULL == in)) {
+                       Z_LOGE("Invalid parameter !");
+                       list_async = g_slist_next(list_async);
+                       continue;
+               }
+
+               if (in->is_finished)
+                       _finished_count++;
+               if (in->is_initialized)
+                       _succeeded_count++;
+
+               list_async = g_slist_next(list_async);
+       }
+
+       if (i == _finished_count) {
+               gboolean ret = TRUE;
+               guint driver_noti_id = (ZBLIB_DRIVER_TYPE_MANAGER << 24)
+                               | ZBLIB_MANAGER_NOTI_ZIGBEE_ENABLED;
+
+               if (_finished_count == _succeeded_count) {
+                       /* All initializer finished successfully */
+                       Z_LOGD("All async init finished !");
+                       ret = TRUE;
+               } else {
+                       /* Some initializers are failed */
+                       Z_LOGE("There are some failed plugin initializer !");
+                       ret = FALSE;
+               }
+               /* Notify whether zigbee service is enabled or not */
+               zblib_plugin_send_notification(plugin,
+                       driver_noti_id, &ret, sizeof(ret));
+       }
+}
+
 static void *__zblib_service_load_plugin(gchar *filename,
-       struct zblib_plugin_descriptor **descriptor_out)
+       ZblibPluginDescriptor_t **descriptor_out)
 {
-       struct zblib_plugin_descriptor *descriptor = NULL;
+       ZblibPluginDescriptor_t *descriptor = NULL;
        void *handle = NULL;
        struct stat stat_buf;
        char file_date[27];
 
-       if (descriptor_out == NULL) {
-               Z_LOGE("descriptor_out is NULL!!!");
-               return FALSE;
-       }
+       zblib_check_null_ret_error("descriptor_out", descriptor_out, NULL);
 
        /* Open .so */
        handle = dlopen(filename, RTLD_LAZY);
-       if (NULL == handle) {
+       if (G_UNLIKELY(NULL == handle)) {
                Z_LOGE("dlopen() failed:[%s]", filename);
                return NULL;
        }
 
        /* Get symbol - "zigbee_plugin_descriptor" */
        descriptor = dlsym(handle, "zigbee_plugin_descriptor");
-       if (NULL == descriptor) {
+       if (G_UNLIKELY(NULL == descriptor)) {
                Z_LOGE("dlsym() failed:[%s]", "plugin_define_desc");
                dlclose(handle);
                return NULL;
@@ -93,16 +191,17 @@ static void *__zblib_service_load_plugin(gchar *filename,
 
 static gboolean __zblib_service_init_plugin(ZigBeePlugin *plugin)
 {
-       const struct zblib_plugin_descriptor *descriptor = zblib_plugin_get_descriptor(plugin);
+       const ZblibPluginDescriptor_t *descriptor = zblib_plugin_get_descriptor(plugin);
 
-       if ((descriptor == NULL) || (descriptor->init == NULL)) {
-               Z_LOGE("descriptor OR init function is NULL!!!");
+       zblib_check_null_ret_error("descriptor", descriptor, FALSE);
+       if (NULL == descriptor->init) {
+               Z_LOGD("descriptor->init is NULL, trying async init");
                return FALSE;
        }
 
-       if (descriptor->init(plugin) == FALSE) {
+       if (G_UNLIKELY(FALSE == descriptor->init(plugin))) {
                char *plugin_name = zblib_plugin_get_plugin_name(plugin);
-               if (NULL != plugin_name) {
+               if (G_UNLIKELY(NULL != plugin_name)) {
                        Z_LOGE("plugin(%s) init failed!", plugin_name);
                        g_free(plugin_name);
                }
@@ -112,23 +211,60 @@ static gboolean __zblib_service_init_plugin(ZigBeePlugin *plugin)
        return TRUE;
 }
 
-static gboolean __zblib_service_unload_plugin(ZigBeePlugin *plugin)
+static gboolean __zblib_service_init_async_plugin(ZigBeePlugin *plugin,
+               zblib_plugin_init_finished_cb callback, void *user_data)
 {
-       const struct zblib_plugin_descriptor *descriptor = zblib_plugin_get_descriptor(plugin);
+       const ZblibPluginDescriptor_t *descriptor = zblib_plugin_get_descriptor(plugin);
        char *plugin_name = zblib_plugin_get_plugin_name(plugin);
 
-       if ((descriptor == NULL) || (descriptor->unload == NULL)) {
-               Z_LOGE("descriptor OR unload function is NULL!!!");
+       zblib_check_null_ret_error("descriptor", descriptor, FALSE);
+       zblib_check_null_ret_error("descriptor->init_async", descriptor->init_async, FALSE);
+
+       if (G_UNLIKELY(NULL != plugin_name))
+               plugin_name = g_strdup("NONAME");
+
+       if (G_UNLIKELY(FALSE == descriptor->init_async(plugin, callback, user_data))) {
+               Z_LOGE("plugin(%s) init failed!", plugin_name);
+               g_free(plugin_name);
                return FALSE;
        }
 
+       g_free(plugin_name);
+       return TRUE;
+}
+
+static gboolean __zblib_service_unload_plugin(ZigBeePlugin *plugin)
+{
+       const ZblibPluginDescriptor_t *descriptor = zblib_plugin_get_descriptor(plugin);
+       char *plugin_name = NULL;
+
+       zblib_check_null_ret_error("descriptor", descriptor, FALSE);
+       zblib_check_null_ret_error("descriptor->unload", descriptor->unload, FALSE);
+
+       plugin_name = zblib_plugin_get_plugin_name(plugin);
 
        descriptor->unload(plugin);
        Z_LOGI("plugin(%s) unloaded!", plugin_name);
 
+       g_free(plugin_name);
+
        return TRUE;
 }
 
+static void __zblib_service_remove_request_table_iter(gpointer key,
+       gpointer value, gpointer user_data)
+{
+       ZigBeeServiceInterface *service_interface = (ZigBeeServiceInterface *)user_data;
+       gint request_id = (gint)key;
+
+       NOT_USED(value);
+
+       zblib_check_null_ret("service_interface", service_interface);
+
+       Z_LOGD("Removing request id [%d]", request_id);
+       zblib_request_free(service_interface, request_id);
+}
+
 ZigBeeService *zblib_service_new()
 {
        ZigBeeService *service;
@@ -137,20 +273,52 @@ ZigBeeService *zblib_service_new()
 
        /* Create g-main loop */
        service->main_loop = g_main_loop_new(NULL, FALSE);
-       if (service->main_loop == NULL) {
+       if (G_UNLIKELY(NULL == service->main_loop)) {
                Z_LOGE("g-main loop creation failed!!!");
                g_free(service);
                return NULL;
        }
 
+       /* Create request hash table */
+       service->request_table = g_hash_table_new_full(g_direct_hash,
+               g_direct_equal, NULL, NULL);
+
        return service;
 }
 
 void zblib_service_free(ZigBeeService *service)
 {
-       if (service == NULL) {
-               Z_LOGE("service is NULL");
-               return;
+       zblib_check_null_ret("service", service);
+
+       if (service->request_table) {
+               GSList *interface_objs = NULL;
+               ZigBeeServiceInterface *service_interface = NULL;
+
+               interface_objs = service->interface_objs;
+               if (NULL == interface_objs) {
+                       Z_LOGE("interface_objs is NULL");
+               } else {
+                       while (interface_objs) {
+                               service_interface = (ZigBeeServiceInterface *)interface_objs->data;
+
+                               /* Remove left request */
+                               g_hash_table_foreach(service->request_table,
+                                               __zblib_service_remove_request_table_iter,
+                                               service_interface);
+
+                               /* Move to next service interface */
+                               interface_objs = g_slist_next(interface_objs);
+                       }
+                       g_hash_table_remove_all(service->request_table);
+                       g_hash_table_destroy(service->request_table);
+                       service->request_table = NULL;
+               }
+       }
+
+       /* Free async initializer */
+       if (service->async_initializer) {
+               g_slist_free(service->async_initializer);
+               service->async_initializer = NULL;
        }
 
        /* Free plug-ins */
@@ -168,10 +336,8 @@ void zblib_service_free(ZigBeeService *service)
 
 gboolean zblib_service_run(ZigBeeService *service)
 {
-       if ((service == NULL) || (service->main_loop == NULL)) {
-               Z_LOGE("service or mainloop is NULL");
-               return FALSE;
-       }
+       zblib_check_null_ret_error("service", service, FALSE);
+       zblib_check_null_ret_error("service->main_loop", service->main_loop, FALSE);
 
        g_main_loop_run(service->main_loop);
 
@@ -180,10 +346,8 @@ gboolean zblib_service_run(ZigBeeService *service)
 
 gboolean zblib_service_exit(ZigBeeService *service)
 {
-       if ((service == NULL) || (service->main_loop == NULL)) {
-               Z_LOGE("service or mainloop is NULL");
-               return FALSE;
-       }
+       zblib_check_null_ret_error("service", service, FALSE);
+       zblib_check_null_ret_error("service->main_loop", service->main_loop, FALSE);
 
        g_main_loop_quit(service->main_loop);
 
@@ -194,10 +358,8 @@ gboolean zblib_service_add_plugin(ZigBeeService *service, ZigBeePlugin *plugin)
 {
        gchar *plugin_name;
 
-       if ((service == NULL) || (plugin == NULL)) {
-               Z_LOGE("service: [%p] plugin: [%p]", service, plugin);
-               return FALSE;
-       }
+       zblib_check_null_ret_error("service", service, FALSE);
+       zblib_check_null_ret_error("plugin", plugin, FALSE);
 
        plugin_name = zblib_plugin_get_plugin_name(plugin);
 
@@ -211,14 +373,15 @@ gboolean zblib_service_add_plugin(ZigBeeService *service, ZigBeePlugin *plugin)
 
 gboolean zblib_service_remove_plugin(ZigBeeService *service, ZigBeePlugin *plugin)
 {
-       if ((service == NULL) || (plugin == NULL)) {
-               Z_LOGE("service: [%p] plugin: [%p]", service, plugin);
-               return FALSE;
-       }
+       zblib_check_null_ret_error("service", service, FALSE);
+       zblib_check_null_ret_error("plugin", plugin, FALSE);
 
        /* Specific vendor plug-in would be removed */
        service->plugins = g_slist_remove(service->plugins, plugin);
 
+       /* Deinitialize plugin */
+       zblib_plugin_free(plugin);
+
        return TRUE;
 }
 
@@ -228,18 +391,16 @@ gboolean zblib_service_load_plugins(ZigBeeService *service, const char *plugin_p
        gchar *filename = NULL;
        GDir *dir = NULL;
        void *handle = NULL;
-       struct zblib_plugin_descriptor *descriptor = NULL;
+       ZblibPluginDescriptor_t *descriptor = NULL;
        ZigBeePlugin *plugin = NULL;
        gboolean ret;
 
-       if ((service == NULL) || (plugin_path == NULL)) {
-               Z_LOGE("service: [%p] plugin_path: [%p]", service, plugin_path);
-               return FALSE;
-       }
+       zblib_check_null_ret_error("service", service, FALSE);
+       zblib_check_null_ret_error("plugin_path", plugin_path, FALSE);
 
        /* Open plug-in directory */
        dir = g_dir_open(plugin_path, 0, NULL);
-       if (dir == NULL) {
+       if (G_UNLIKELY(dir == NULL)) {
                Z_LOGE("Directory open failed!");
                return FALSE;
        }
@@ -254,21 +415,21 @@ gboolean zblib_service_load_plugins(ZigBeeService *service, const char *plugin_p
 
                /* Load plug-in */
                handle = __zblib_service_load_plugin(filename, &descriptor);
-               if (NULL == handle) {
+               if (G_UNLIKELY(NULL == handle)) {
                        g_free(filename);
                        continue;
                }
 
                /* Create new plug-in */
                plugin = zblib_plugin_new(service, filename, descriptor, handle);
-               if (NULL == plugin) {
+               if (G_UNLIKELY(NULL == plugin)) {
                        g_free(filename);
                        continue;
                }
 
                /* Add new plug-in */
                ret = zblib_service_add_plugin(service, plugin);
-               if (FALSE == ret) {
+               if (G_UNLIKELY(FALSE == ret)) {
                        zblib_plugin_free(plugin);
                }
 
@@ -282,23 +443,74 @@ gboolean zblib_service_load_plugins(ZigBeeService *service, const char *plugin_p
 gboolean zblib_service_initialize_plugins(ZigBeeService *service)
 {
        GSList *list;
+       GSList *list_async;
 
-       if (service == NULL) {
-               Z_LOGE("service is NULL");
-               return FALSE;
-       }
+       zblib_check_null_ret_error("service", service, FALSE);
 
        /* Refer plug-in list */
        list = zblib_service_ref_plugins(service);
+       list_async = __zblib_service_ref_async_initializer(service);
        while (list != NULL) {
                /* Initialize each plug-in */
-               if (G_UNLIKELY(FALSE == __zblib_service_init_plugin((ZigBeePlugin *)(list->data)))) {
-                       list = g_slist_next(list);
-                       continue;
+               ZigBeePlugin *plugin = (ZigBeePlugin *)(list->data);
+               if (FALSE == __zblib_service_init_plugin(plugin)) {
+                       /* If there is no initializer, it should have asynchronous one */
+                       const ZblibPluginDescriptor_t *descriptor =
+                                       zblib_plugin_get_descriptor(plugin);
+                       if (NULL != descriptor->init_async) {
+                               /* Register async initializer */
+                               struct _zblib_async_init_info *info =
+                                       g_try_new0(struct _zblib_async_init_info, 1);
+                               if(NULL == info) {
+                                       Z_LOGE("Fatal : Failed to allocate memory");
+                                       return FALSE;
+                               }
+                               info->is_finished = FALSE;
+                               info->is_initialized = FALSE;
+                               info->plugin = plugin;
+                               info->user_data = NULL;
+
+                               list_async = g_slist_append(list_async, info);
+                       } else {
+                               Z_LOGE("Fatal : Failed to initialize plugin");
+                               return FALSE;
+                       }
                }
                list = g_slist_next(list);
        }
 
+       __zblib_service_set_async_initializer(service, list_async);
+
+       return TRUE;
+}
+
+gboolean zblib_service_initialize_async_plugins(ZigBeeService *service)
+{
+       GSList *list_async;
+
+       zblib_check_null_ret_error("service", service, FALSE);
+
+       /* Refer async initializer list */
+       list_async = __zblib_service_ref_async_initializer(service);
+       while (list_async != NULL) {
+               /* Initialize each plug-in */
+               struct _zblib_async_init_info *info =
+                               (struct _zblib_async_init_info *)(list_async->data);
+
+               if (G_UNLIKELY(NULL == info)) {
+                       Z_LOGE("Invalid parameter !");
+                       list_async = g_slist_next(list_async);
+                       continue;
+               }
+
+               if (G_UNLIKELY(FALSE == __zblib_service_init_async_plugin(
+                                       info->plugin, __on_zblib_init_async_finished, info))) {
+                       Z_LOGE("Fatal : Failed to initialize mandatory plugin");
+                       return FALSE;
+               }
+               list_async = g_slist_next(list_async);
+       }
+
        return TRUE;
 }
 
@@ -306,10 +518,7 @@ gboolean zblib_service_unload_plugins(ZigBeeService *service)
 {
        GSList *list;
 
-       if (service == NULL) {
-               Z_LOGE("service is NULL");
-               return FALSE;
-       }
+       zblib_check_null_ret_error("service", service, FALSE);
 
        list = zblib_service_ref_plugins(service);
        while (list != NULL) {
@@ -330,10 +539,7 @@ gboolean zblib_service_unload_plugins(ZigBeeService *service)
 
 GSList *zblib_service_ref_plugins(ZigBeeService *service)
 {
-       if (service == NULL) {
-               Z_LOGE("service is NULL");
-               return NULL;
-       }
+       zblib_check_null_ret_error("service", service, NULL);
 
        return service->plugins;
 }
@@ -343,10 +549,8 @@ gboolean zblib_service_add_service_interface(ZigBeeService *service,
 {
        gchar *object_name;
 
-       if ((service == NULL) || (service_interface == NULL)) {
-               Z_LOGE("service: [%p] service_interface: [%p]", service, service_interface);
-               return FALSE;
-       }
+       zblib_check_null_ret_error("service", service, FALSE);
+       zblib_check_null_ret_error("service_interface_name", service_interface, FALSE);
 
        object_name = zblib_service_interface_get_name(service_interface);
 
@@ -363,10 +567,8 @@ gboolean zblib_service_add_service_interface(ZigBeeService *service,
 gboolean zblib_service_remove_service_interface(ZigBeeService *service,
        ZigBeeServiceInterface *service_interface)
 {
-       if ((service == NULL) || (service_interface == NULL)) {
-               Z_LOGE("service: [%p] service_interface: [%p]", service, service_interface);
-               return FALSE;
-       }
+       zblib_check_null_ret_error("service", service, FALSE);
+       zblib_check_null_ret_error("service_interface_name", service_interface, FALSE);
 
        /*
         * service interface object would be removed
@@ -385,10 +587,8 @@ ZigBeeServiceInterface *zblib_service_ref_service_interface(ZigBeeService *servi
 
        GSList *list;
 
-       if ((service == NULL) || (service_interface_name == NULL)) {
-               Z_LOGE("service: [%p] service_interface_name: [%p]", service, service_interface_name);
-               return NULL;
-       }
+       zblib_check_null_ret_error("service", service, NULL);
+       zblib_check_null_ret_error("service_interface_name", service_interface_name, NULL);
 
        list = service->interface_objs;
        while (list) {
@@ -402,11 +602,12 @@ ZigBeeServiceInterface *zblib_service_ref_service_interface(ZigBeeService *servi
                        service_interface = tmp_service_interface;
                        break;
                }
+               g_free(object_name);
 
                list = g_slist_next(list);
        }
 
-       if (service_interface == NULL) {
+       if (NULL == service_interface) {
                Z_LOGE("Service interface object of name '%s' not found!",
                        service_interface_name);
                return NULL;
@@ -417,3 +618,83 @@ ZigBeeServiceInterface *zblib_service_ref_service_interface(ZigBeeService *servi
        return service_interface;
 }
 
+GHashTable *zblib_service_ref_request_hash_table(ZigBeeService *service)
+{
+       zblib_check_null_ret_error("service", service, NULL);
+
+       return service->request_table;
+}
+
+gint zblib_service_generate_request_id(ZigBeeService *service)
+{
+       zblib_check_null_ret_error("service", service, -1);
+
+       /* Increment request ID */
+       service->request_id++;
+
+       return (gint)service->request_id;
+}
+
+gboolean zblib_service_dispatch_request(ZigBeeService *service,
+       guint request_id)
+{
+       ZigBeePlugin *plugin = NULL;
+       GSList *plugin_list = NULL;
+       gboolean ret = FALSE;
+
+       zblib_check_null_ret_error("service", service, FALSE);
+
+       /* Fetch plugin_list */
+       plugin_list = service->plugins;
+       zblib_check_null_ret_error("plugin_list", plugin_list, FALSE);
+
+       while (plugin_list) {
+               plugin = (ZigBeePlugin *)plugin_list->data;
+
+               /* Dispatch request to plugin */
+               ret = zblib_plugin_dispatch_request(plugin, request_id);
+
+               /* Move to next plugin */
+               plugin_list = g_slist_next(plugin_list);
+       }
+
+       return ret;
+}
+
+void zblib_service_send_response(ZigBeeService *service,
+       guint request_id, gpointer resp_data, guint resp_data_len)
+{
+       ZigBeeServiceInterface *service_interface = NULL;
+
+       zblib_check_null_ret("service", service);
+
+       service_interface = zblib_request_ref_service_interface(service, request_id);
+       zblib_check_null_ret("service_interface", service_interface);
+
+       /* Send response to service interface */
+       zblib_service_interface_send_response(service_interface,
+               request_id, resp_data, resp_data_len);
+}
+
+void zblib_service_send_notification(ZigBeeService *service,
+       guint noti_id, gpointer noti_data, guint noti_data_len)
+{
+       GSList *interface_objs = NULL;
+       ZigBeeServiceInterface *service_interface = NULL;
+
+       zblib_check_null_ret("service", service);
+
+       interface_objs = service->interface_objs;
+       zblib_check_null_ret("interface_objs", interface_objs);
+
+       while (interface_objs) {
+               service_interface = (ZigBeeServiceInterface *)interface_objs->data;
+
+               /* Send notification to service interface */
+               zblib_service_interface_send_notification(service_interface,
+                       noti_id, noti_data, noti_data_len);
+
+               /* Move to next service interface */
+               interface_objs = g_slist_next(interface_objs);
+       }
+}