summaryrefslogtreecommitdiffstats
path: root/src/framework/init
diff options
context:
space:
mode:
authorqchang <qing.chang1@huawei.com>2018-03-08 17:39:22 -0800
committerqchang <qing.chang1@huawei.com>2018-03-08 17:39:22 -0800
commit697ade6190b23c80e7f60963983786e679759393 (patch)
treedd9782d1e936b8342163b26795e23571d4b1b415 /src/framework/init
parent71a4e2f34afa8018426f0e830050e50a1de6d375 (diff)
dmm initial commit
Change-Id: I049ee277cf4efdb83f9c2ac439365fcd421c159b Signed-off-by: qchang <qing.chang1@huawei.com>
Diffstat (limited to 'src/framework/init')
-rw-r--r--src/framework/init/CMakeLists.txt24
-rw-r--r--src/framework/init/fw_init.c320
-rw-r--r--src/framework/init/fw_module.c331
-rw-r--r--src/framework/init/fw_module.h85
4 files changed, 760 insertions, 0 deletions
diff --git a/src/framework/init/CMakeLists.txt b/src/framework/init/CMakeLists.txt
new file mode 100644
index 0000000..ff8d4d2
--- /dev/null
+++ b/src/framework/init/CMakeLists.txt
@@ -0,0 +1,24 @@
+#########################################################################
+#
+# Copyright (c) 2018 Huawei Technologies Co.,Ltd.
+# 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.
+#########################################################################
+
+SET(LIBSBR_SRC fw_init.c fw_module.c)
+
+SET(COMM_CONFIG ${PROJECT_SOURCE_DIR}/src/framework/common/base/include/common_sys_config.h)
+ADD_DEFINITIONS(-fPIC -mssse3)
+ADD_DEFINITIONS(-include ${COMM_CONFIG})
+
+ADD_LIBRARY(nStackfwinit static ${LIBSBR_SRC})
+
diff --git a/src/framework/init/fw_init.c b/src/framework/init/fw_init.c
new file mode 100644
index 0000000..6337b67
--- /dev/null
+++ b/src/framework/init/fw_init.c
@@ -0,0 +1,320 @@
+/*
+*
+* Copyright (c) 2018 Huawei Technologies Co.,Ltd.
+* 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.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "nstack_securec.h"
+#include "fw_module.h"
+#include "nstack_log.h"
+
+#ifdef __cplusplus
+/* *INDENT-OFF* */
+extern "C"{
+/* *INDENT-ON* */
+#endif /* __cplusplus */
+
+NSTACK_STATIC int
+nsfw_module_instance_isIndepend (nsfw_module_instance_t * inst)
+{
+ nsfw_module_depends_t *dep = inst->depends;
+ while (dep)
+ {
+ if (!dep->isReady)
+ return 1;
+ dep = dep->next;
+ }
+
+ return 0;
+}
+
+NSTACK_STATIC void
+nsfw_module_instance_depend_check (nsfw_module_instance_t * inst)
+{
+ nsfw_module_instance_t *curInst = nsfw_module_getManager ()->inst;
+ while (curInst)
+ {
+ if (curInst == inst)
+ goto nextLoop;
+ if (NSFW_INST_STAT_CHECKING == curInst->stat
+ || NSFW_INST_STAT_DEPENDING == curInst->stat)
+ {
+ nsfw_module_depends_t *dep = curInst->depends;
+ while (dep)
+ {
+ if (0 == dep->isReady && 0 == strcmp (dep->name, inst->name))
+ {
+ dep->isReady = 1; /* Don't break for case that duplicate name exist, though I think it should
+ not happen */
+ }
+ dep = dep->next;
+ }
+ }
+ nextLoop:
+ curInst = curInst->next;
+ }
+
+}
+
+/**
+ * @Function nstack_framework_init
+ * @Description Init child modules
+ * @param father instance , NULL means root
+ * @return 0 on success, -1 on error
+ */
+NSTACK_STATIC int
+nstack_framework_initChild_unsafe (nsfw_module_instance_t * father)
+{
+ NSFW_LOGDBG ("init framework module] name=%s",
+ father ? father->name : "NULL");
+
+ nsfw_module_instance_t *inst = nsfw_module_getManager ()->inst;
+
+ while (inst)
+ {
+ NSFW_LOGDBG
+ ("init child] inst=%s, inst->father=%s, inst->depends=%s, inst->state=%d",
+ inst->name, inst->father ? inst->father->name : "NULL",
+ inst->depends ? inst->depends->name : "NULL", inst->stat);
+
+ if (father != inst->father)
+ {
+ NSFW_LOGDBG ("inst->father not match] inst=%s, ", inst->name);
+
+ inst = inst->next;
+ continue;
+ }
+
+ switch (inst->stat)
+ {
+ case NSFW_INST_STAT_CHECKING:
+ /* First, check if any depends, then check if other instance depends on it */
+ if (nsfw_module_instance_isIndepend (inst))
+ {
+ inst->stat = NSFW_INST_STAT_DEPENDING;
+ NSFW_LOGDBG ("inst is still depending] name=%s", inst->name);
+ inst = inst->next;
+ break;
+ }
+
+ NSFW_LOGINF ("Going to init module] name=%s, init fun=%p",
+ inst->name, inst->fnInit);
+ if (NULL != inst->fnInit && 0 != inst->fnInit (inst->param))
+ {
+ NSFW_LOGERR ("initial fail!!!] inst=%s", inst->name);
+ inst->stat = NSFW_INST_STAT_FAIL;
+ return -1;
+ }
+
+ inst->stat = NSFW_INST_STAT_DONE;
+ nsfw_module_instance_depend_check (inst);
+
+ if (-1 == nsfw_module_addDoneNode (inst))
+ {
+ NSFW_LOGERR ("add done node fail");
+ }
+
+ inst = nsfw_module_getManager ()->inst; /* check from begining */
+ break;
+ case NSFW_INST_STAT_DEPENDING:
+ /* check if depending stat is still there */
+ if (!nsfw_module_instance_isIndepend (inst))
+ {
+ inst->stat = NSFW_INST_STAT_CHECKING;
+ break;
+ }
+ case NSFW_INST_STAT_FAIL:
+ case NSFW_INST_STAT_DONE:
+ default:
+ inst = inst->next;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+NSTACK_STATIC void
+nstack_framework_printInstanceInfo (nsfw_module_instance_t * inst)
+{
+
+ if (NULL == inst)
+ {
+ NSFW_LOGERR ("param error,inst==NULL");
+ return;
+ }
+
+ char info[1024] = "";
+ int plen = 0;
+
+ int ret = SPRINTF_S (info, sizeof (info), "Inst:%s,father:%s,depends:",
+ inst->name,
+ inst->father ? inst->father->name : "NULL");
+
+ if (ret <= 0)
+ {
+ NSFW_LOGERR ("Sprintf Error] module=%s,state=%d, ret=%d", inst->name,
+ inst->stat, ret);
+ return;
+ }
+ else
+ {
+ plen += ret;
+ }
+
+ if (NULL == inst->depends)
+ {
+ ret = SPRINTF_S (info + plen, sizeof (info) - plen, "NULL");
+ if (ret <= 0)
+ {
+ NSFW_LOGERR ("Sprintf Error] module=%s,state=%d, ret=%d",
+ inst->name, inst->stat, ret);
+ return;
+ }
+ NSFW_LOGINF ("] inst info=%s", info);
+ return;
+ }
+
+ nsfw_module_depends_t *dep = inst->depends;
+ while (dep)
+ {
+ ret = SPRINTF_S (info + plen, sizeof (info) - plen, "%s ", dep->name);
+ if (ret <= 0)
+ {
+ NSFW_LOGERR ("Sprintf Error] module=%s,state=%d, ret=%d",
+ inst->name, inst->stat, ret);
+ return;
+ }
+ plen += ret;
+ dep = dep->next;
+ }
+
+ NSFW_LOGINF ("] inst info=%s", info);
+}
+
+NSTACK_STATIC void
+nstack_framework_printInitialResult ()
+{
+ nsfw_module_manager_t *manager = nsfw_module_getManager ();
+
+ if (manager->doneHead)
+ {
+ NSFW_LOGINF ("Here is the initial done modules: ");
+
+ nsfw_module_doneNode_t *curNode = manager->doneHead;
+ while (curNode)
+ {
+ nstack_framework_printInstanceInfo (curNode->inst);
+ curNode = curNode->next;
+ }
+ }
+ else
+ {
+ NSFW_LOGERR ("No initial done modules");
+ }
+
+ nsfw_module_instance_t *curInst = manager->inst;
+ int unDoneNum = 0;
+ while (curInst)
+ {
+ if (curInst->stat != NSFW_INST_STAT_DONE)
+ {
+ if (0 == unDoneNum)
+ {
+ NSFW_LOGINF ("Here is the unInited modules:");
+ }
+ unDoneNum++;
+ nstack_framework_printInstanceInfo (curInst);
+ }
+ curInst = curInst->next;
+ }
+ if (0 == unDoneNum)
+ NSFW_LOGINF ("All modules are inited");
+}
+
+/**
+ * @Function nstack_framework_init
+ * @Description This function will do framework initial work, it will involk all initial functions
+ * registed using macro NSFW_MODULE_INIT before
+ * @param none
+ * @return 0 on success, -1 on error
+ */
+int
+nstack_framework_init (void)
+{
+ int ret = -1;
+ if (nsfw_module_getManager ()->done)
+ {
+ goto init_finished;
+ }
+
+ if (pthread_mutex_lock (&nsfw_module_getManager ()->initMutex))
+ {
+ return -1;
+ }
+
+ if (nsfw_module_getManager ()->done)
+ {
+ goto done;
+ }
+
+ ret = nstack_framework_initChild_unsafe (NULL);
+
+ if (0 == ret)
+ {
+ nsfw_module_getManager ()->done = 1;
+ }
+ else
+ {
+ nsfw_module_getManager ()->done = -1;
+ }
+
+ // Going to print done modules and undone modules
+ nstack_framework_printInitialResult ();
+
+done:
+ if (pthread_mutex_unlock (&nsfw_module_getManager ()->initMutex))
+ {
+ return -1;
+ }
+init_finished:
+ ret = nsfw_module_getManager ()->done == 1 ? 0 : -1;
+ return ret;
+}
+
+/**
+ * @Function nstack_framework_setModuleParam
+ * @Description This function set parameter of module initial function parameter
+ * @param module - name of module
+ * @param param - parameter to set
+ * @return 0 on success, -1 on error
+ */
+int
+nstack_framework_setModuleParam (char *module, void *param)
+{
+ nsfw_module_instance_t *inst = nsfw_module_getModuleByName (module);
+ if (!inst)
+ return -1;
+
+ inst->param = param;
+ return 0;
+}
+
+#ifdef __cplusplus
+/* *INDENT-OFF* */
+}
+/* *INDENT-ON* */
+#endif /* __cplusplus */
diff --git a/src/framework/init/fw_module.c b/src/framework/init/fw_module.c
new file mode 100644
index 0000000..65bbb0a
--- /dev/null
+++ b/src/framework/init/fw_module.c
@@ -0,0 +1,331 @@
+/*
+*
+* Copyright (c) 2018 Huawei Technologies Co.,Ltd.
+* 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.
+*/
+
+#include <memory.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "nstack_securec.h"
+#include "fw_module.h"
+
+#ifdef __cplusplus
+/* *INDENT-OFF* */
+extern "C"{
+/* *INDENT-ON* */
+#endif /* __cplusplus */
+
+COMPAT_PROTECT (NSFW_MOUDLE_INSTANCE_POOL_SIZE, 64);
+COMPAT_PROTECT (NSFW_MOUDLE_DEPENDS_POOL_SIZE, 128);
+
+nsfw_module_instance_pool_t g_nsfw_module_inst_pool;
+nsfw_module_depends_pool_t g_nsfw_module_deps_pool;
+
+/*
+* WARNING!!!:
+* This function is only used in constructor progress. Multi-thread concurrent is not supported!
+*/
+NSTACK_STATIC nsfw_module_instance_t *
+nsfw_module_malloc_instance ()
+{
+ if (g_nsfw_module_inst_pool.last_idx >= NSFW_MOUDLE_INSTANCE_POOL_SIZE)
+ {
+ return NULL;
+ }
+ return
+ &g_nsfw_module_inst_pool.module_instance_pool[g_nsfw_module_inst_pool.
+ last_idx++];
+}
+
+/*
+* WARNING!!!:
+* This function is only used in constructor progress. Multi-thread concurrent is not supported!
+*/
+NSTACK_STATIC nsfw_module_depends_t *
+nsfw_module_malloc_depends ()
+{
+ if (g_nsfw_module_deps_pool.last_idx >= NSFW_MOUDLE_DEPENDS_POOL_SIZE)
+ {
+ return NULL;
+ }
+ return
+ &g_nsfw_module_deps_pool.module_depends_pool[g_nsfw_module_deps_pool.
+ last_idx++];
+}
+
+NSTACK_STATIC void
+nsfw_module_setChildInstance (nsfw_module_instance_t *
+ father, nsfw_module_instance_t * child)
+{
+ if (NULL == father || NULL == child)
+ return;
+ child->father = father;
+}
+
+nsfw_module_depends_t *
+nsfw_module_create_depends (char *name)
+{
+ if (NULL == name)
+ return NULL;
+
+ /*Change module malloc to pool array */
+ nsfw_module_depends_t *dep = nsfw_module_malloc_depends ();
+
+ if (NULL == dep)
+ return NULL;
+
+ if (EOK !=
+ MEMSET_S (dep, sizeof (nsfw_module_depends_t), 0,
+ sizeof (nsfw_module_depends_t)))
+ {
+ goto fail;
+ }
+
+ /*change destMax from nameSize - 1 to sizeof(dep->name) */
+ if (EOK != STRCPY_S (dep->name, sizeof (dep->name), name))
+ {
+ goto fail;
+ }
+ dep->isReady = 0;
+
+ return dep;
+
+fail:
+ // NOTE: if dep is not null, we do not free it and just leave it there.
+ return NULL;
+}
+
+nsfw_module_instance_t *
+nsfw_module_create_instance (void)
+{
+ /*Change module malloc to pool array */
+ nsfw_module_instance_t *inst = nsfw_module_malloc_instance ();
+ if (NULL == inst)
+ return NULL;
+
+ if (EOK !=
+ MEMSET_S (inst, sizeof (nsfw_module_instance_t), 0,
+ sizeof (nsfw_module_instance_t)))
+ {
+ // NOTE: if inst is not null, we do not free it and just leave it there.
+ return NULL;
+ }
+
+ inst->stat = NSFW_INST_STAT_CHECKING;
+ return inst;
+}
+
+void
+nsfw_module_set_instance_name (nsfw_module_instance_t * inst, char *name)
+{
+ if (NULL == inst || NULL == name || inst->name[0] != '\0')
+ {
+ return;
+ }
+
+ /*change destMax from nameSize - 1 to sizeof(inst->name) */
+ if (EOK != STRCPY_S (inst->name, sizeof (inst->name), name))
+ {
+ return;
+ }
+
+ // Now we need to search if it's any instance's father
+ nsfw_module_instance_t *curInst = nsfw_module_getManager ()->inst;
+ while (curInst)
+ {
+ if (curInst == inst)
+ goto next_loop;
+
+ if (0 == strcmp (curInst->fatherName, inst->name)
+ && NULL == curInst->father)
+ {
+ nsfw_module_setChildInstance (inst, curInst);
+ }
+ next_loop:
+ curInst = curInst->next;
+ }
+ return;
+}
+
+void
+nsfw_module_set_instance_father (nsfw_module_instance_t * inst,
+ char *fatherName)
+{
+ if (NULL == inst || NULL == fatherName)
+ {
+ return;
+ }
+
+ if (EOK !=
+ STRCPY_S (inst->fatherName, sizeof (inst->fatherName), fatherName))
+ {
+ return;
+ }
+
+ nsfw_module_instance_t *fatherInst =
+ nsfw_module_getModuleByName (fatherName);
+ if (fatherInst)
+ {
+ nsfw_module_setChildInstance (fatherInst, inst);
+ }
+ return;
+}
+
+void
+nsfw_module_set_instance_priority (nsfw_module_instance_t * inst,
+ int priority)
+{
+ if (NULL == inst)
+ return;
+ inst->priority = priority;
+
+ nsfw_module_del_instance (inst);
+ nsfw_module_add_instance (inst);
+ return;
+}
+
+void
+nsfw_module_set_instance_initfn (nsfw_module_instance_t * inst,
+ nsfw_module_init_fn fn)
+{
+ if (NULL == inst)
+ return;
+ inst->fnInit = fn;
+ return;
+}
+
+void
+nsfw_module_set_instance_depends (nsfw_module_instance_t * inst, char *name)
+{
+ if (NULL == inst || name == NULL)
+ return;
+
+ // Check if depends already set
+ nsfw_module_depends_t *dep = inst->depends;
+ while (dep)
+ {
+ if (0 == strcmp (dep->name, name))
+ return;
+ dep = dep->next;
+ }
+
+ dep = nsfw_module_create_depends (name);
+ if (NULL == dep)
+ return;
+
+ if (NULL == inst->depends)
+ inst->depends = dep;
+ else
+ inst->depends->next = dep;
+}
+
+/* *INDENT-OFF* */
+nsfw_module_manager_t g_nsfw_module_manager = {.inst = NULL, .initMutex =
+ PTHREAD_MUTEX_INITIALIZER, .done = 0};
+/* *INDENT-ON* */
+
+void
+nsfw_module_add_instance (nsfw_module_instance_t * inst)
+{
+ nsfw_module_instance_t *curInst = nsfw_module_getManager ()->inst;
+
+ if (NULL == curInst || curInst->priority > inst->priority)
+ {
+ inst->next = curInst;
+ nsfw_module_getManager ()->inst = inst;
+ }
+ else
+ {
+ while (curInst->next && curInst->next->priority <= inst->priority)
+ {
+ curInst = curInst->next;
+ }
+ inst->next = curInst->next;
+ curInst->next = inst;
+ }
+}
+
+void
+nsfw_module_del_instance (nsfw_module_instance_t * inst)
+{
+ if (nsfw_module_getManager ()->inst == inst)
+ {
+ nsfw_module_getManager ()->inst = inst->next;
+ return;
+ }
+
+ nsfw_module_instance_t *curInst = nsfw_module_getManager ()->inst;
+
+ while (curInst->next && curInst->next != inst)
+ curInst = curInst->next;
+
+ if (!curInst->next)
+ return;
+ curInst->next = inst->next;
+}
+
+nsfw_module_instance_t *
+nsfw_module_getModuleByName (char *name)
+{
+ if (NULL == name)
+ return NULL;
+
+ nsfw_module_instance_t *curInst = nsfw_module_getManager ()->inst;
+ while (curInst)
+ {
+ if (0 == strcmp (curInst->name, name))
+ {
+ return curInst;
+ }
+ curInst = curInst->next;
+ }
+
+ return NULL;
+}
+
+int
+nsfw_module_addDoneNode (nsfw_module_instance_t * inst)
+{
+ nsfw_module_doneNode_t *node =
+ (nsfw_module_doneNode_t *) malloc (sizeof (nsfw_module_doneNode_t));
+ if (NULL == node)
+ return -1;
+ node->inst = inst;
+ node->next = NULL;
+
+ nsfw_module_manager_t *manager = nsfw_module_getManager ();
+ if (NULL == manager->doneHead)
+ {
+ manager->doneHead = node;
+ }
+ else
+ {
+ nsfw_module_doneNode_t *tail = manager->doneHead;
+ while (tail->next)
+ {
+ tail = tail->next;
+ }
+
+ tail->next = node;
+ }
+
+ return 0;
+}
+
+#ifdef __cplusplus
+/* *INDENT-OFF* */
+}
+/* *INDENT-ON* */
+#endif /* __cplusplus */
diff --git a/src/framework/init/fw_module.h b/src/framework/init/fw_module.h
new file mode 100644
index 0000000..1cfc95f
--- /dev/null
+++ b/src/framework/init/fw_module.h
@@ -0,0 +1,85 @@
+/*
+*
+* Copyright (c) 2018 Huawei Technologies Co.,Ltd.
+* 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 _FW_MODULE
+#define _FW_MODULE
+#include <pthread.h>
+
+#ifdef __cplusplus
+/* *INDENT-OFF* */
+extern "C"{
+/* *INDENT-ON* */
+#endif /* _cplusplus */
+
+#include "nsfw_init.h"
+
+/* Unique name declare */
+#define NSFW__STRINGIFY(x) #x
+#define NSFW_STRINGIFY(x) NSFW__STRINGIFY(x)
+
+#define NSFW__PASTE(a,b) a##b
+#define NSFW_PASTE(a,b) NSFW__PASTE(a,b)
+
+#define NSFW_UNIQUE_ID(prefix) NSFW_PASTE(NSFW_PASTE(__LINE__, prefix), __COUNTER__)
+
+#define NSFW_MODULE_INITFN(_fn) \
+ static int _fn(void* param)
+extern nsfw_module_depends_t *nsfw_module_create_depends (char *name);
+
+#define NSFW_MODULE_SET_STATE(inst, state) ((inst)->stat = (state))
+
+typedef struct _nsfw_module_doneNode
+{
+ nsfw_module_instance_t *inst;
+ struct _nsfw_module_doneNode *next;
+} nsfw_module_doneNode_t;
+
+typedef struct _nsfw_module_manager
+{
+ pthread_mutex_t initMutex;
+ int done; // 0 - not finished, 1 - finished, -1 - error
+ nsfw_module_instance_t *inst;
+ nsfw_module_doneNode_t *doneHead;
+} nsfw_module_manager_t;
+
+extern int nsfw_module_addDoneNode (nsfw_module_instance_t * inst);
+
+extern nsfw_module_manager_t g_nsfw_module_manager;
+#define nsfw_module_getManager() (&g_nsfw_module_manager)
+
+#define NSFW_MOUDLE_INSTANCE_POOL_SIZE 64
+#define NSFW_MOUDLE_DEPENDS_POOL_SIZE 128
+
+typedef struct _nsfw_module_instance_pool
+{
+ int last_idx;
+ nsfw_module_instance_t
+ module_instance_pool[NSFW_MOUDLE_INSTANCE_POOL_SIZE];
+} nsfw_module_instance_pool_t;
+
+typedef struct _nsfw_module_depends_pool
+{
+ int last_idx;
+ nsfw_module_depends_t module_depends_pool[NSFW_MOUDLE_DEPENDS_POOL_SIZE];
+} nsfw_module_depends_pool_t;
+
+#ifdef __cplusplus
+/* *INDENT-OFF* */
+}
+/* *INDENT-ON* */
+#endif /* _cplusplus */
+
+#endif /* _FW_MODULE */