summaryrefslogtreecommitdiffstats
path: root/src/framework/ipc/ps/nsfw_recycle_module.c
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/ipc/ps/nsfw_recycle_module.c
parent71a4e2f34afa8018426f0e830050e50a1de6d375 (diff)
dmm initial commit
Change-Id: I049ee277cf4efdb83f9c2ac439365fcd421c159b Signed-off-by: qchang <qing.chang1@huawei.com>
Diffstat (limited to 'src/framework/ipc/ps/nsfw_recycle_module.c')
-rw-r--r--src/framework/ipc/ps/nsfw_recycle_module.c666
1 files changed, 666 insertions, 0 deletions
diff --git a/src/framework/ipc/ps/nsfw_recycle_module.c b/src/framework/ipc/ps/nsfw_recycle_module.c
new file mode 100644
index 0000000..bb3844f
--- /dev/null
+++ b/src/framework/ipc/ps/nsfw_recycle_module.c
@@ -0,0 +1,666 @@
+/*
+*
+* 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 <stdlib.h>
+#include "types.h"
+#include "nstack_securec.h"
+#include "nsfw_init.h"
+
+#include "nsfw_mgr_com_api.h"
+#include "nsfw_mem_api.h"
+#include "nsfw_ps_api.h"
+#include "nsfw_ps_mem_api.h"
+#include "nsfw_fd_timer_api.h"
+#include "nsfw_recycle_module.h"
+#include "nsfw_maintain_api.h"
+#include "nstack_log.h"
+#include "common_mem_api.h"
+
+#ifdef __cplusplus
+/* *INDENT-OFF* */
+extern "C"{
+/* *INDENT-ON* */
+#endif /* __cplusplus */
+
+/* only work on nStackMain*/
+nsfw_recycle_cfg g_rec_cfg;
+
+nsfw_recycle_fun g_rec_fun[NSFW_REC_TYPE_MAX] = { 0 };
+
+nsfw_rec_fun_info g_rec_lock_fun[NSFW_REC_LOCK_REL_MAX_FUN];
+
+/*****************************************************************************
+* Prototype : nsfw_recycle_reg_fun
+* Description : reg one recycle type recycle funciton
+* Input : u16 rec_type
+* nsfw_recycle_fun fun
+* Output : None
+* Return Value : u8
+* Calls :
+* Called By :
+*****************************************************************************/
+u8
+nsfw_recycle_reg_fun (u16 rec_type, nsfw_recycle_fun fun)
+{
+ if (NULL == fun || rec_type >= NSFW_REC_TYPE_MAX)
+ {
+ NSFW_LOGERR ("argv err]fun=%p,type=%u", fun, rec_type);
+ return FALSE;
+ }
+
+ g_rec_fun[rec_type] = fun;
+ NSFW_LOGINF ("reg]fun=%d,type=%u", fun, rec_type);
+ return TRUE;
+}
+
+/*****************************************************************************
+* Prototype : nsfw_recycle_lock_rel_fun
+* Description : reg lock release when app exit run
+* Input : nsfw_recycle_fun fun
+* void* data
+* u8 proc_type: NULL as all
+* Output : None
+* Return Value : u8
+* Calls :
+* Called By :
+*****************************************************************************/
+u8
+nsfw_recycle_lock_rel_fun (nsfw_recycle_fun fun, void *data, u8 proc_type)
+{
+ if (NULL == fun)
+ {
+ NSFW_LOGERR ("argv err]fun=%p,data=%p", fun, data);
+ return FALSE;
+ }
+
+ u32 i;
+
+ for (i = 0; i < NSFW_REC_LOCK_REL_MAX_FUN; i++)
+ {
+ if (NULL == g_rec_lock_fun[i].rec_fun)
+ {
+ g_rec_lock_fun[i].rec_fun = fun;
+ g_rec_lock_fun[i].data = data;
+ g_rec_lock_fun[i].proc_type = proc_type;
+ NSFW_LOGINF ("reg mgr_msg fun suc]fun=%p,data=%p", fun, data);
+ return TRUE;
+ }
+ }
+
+ NSFW_LOGINF ("reg]fun=%p,data=%p", fun, data);
+ return TRUE;
+}
+
+/*****************************************************************************
+* Prototype : nsfw_recycle_exit_pid_lock
+* Description : release all lock fun
+* Input : u32 pid
+* Output : None
+* Return Value : u8
+* Calls :
+* Called By :
+*****************************************************************************/
+int
+nsfw_recycle_exit_pid_lock (u32 pid, u8 proc_type, void *argv)
+{
+ u32 i;
+ NSFW_LOGINF ("release lock]pid=%d,type=%d", pid, proc_type);
+ for (i = 0; i < NSFW_REC_LOCK_REL_MAX_FUN; i++)
+ {
+ if (NULL == g_rec_lock_fun[i].rec_fun)
+ {
+ break;
+ }
+
+ if ((NSFW_PROC_NULL == g_rec_lock_fun[i].proc_type)
+ || (proc_type == g_rec_lock_fun[i].proc_type))
+ {
+ (void) g_rec_lock_fun[i].rec_fun (pid, g_rec_lock_fun[i].data, 0);
+ }
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+* Prototype : nsfw_recycle_obj_end
+* Description : one recycle object process finished notify
+* Input : u32 pid
+* Output : None
+* Return Value : u8
+* Calls :
+* Called By :
+*****************************************************************************/
+u8
+nsfw_recycle_obj_end (u32 pid)
+{
+ nsfw_mgr_msg *rsp_msg =
+ nsfw_mgr_msg_alloc (MGR_MSG_RCC_END_REQ, NSFW_PROC_MAIN);
+ if (NULL == rsp_msg)
+ {
+ NSFW_LOGERR ("alloc rsp msg failed]pid=%u", pid);
+ return FALSE;
+ }
+
+ nsfw_ps_info_msg *ps_msg = GET_USER_MSG (nsfw_ps_info_msg, rsp_msg);
+ ps_msg->host_pid = pid;
+ (void) nsfw_mgr_send_msg (rsp_msg);
+ nsfw_mgr_msg_free (rsp_msg);
+ NSFW_LOGINF ("send obj end msg]pid=%d", pid);
+ return TRUE;
+}
+
+/*****************************************************************************
+* Prototype : nsfw_recycle_callback_all_obj
+* Description : process all recycle object
+* Input : u32 pid
+* nsfw_recycle_pool *rec_pool
+* Output : None
+* Return Value : nsfw_rcc_stat
+* Calls :
+* Called By :
+*****************************************************************************/
+nsfw_rcc_stat
+nsfw_recycle_callback_all_obj (u32 pid, nsfw_recycle_pool * rec_pool)
+{
+ u32 match = 0;
+ nsfw_recycle_obj *obj = NULL;
+ if (NULL == rec_pool)
+ {
+ return NSFW_RCC_CONTINUE;
+ }
+
+ nsfw_recycle_obj *p_start = rec_pool->obj;
+ u32 i;
+ u32 size = rec_pool->pool_size;
+
+ nsfw_ps_info *pps_info;
+ pps_info = nsfw_ps_info_get (pid);
+ if (NULL == pps_info)
+ {
+ NSFW_LOGERR ("get ps_info falied!]pid=%d", pid);
+ return NSFW_RCC_CONTINUE;
+ }
+
+ i32 cur_idx = (i32) (u64) nsfw_ps_get_uv (pps_info, NSFW_REC_IDX);
+
+ if (-1 == cur_idx)
+ {
+ cur_idx = 0;
+ nsfw_ps_set_uv (pps_info, NSFW_REC_IDX, (void *) (u64) cur_idx);
+ (void) nsfw_recycle_exit_pid_lock (pid, NSFW_PROC_APP, NULL);
+ }
+ else
+ {
+ cur_idx++;
+ nsfw_ps_set_uv (pps_info, NSFW_REC_IDX, (void *) (u64) cur_idx);
+ }
+
+ for (i = cur_idx; i < size; i++)
+ {
+ obj = &p_start[i];
+ cur_idx = i;
+ nsfw_ps_set_uv (pps_info, NSFW_REC_IDX, (void *) (u64) cur_idx);
+ if (FALSE == obj->alloc_flag)
+ {
+ continue;
+ }
+
+ if ((obj->rec_type < NSFW_REC_TYPE_MAX)
+ && (NULL != g_rec_fun[obj->rec_type]))
+ {
+ match++;
+ if (NSFW_RCC_SUSPEND ==
+ g_rec_fun[obj->rec_type] (pid, obj->data, obj->rec_type))
+ {
+ NSFW_LOGINF
+ ("call suspend]type=%d,obj_pid=%d,pid=%d,count=%d",
+ obj->rec_type, obj->host_pid, pid, match);
+ return NSFW_RCC_SUSPEND;
+ }
+ }
+ else
+ {
+ NSFW_LOGERR ("obj_error!drop]type=%d,obj_pid=%d,pid=%d",
+ obj->rec_type, obj->host_pid, pid);
+ }
+ }
+
+ NSFW_LOGWAR ("rec obj]pid=%d,count=%d,cur_idx=%d", pid, match, cur_idx);
+ return NSFW_RCC_CONTINUE;
+}
+
+/*****************************************************************************
+* Prototype : nsfw_recycle_pid_obj
+* Description : recycle object with pid
+* Input : u32 pid
+* Output : None
+* Return Value : u8
+* Calls :
+* Called By :
+*****************************************************************************/
+u8
+nsfw_recycle_pid_obj (u32 pid)
+{
+ nsfw_ps_info *pps_info;
+ pps_info = nsfw_ps_info_get (pid);
+ if (NULL == pps_info)
+ {
+ NSFW_LOGERR ("get ps_info falied!]pid=%d", pid);
+ return FALSE;
+ }
+
+ nsfw_recycle_pool *rec_pool = g_rec_cfg.mem_rec_obj_pool;
+ void *timer_ptr = nsfw_ps_get_uv (pps_info, NSFW_REC_TIMER);
+ if (NSFW_RCC_SUSPEND == nsfw_recycle_callback_all_obj (pid, rec_pool))
+ {
+ if (NULL != timer_ptr)
+ {
+ nsfw_timer_rmv_timer (timer_ptr);
+ timer_ptr = NULL;
+ }
+
+ struct timespec time_left = { NSFW_REC_WEND_TVLAUE, 0 };
+ timer_ptr =
+ (void *) nsfw_timer_reg_timer (NSFW_REC_WEND_TIMER,
+ (void *) (u64) pid,
+ nsfw_recycle_obj_timeout, time_left);
+ nsfw_ps_set_uv (pps_info, NSFW_REC_TIMER, timer_ptr);
+ return TRUE;
+ }
+
+ if (NULL != timer_ptr)
+ {
+ nsfw_timer_rmv_timer (timer_ptr);
+ nsfw_ps_set_uv (pps_info, NSFW_REC_TIMER, NULL);
+ }
+
+ (void) nsfw_ps_exit_end_notify (pid);
+ nsfw_ps_info_free (pps_info);
+ return TRUE;
+}
+
+/*****************************************************************************
+* Prototype : nsfw_recycle_all_obj
+* Description :
+* Input : u32 pid
+* nsfw_mem_addr_msg *addr_msg
+* Output : None
+* Return Value : u8
+* Calls :
+* Called By :
+*****************************************************************************/
+u8
+nsfw_recycle_all_obj (u32 pid)
+{
+ nsfw_ps_info *pps_info;
+ pps_info = nsfw_ps_info_get (pid);
+ if (NULL == pps_info)
+ {
+ pps_info = nsfw_ps_info_alloc (pid, NSFW_PROC_APP);
+ if (NULL == pps_info)
+ {
+ NSFW_LOGERR ("alloc ps_info falied!]pid=%u", pid);
+ return FALSE;
+ }
+ }
+
+ nsfw_ps_set_uv (pps_info, NSFW_REC_IDX, (void *) (-1));
+ nsfw_ps_set_uv (pps_info, NSFW_REC_TIMER, NULL);
+ return nsfw_recycle_pid_obj (pid);
+}
+
+/*****************************************************************************
+* Prototype : mem_app_exit_proc
+* Description : exiting message process
+* Input : nsfw_mgr_msg* msg
+* Output : None
+* Return Value : int
+* Calls :
+* Called By :
+*****************************************************************************/
+int
+mem_app_exit_proc (nsfw_mgr_msg * msg)
+{
+ if (NULL == msg)
+ {
+ NSFW_LOGERR ("msg nul");
+ return FALSE;
+ }
+
+ nsfw_ps_info_msg *ps_info_msg = GET_USER_MSG (nsfw_ps_info_msg, msg);
+
+ /* look up the app rec memzone and release all resource */
+ /* no need to send rsp for it will be send after stack process over */
+ if (TRUE == nsfw_recycle_all_obj (ps_info_msg->host_pid))
+ {
+ NSFW_LOGINF ("obj found!]pid=%d", ps_info_msg->host_pid);
+ return TRUE;
+ }
+
+ (void) nsfw_ps_exit_end_notify (ps_info_msg->host_pid);
+ return FALSE;
+}
+
+/*****************************************************************************
+* Prototype : nsfw_recycle_obj_end_proc
+* Description : obj recycle finished notify process
+* Input : nsfw_mgr_msg* msg
+* Output : None
+* Return Value : int
+* Calls :
+* Called By :
+*****************************************************************************/
+int
+nsfw_recycle_obj_end_proc (nsfw_mgr_msg * msg)
+{
+ if (NULL == msg)
+ {
+ NSFW_LOGERR ("msg nul");
+ return FALSE;
+ }
+
+ nsfw_ps_info_msg *ps_info_msg = GET_USER_MSG (nsfw_ps_info_msg, msg);
+
+ return nsfw_recycle_pid_obj (ps_info_msg->host_pid);
+}
+
+/*****************************************************************************
+* Prototype : nsfw_recycle_obj_timeout
+* Description : recycle object timeout process
+* Input : u32 timer_type
+* void* data
+* Output : None
+* Return Value : int
+* Calls :
+* Called By :
+*****************************************************************************/
+int
+nsfw_recycle_obj_timeout (u32 timer_type, void *data)
+{
+ u32 pid = (u64) data;
+ void *timer_ptr = NULL;
+ NSFW_LOGINF ("ps_info timerout]pid=%u", pid);
+
+ nsfw_ps_info *pps_info;
+ pps_info = nsfw_ps_info_get (pid);
+ if (NULL != pps_info)
+ {
+ nsfw_recycle_pool *rec_pool = g_rec_cfg.mem_rec_obj_pool;
+ if (NULL != rec_pool)
+ {
+ if (TRUE == g_hbt_switch)
+ {
+ struct timespec time_left = { NSFW_REC_WEND_TVLAUE, 0 };
+ timer_ptr =
+ (void *) nsfw_timer_reg_timer (timer_type, data,
+ nsfw_recycle_obj_timeout,
+ time_left);
+ nsfw_ps_set_uv (pps_info, NSFW_REC_TIMER, timer_ptr);
+ return TRUE;
+ }
+ }
+ nsfw_ps_set_uv (pps_info, NSFW_REC_TIMER, timer_ptr);
+ }
+
+ (void) nsfw_recycle_pid_obj (pid);
+ return TRUE;
+}
+
+/*****************************************************************************
+* Prototype : mem_rec_zone_init
+* Description : init recycle zone in app, only work on App
+* Input : None
+* Output : None
+* Return Value : u8
+* Calls :
+* Called By :
+*****************************************************************************/
+u8
+mem_rec_zone_init ()
+{
+ nsfw_mem_mring pringinfo;
+ pringinfo.enmptype = NSFW_MRING_MPMC;
+ pringinfo.isocket_id = NSFW_SOCKET_ANY;
+ pringinfo.stname.entype = NSFW_NSHMEM;
+ pringinfo.usnum = MEM_RECYCLE_PER_PRO_QUE;
+ u32 i;
+ for (i = 0; i < NSFW_REC_PRO_MAX; i++)
+ {
+ if (-1 ==
+ SPRINTF_S (pringinfo.stname.aname, NSFW_MEM_NAME_LENTH, "%s%d",
+ MEM_REC_QUEUE_NAME, i))
+ {
+ NSFW_LOGERR ("SPRINTF_S failed]");
+ return FALSE;
+ }
+ g_rec_cfg.mem_rec_pro[i] = nsfw_mem_ring_create (&pringinfo);
+ if (NULL == g_rec_cfg.mem_rec_pro[i])
+ {
+ NSFW_LOGERR ("alloc rec ring nul!");
+ return FALSE;
+ }
+ }
+
+ MEM_STAT (NSFW_RECYCLE_MODULE, MEM_REC_QUEUE_NAME, NSFW_NSHMEM,
+ NSFW_REC_PRO_MAX * nsfw_mem_get_len (g_rec_cfg.mem_rec_pro[0],
+ NSFW_MEM_RING));
+
+ nsfw_mem_zone pzoneinfo;
+ pzoneinfo.isocket_id = NSFW_SOCKET_ANY;
+ pzoneinfo.stname.entype = NSFW_NSHMEM;
+ pzoneinfo.lenth =
+ MEM_RECYCLE_OBJ_MAX_NUM * sizeof (nsfw_recycle_obj) +
+ sizeof (nsfw_recycle_pool);
+ if (-1 ==
+ SPRINTF_S (pzoneinfo.stname.aname, NSFW_MEM_NAME_LENTH, "%s",
+ MEM_REC_POOL_NAME))
+ {
+ NSFW_LOGERR ("SPRINTF_S failed]");
+ return FALSE;
+ }
+
+ g_rec_cfg.mem_rec_obj_pool = nsfw_mem_zone_create (&pzoneinfo);
+ if (NULL == g_rec_cfg.mem_rec_obj_pool)
+ {
+ NSFW_LOGERR ("alloc rec pool nul!");
+ return FALSE;
+ }
+
+ MEM_STAT (NSFW_RECYCLE_MODULE, MEM_REC_POOL_NAME, NSFW_NSHMEM,
+ pzoneinfo.lenth);
+
+ int retval;
+ retval =
+ MEMSET_S (g_rec_cfg.mem_rec_obj_pool, pzoneinfo.lenth, 0,
+ pzoneinfo.lenth);
+ if (EOK != retval)
+ {
+ NSFW_LOGERR ("mem set init failed!");
+ return FALSE;
+ }
+
+ i32 j;
+ nsfw_recycle_pool *rec_pool =
+ (nsfw_recycle_pool *) g_rec_cfg.mem_rec_obj_pool;
+ rec_pool->pool_size = MEM_RECYCLE_OBJ_MAX_NUM;
+
+ nsfw_recycle_obj *p_start = rec_pool->obj;
+ for (i = 0; i < NSFW_REC_PRO_MAX; i++)
+ {
+ for (j = 0; j < MEM_RECYCLE_PER_PRO_QUE; j++)
+ {
+ if (FALSE == p_start[j].alloc_flag)
+ {
+ if (0 ==
+ nsfw_mem_ring_enqueue (g_rec_cfg.mem_rec_pro[i],
+ &p_start[j]))
+ {
+ NSFW_LOGERR ("enqueue failed");
+ break;
+ }
+ }
+ }
+ p_start = p_start + MEM_RECYCLE_PER_PRO_QUE;
+ }
+
+ NSFW_LOGINF ("init rec pool and ring suc!");
+ return TRUE;
+}
+
+/*****************************************************************************
+* Prototype : nsfw_recycle_reg_obj
+* Description : reg one recycle object
+* Input : u8 priority
+* u16 rec_type
+* void* data
+* Output : None
+* Return Value : void *
+* Calls :
+* Called By :
+*****************************************************************************/
+void *
+nsfw_recycle_reg_obj (u8 priority, u16 rec_type, void *data)
+{
+ if (NSFW_REC_PRO_MAX <= priority)
+ {
+ NSFW_LOGERR ("pro error]priority=%d,rec_type=%d,data=%p", priority,
+ rec_type, data);
+ return NULL;
+ }
+
+ nsfw_recycle_obj *obj = NULL;
+ if (0 ==
+ nsfw_mem_ring_dequeue (g_rec_cfg.mem_rec_pro[priority], (void *) &obj))
+ {
+ NSFW_LOGERR ("dequeue error]priority=%d,rec_type=%d,data=%p",
+ priority, rec_type, data);
+ return NULL;
+ }
+
+ if (EOK != MEMSET_S (obj, sizeof (*obj), 0, sizeof (*obj)))
+ {
+ if (0 == nsfw_mem_ring_enqueue (g_rec_cfg.mem_rec_pro[priority], obj))
+ {
+ NSFW_LOGERR ("enqueue error]priority=%d,rec_type=%d,data=%p",
+ priority, rec_type, data);
+ }
+
+ NSFW_LOGERR ("mem set error]priority=%d,rec_type=%d,data=%p",
+ priority, rec_type, data);
+ return NULL;
+ }
+
+ obj->alloc_flag = TRUE;
+ obj->rec_type = rec_type;
+ obj->data = data;
+ obj->host_pid = get_sys_pid ();
+ obj->alloc_flag = TRUE;
+ NSFW_LOGINF ("en queue obj]priority=%d,rec_type=%d,data=%p", priority,
+ rec_type, data);
+ return obj;
+}
+
+/*****************************************************************************
+* Prototype : nsfw_recycle_rechk_lock
+* Description : add for rechk lock
+* Input : None
+* Output : None
+* Return Value : int
+* Calls :
+* Called By :
+*****************************************************************************/
+int
+nsfw_recycle_rechk_lock ()
+{
+ return nsfw_ps_rechk_pid_exit (nsfw_recycle_exit_pid_lock, NULL);
+}
+
+/*****************************************************************************
+* Prototype : nsfw_recycle_module_init
+* Description : module init
+* Input : void* param
+* Output : None
+* Return Value : static int
+* Calls :
+* Called By :
+*****************************************************************************/
+NSTACK_STATIC int nsfw_recycle_module_init (void *param);
+NSTACK_STATIC int
+nsfw_recycle_module_init (void *param)
+{
+ u32 proc_type = (u32) ((long long) param);
+ NSFW_LOGINF ("recycle module init]type=%d", proc_type);
+ g_rec_cfg.rec_waite_end_tvalue = NSFW_REC_WEND_TVLAUE_DEF;
+ switch (proc_type)
+ {
+ case NSFW_PROC_MASTER:
+ return 0;
+ case NSFW_PROC_MAIN:
+ (void) nsfw_mgr_reg_msg_fun (MGR_MSG_APP_EXIT_REQ, mem_app_exit_proc);
+ (void) nsfw_mgr_reg_msg_fun (MGR_MSG_RCC_END_REQ,
+ nsfw_recycle_obj_end_proc);
+ if (TRUE == mem_rec_zone_init ())
+ {
+ return 0;
+ }
+
+ return 0;
+ default:
+ if (proc_type < NSFW_PROC_MAX)
+ {
+ break;
+ }
+ return -1;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+* Prototype : nsfw_recycle_fork_init
+* Description : fork init
+* Input : None
+* Output : None
+* Return Value : u8
+* Calls :
+* Called By :
+*****************************************************************************/
+u8
+nsfw_recycle_fork_init ()
+{
+ /* reconnect to master after fork in child proc */
+ nsfw_mgr_close_dst_proc (NSFW_PROC_MAIN, 0);
+ nsfw_mgr_close_dst_proc (NSFW_PROC_MASTER, 0);
+ if (0 == nsfw_recycle_module_init ((void *) ((long long) NSFW_PROC_APP)))
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/* *INDENT-OFF* */
+NSFW_MODULE_NAME (NSFW_RECYCLE_MODULE)
+NSFW_MODULE_PRIORITY (10)
+NSFW_MODULE_DEPENDS (NSFW_PS_MEM_MODULE)
+NSFW_MODULE_INIT (nsfw_recycle_module_init)
+/* *INDENT-ON* */
+
+#ifdef __cplusplus
+/* *INDENT-OFF* */
+}
+/* *INDENT-ON* */
+#endif /* __cplusplus */