From d568797ecbc98b9bbf7d537690c326f88f07424d Mon Sep 17 00:00:00 2001 From: Jiwan Kim Date: Mon, 3 Apr 2017 15:33:56 +0900 Subject: [PATCH 1/1] Support asynchronous plugin initializer - To support firmware update on plugin initialize time, asynchronous init function is required. - Add support logic for async initializer. Change-Id: Ie8631a62c0fdb97cef87383bf075e3e346880a97 Signed-off-by: Jiwan Kim --- zigbee-daemon/src/main.c | 15 +- .../src/zigbee_service_dbus_interface.c | 47 +++-- zigbee-daemon/zigbee-lib/include/zblib.h | 1 + .../zigbee-lib/include/zblib_driver_manager.h | 27 +++ zigbee-daemon/zigbee-lib/include/zblib_plugin.h | 6 +- zigbee-daemon/zigbee-lib/include/zblib_service.h | 1 + zigbee-daemon/zigbee-lib/src/zblib_service.c | 190 ++++++++++++++++++++- zigbee-daemon/zigbee-service/src/zigbee_service.c | 10 +- 8 files changed, 278 insertions(+), 19 deletions(-) create mode 100644 zigbee-daemon/zigbee-lib/include/zblib_driver_manager.h diff --git a/zigbee-daemon/src/main.c b/zigbee-daemon/src/main.c index 05895ff..78639c3 100644 --- a/zigbee-daemon/src/main.c +++ b/zigbee-daemon/src/main.c @@ -34,6 +34,15 @@ /**< ZigBee Service */ ZigBeeService *zigbee_service; +static gboolean _request_terminate(gpointer user_data) +{ + NOTUSED(user_data); + + zblib_service_exit(zigbee_service); + + return G_SOURCE_REMOVE; +} + int main(int arg, char **argv) { ZigBeeService *service = NULL; @@ -49,8 +58,6 @@ int main(int arg, char **argv) NOTUSED(arg); NOTUSED(argv); - Z_LOGI("service mainloop start"); - /* Create ZigBee service */ zigbee_service = service = zblib_service_new(); @@ -65,10 +72,12 @@ int main(int arg, char **argv) ret = zigbee_service_init(service); if (G_UNLIKELY(FALSE == ret)) { Z_LOGE("zigbee_service_init failed!"); - goto END; + /* Minimum mainloop time is required to notify the result */ + g_timeout_add(100, _request_terminate, NULL); } /* Run ZigBee service */ + Z_LOGI("service mainloop start"); ret = zblib_service_run(service); if (G_UNLIKELY(FALSE == ret)) { Z_LOGE("Run service failed!"); diff --git a/zigbee-daemon/zigbee-interface/src/zigbee_service_dbus_interface.c b/zigbee-daemon/zigbee-interface/src/zigbee_service_dbus_interface.c index 3f729d5..97111d9 100644 --- a/zigbee-daemon/zigbee-interface/src/zigbee_service_dbus_interface.c +++ b/zigbee-daemon/zigbee-interface/src/zigbee_service_dbus_interface.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "zigbee_service_interface.h" #include "zigbee_service_interface_common.h" @@ -34,6 +35,26 @@ /**< ZigBee D-BUS service interface name */ #define ZIGBEE_DBUS_SERVICE_INTERFACE_NAME "zigbee-dbus" +static void _notify_zigbee_state(ZigBeeServiceInterface *service_interface, + gboolean result) +{ + ZigbeeCustomData_t *custom_data = zblib_service_interface_ref_user_data(service_interface); + ZigBeeService *service = zblib_service_interface_ref_service(service_interface); + + if (NULL == custom_data) { + Z_LOGE("Unexpected invalid parameter !"); + return; + } + + if (result) { + /* Notify zigbee service manually here (Enabled) */ + zigbee_manager_emit_zigbee_state(custom_data->zigbee_mgr, result); + } else { + /* ZigBee state will be emitted on bus termination */ + zblib_service_exit(service); + } +} + static gboolean on_manager_enable(ZigbeeManager *zigbee_mgr, GDBusMethodInvocation *invocation, gpointer user_data) @@ -49,11 +70,6 @@ static gboolean on_manager_enable(ZigbeeManager *zigbee_mgr, zigbee_manager_complete_enable(zigbee_mgr, invocation); - if (TRUE == custom_data->sevice_interface_init_complete) { - /* Emit zigbee_state - enabled */ - zigbee_manager_emit_zigbee_state(zigbee_mgr, TRUE); - } - return TRUE; } @@ -291,6 +307,18 @@ static void zigbee_service_dbus_interface_noti_cb(ZigBeeServiceInterface *servic } break; + case ZBLIB_DRIVER_TYPE_MANAGER: { + /* Handle 'enabled' notification here */ + if (notification_id == ZBLIB_MANAGER_NOTI_ZIGBEE_ENABLED) { + gboolean *rsp = (gboolean*)noti_data; + + Z_LOGD("Firmware update result : [%s]", ((*rsp) ? "Succeed" : "Failed")); + _notify_zigbee_state(service_interface, *rsp); + } else + Z_LOGE("Unhandled notification id: [%d]", notification_id); + } + break; + case ZBLIB_DRIVER_TYPE_NONE: /* Fall through */ default: { Z_LOGE("Unhandled driver type: [%d]", driver_type); @@ -329,11 +357,6 @@ static void zigbee_on_name_acquired(GDBusConnection *connection, /* Bus name is 'acquired' */ custom_data->name_acquired = TRUE; - - if (TRUE == custom_data->sevice_interface_init_complete) { - /* Emit zigbee_state - enabled */ - zigbee_manager_emit_zigbee_state(custom_data->zigbee_mgr, TRUE); - } } static void zigbee_on_bus_acquired(GDBusConnection *connection, @@ -591,6 +614,10 @@ void zigbee_service_dbus_interface_deinit(ZigBeeService *service) goto EXIT; } + /* Emit zigbee_state - disabled */ + Z_LOGD("Update zigbee_state ----"); + zigbee_manager_emit_zigbee_state(interface_data->zigbee_mgr, FALSE); + /* * Unown "org.tizen.zigbee.manager" named bus on D-BUS SYSTEM bus */ diff --git a/zigbee-daemon/zigbee-lib/include/zblib.h b/zigbee-daemon/zigbee-lib/include/zblib.h index d439aa5..2fc35ac 100644 --- a/zigbee-daemon/zigbee-lib/include/zblib.h +++ b/zigbee-daemon/zigbee-lib/include/zblib.h @@ -61,6 +61,7 @@ typedef struct zblib_request_type ZigBeeRequest; /**< ZigBee driver types */ typedef enum { ZBLIB_DRIVER_TYPE_NONE, /**< None */ + ZBLIB_DRIVER_TYPE_MANAGER, /**< Manager */ ZBLIB_DRIVER_TYPE_SERVICE, /**< Service */ ZBLIB_DRIVER_TYPE_ZDO_DEV_CONTROL, /**< ZDO Dev control */ ZBLIB_DRIVER_TYPE_ZDO_BIND, /**< ZDO bind */ diff --git a/zigbee-daemon/zigbee-lib/include/zblib_driver_manager.h b/zigbee-daemon/zigbee-lib/include/zblib_driver_manager.h new file mode 100644 index 0000000..5b5bafa --- /dev/null +++ b/zigbee-daemon/zigbee-lib/include/zblib_driver_manager.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Suresh Kumar N (suresh.n@samsung.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ZIGBEE_LIB_DRIVER_MANAGER_H__ +#define __ZIGBEE_LIB_DRIVER_MANAGER_H__ + +/**< ZigBee 'Manager' notification IDs */ +typedef enum { + ZBLIB_MANAGER_NOTI_ZIGBEE_ENABLED = 1, /**< Zigbee enabled */ +} ZblibManagerNoti_e; + +#endif /* __ZIGBEE_LIB_DRIVER_MANAGER_H__ */ diff --git a/zigbee-daemon/zigbee-lib/include/zblib_plugin.h b/zigbee-daemon/zigbee-lib/include/zblib_plugin.h index c901a96..cd77d97 100644 --- a/zigbee-daemon/zigbee-lib/include/zblib_plugin.h +++ b/zigbee-daemon/zigbee-lib/include/zblib_plugin.h @@ -19,13 +19,17 @@ #ifndef __ZIGBEE_LIB_PLUGIN_H__ #define __ZIGBEE_LIB_PLUGIN_H__ +/**< ZigBee plug-in asynchronous initializer callback */ +typedef void (*zblib_plugin_init_finished_cb)(gboolean result, void *user_data); + /**< ZigBee plug-in descriptor */ typedef struct { const gchar *name; int version; - gboolean (*is_implemented)(); /**< Is plug-in implemented */ gboolean (*load)(); /**< Load plugin */ gboolean (*init)(ZigBeePlugin *); /**< Initialize plugin */ + gboolean (*init_async)(ZigBeePlugin *, zblib_plugin_init_finished_cb, void *); + /**< Initialize plugin asynchronously */ void (*unload)(ZigBeePlugin *); /**< Unload plugin */ } ZblibPluginDescriptor_t; diff --git a/zigbee-daemon/zigbee-lib/include/zblib_service.h b/zigbee-daemon/zigbee-lib/include/zblib_service.h index 6034098..e0dc480 100644 --- a/zigbee-daemon/zigbee-lib/include/zblib_service.h +++ b/zigbee-daemon/zigbee-lib/include/zblib_service.h @@ -30,6 +30,7 @@ gboolean zblib_service_remove_plugin(ZigBeeService *service, ZigBeePlugin *plugi gboolean zblib_service_load_plugins(ZigBeeService *service, const char *plugin_path); gboolean zblib_service_initialize_plugins(ZigBeeService *service); +gboolean zblib_service_initialize_async_plugins(ZigBeeService *service); gboolean zblib_service_unload_plugins(ZigBeeService *service); GSList *zblib_service_ref_plugins(ZigBeeService *service); diff --git a/zigbee-daemon/zigbee-lib/src/zblib_service.c b/zigbee-daemon/zigbee-lib/src/zblib_service.c index 681dc31..72e26e7 100644 --- a/zigbee-daemon/zigbee-lib/src/zblib_service.c +++ b/zigbee-daemon/zigbee-lib/src/zblib_service.c @@ -24,6 +24,16 @@ #include #include #include +#include +#include + +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 { @@ -34,8 +44,95 @@ struct zblib_service_type { 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, ZblibPluginDescriptor_t **descriptor_out) { @@ -97,7 +194,10 @@ static gboolean __zblib_service_init_plugin(ZigBeePlugin *plugin) const ZblibPluginDescriptor_t *descriptor = zblib_plugin_get_descriptor(plugin); zblib_check_null_ret_error("descriptor", descriptor, FALSE); - zblib_check_null_ret_error("descriptor->init", descriptor->init, FALSE); + if (NULL == descriptor->init) { + Z_LOGD("descriptor->init is NULL, trying async init"); + return FALSE; + } if (G_UNLIKELY(FALSE == descriptor->init(plugin))) { char *plugin_name = zblib_plugin_get_plugin_name(plugin); @@ -111,6 +211,28 @@ static gboolean __zblib_service_init_plugin(ZigBeePlugin *plugin) return TRUE; } +static gboolean __zblib_service_init_async_plugin(ZigBeePlugin *plugin, + zblib_plugin_init_finished_cb callback, void *user_data) +{ + const ZblibPluginDescriptor_t *descriptor = zblib_plugin_get_descriptor(plugin); + char *plugin_name = zblib_plugin_get_plugin_name(plugin); + + 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); @@ -193,6 +315,12 @@ void zblib_service_free(ZigBeeService *service) } } + /* Free async initializer */ + if (service->async_initializer) { + g_slist_free(service->async_initializer); + service->async_initializer = NULL; + } + /* Free plug-ins */ if (service->plugins) { g_slist_free(service->plugins); @@ -315,20 +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; 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; } diff --git a/zigbee-daemon/zigbee-service/src/zigbee_service.c b/zigbee-daemon/zigbee-service/src/zigbee_service.c index d80dbf7..b2a7284 100644 --- a/zigbee-daemon/zigbee-service/src/zigbee_service.c +++ b/zigbee-daemon/zigbee-service/src/zigbee_service.c @@ -56,7 +56,15 @@ gboolean zigbee_service_init(ZigBeeService *service) return FALSE; } - Z_TIME_CHECK("Initializing Plugins Complete. Starting Daemon"); + Z_TIME_CHECK("Initializing Plugins Complete."); + + /* Initialize ZigBee plug-ins */ + if (G_UNLIKELY(TRUE != zblib_service_initialize_async_plugins(service))) { + Z_LOGE("Asynchronously initialize plug-ins failed!"); + return FALSE; + } + + Z_TIME_CHECK("Asynchronous initializer launched successfully. Starting Daemon"); return TRUE; } -- 2.7.4