/*
 * IPRPC - Inter Process Remote Procedure Call
 *
 * Copyright (C) 2012-2013 by Hiroyuki KAJIURA. All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 *
 *     1:Redistributions of source code must retain the above copyright notice, 
 *       this list of conditions and the following disclaimer.
 *     2:Redistributions in binary form must reproduce the above copyright notice, 
 *       this list of conditions and the following disclaimer in the documentation 
 *       and/or other materials provided with the distribution.
 *     3:Neither the name of copyright owner nor the names of its contributors 
 *       may be used to endorse or promote products derived from this software 
 *       without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#define	IPC_QUE_MAIN

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

#include	"ipcInfo.h"
#include	"ipcType.h"
#include	"ipcLog.h"
#include	"ipcSyscall.h"
#include	"ipcLib.h"
#include	"rpcMsg.h"
#include	"ipcShm.h"
#include	"ipcQue.h"
#include	"ipcRendezv.h"

#define	IPC_QUE_START_ID			(1)

typedef struct _IPC_QUE_MANAGE_ {
	RpcMutexID_t queMutex;
	RpcMutexAttribute_t queMutexAttr;
#ifdef	USE_DOUBLE_COND_IN_QUE
	RpcCondID_t emptyCondId;
	RpcCondAttribute_t emptyCondAttr;
	RpcCondID_t fullCondId;
	RpcCondAttribute_t fullCondAttr;
#else	/* USE_DOUBLE_COND_IN_QUE */
	RpcCondID_t queCondId;
	RpcCondAttribute_t queCondAttr;
#endif	/* USE_DOUBLE_COND_IN_QUE */
	uint32_t pid;
	uint32_t msgQueId;
	uint32_t *msgIdData;
	RpcMsgParam_t *msgParamData;
	uint32_t queTop;
	uint32_t queTail;
	uint32_t numOfMsg;
	uint32_t queSize;
	RpcBool_t enableFlag;
	uint32_t useCounter;
} IpcQueManage_t;

typedef struct {
	RpcMutexID_t queCtrlMutex;
	RpcMutexAttribute_t queCtrlMutexAttr;
	RpcList_t *queManageTop;
#ifdef	IPC_USE_HASH_FUNC_FOR_MSG_QUE
	RpcHashEntry_t *msgQueHashTable;
#endif	/* IPC_USE_HASH_FUNC_FOR_MSG_QUE */
	uint32_t queIdCounter;			/* This variable is only used in shared memori area */
} IpcQueControl_t;

static IpcQueControl_t *IpcMsgQueLclControl = (IpcQueControl_t*)NULL;
static IpcQueControl_t *IpcMsgQueShmControl = (IpcQueControl_t*)NULL;
static int IpcShmMsgQueFd = -1;

static RpcResult_t IPC_initQueInternal(RpcBool_t IpcFlag);
static RpcResult_t IPC_createQueInternal(RpcBool_t IpcFlag,uint32_t queSize, uint32_t *queId);
static RpcResult_t IPC_destroyQueInternal(RpcBool_t IpcFlag, uint32_t queId);
static RpcResult_t IPC_enableQueInternal(RpcBool_t IpcFlag,uint32_t queId);
static RpcResult_t IPC_disableQueInternal(RpcBool_t IpcFlag,uint32_t queId);
static RpcResult_t IPC_getMsgFromQueInernal(IpcQueManage_t *queManage, uint32_t *msgId, RpcMsgParam_t *msgParam, uint32_t timeout);
static RpcResult_t IPC_sweepMsgFromQueInternal(IpcQueManage_t *queManage, uint32_t *msgId, RpcMsgParam_t *msgParam);
static RpcResult_t IPC_putMsgToQueInternal(IpcQueManage_t *queManage, uint32_t msgId, RpcMsgParam_t *msgParam, uint32_t timeout);
static RpcResult_t IPC_putMsgToQueUrgentInternal(IpcQueManage_t *queManage, uint32_t msgId, RpcMsgParam_t *msgParam, uint32_t timeout);
static RpcResult_t IPC_getNumOfMsgInternal(IpcQueManage_t *queManage, uint32_t *numOfMsg);
static RpcResult_t IPC_checkTimeoutForQue(uint32_t timeout,RpcBool_t *waitForever,struct timespec *specTime);
static uint32_t IPC_getNewQueId(void);
static RpcBool_t IPC_checkDuplicateQueId(IpcQueControl_t *gmqcp, IpcQueControl_t *lmqcp,uint32_t queId);
static IpcQueManage_t *IPC_getQueManage(RpcBool_t IpcFlag,uint32_t queId);
static void *IPC_queAllocMem(RpcBool_t IpcFlag,uint32_t size);
static void IPC_queFreeMem(RpcBool_t IpcFlag,void *addr);
static IpcQueControl_t *IPC_getQueCtrl(RpcBool_t IpcFlag);

static RpcBool_t IPC_compareQueInternalByQueId(RpcList_t *list,uint32_t queId);

#ifdef	USE_CANCEL_TASK
static void IPC_msgQueCleanup(void *arg);
#endif	/* USE_CANCEL_TASK */

#ifdef	IPC_USE_HASH_FUNC_FOR_MSG_QUE
static RpcHashEntry_t *IPC_initMsgQueHash(RpcBool_t IpcFlag,uint32_t hashTableSize);
static RpcBool_t IPC_compareQueIdbyHash(void *entry, uint8_t *val, uint32_t valSize);
#endif	/* IPC_USE_HASH_FUNC_FOR_MSG_QUE */

static void IPC_printListData(RpcBool_t IpcFlag,IpcQueControl_t *mqcp );
#ifdef	IPC_USE_HASH_FUNC_FOR_MSG_QUE
static void IPC_printQueHash(RpcBool_t IpcFlag, IpcQueControl_t *mqcp);
#endif	/* IPC_USE_HASH_FUNC_FOR_MSG_QUE */

/* ----- IPC-QUEUE APIs ----- */

extern RpcResult_t IPC_InitQue(RpcBool_t masterProcess,RpcBool_t IpcFlag) {
	if(IpcFlag)
		return IPC_InitExtQue(masterProcess);
	else
		return IPC_initQueInternal(RPC_FALSE);
}

extern RpcResult_t IPC_CreateQue(RpcBool_t IpcFlag,uint32_t queSize, uint32_t *queId) {
	return IPC_createQueInternal(IpcFlag,queSize,queId);
}

extern RpcResult_t IPC_DestroyQue(uint32_t queId) {
	RpcResult_t ret;

	if((ret = IPC_destroyQueInternal(RPC_FALSE, queId)) == RPC_SUCCESS) {
		return ret;
	}
	else if((ret == RPC_PARAM_ERROR)||(ret == RPC_NOT_READY)){
		return IPC_destroyQueInternal(RPC_TRUE, queId);
	}
	else {
		return ret;
	}
}

extern RpcResult_t IPC_EnableQue(uint32_t queId) {
	RpcResult_t ret;

//	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"IN IPC_EnableQue pid:0x%x; queId:0x%x;", RPC_GetPid(), queId);
	if((ret = IPC_enableQueInternal(RPC_FALSE, queId)) == RPC_SUCCESS) {
		return ret;
	}
	else if((ret == RPC_PARAM_ERROR)||(ret == RPC_NOT_READY)) {
		return IPC_enableQueInternal(RPC_TRUE, queId);
	}
	else {
		return ret;
	}
}

extern RpcResult_t IPC_DisableQue(uint32_t queId) {
	RpcResult_t ret;

	if((ret = IPC_disableQueInternal(RPC_FALSE, queId)) == RPC_SUCCESS) {
		return ret;
	}
	else if((ret == RPC_PARAM_ERROR)||(ret == RPC_NOT_READY)) {
		return IPC_disableQueInternal(RPC_TRUE,queId);
	}
	else {
		return ret;
	}
}

extern RpcResult_t IPC_GetMsgFromQue(uint32_t queId, uint32_t *msgId, RpcMsgParam_t *msgParam, uint32_t timeout) {
	IpcQueManage_t *queManage;

//	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1, "IN IPC_GetMsgFromQue queId:0x%x; msgId:0x%x; msgParam:0x%x, timeout:%d;",queId,msgId,msgParam,timeout);
	if((msgId == (uint32_t*)NULL)||(msgParam == (RpcMsgParam_t*)NULL)) {
		return RPC_PARAM_ERROR;
	}
//	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1, "     pid:0x%x;",RPC_GetPid());
	if((queManage = IPC_getQueManage(RPC_FALSE, queId)) != (IpcQueManage_t*)NULL) {
		return IPC_getMsgFromQueInernal(queManage,msgId,msgParam,timeout);
	}
	else if((queManage = IPC_getQueManage(RPC_TRUE, queId)) != (IpcQueManage_t*)NULL) {
		return IPC_getMsgFromQueInernal(queManage,msgId,msgParam,timeout);
	}
	else {
		*msgId = 0;
		return RPC_PARAM_ERROR;
	}
}

extern RpcResult_t IPC_SweepMsgFromQue(uint32_t queId, uint32_t *msgId, RpcMsgParam_t *msgParam) {
	IpcQueManage_t *queManage;

	if((msgId == (uint32_t*)NULL)||(msgParam == (RpcMsgParam_t*)NULL)) {
		return RPC_PARAM_ERROR;
	}
	if((queManage = IPC_getQueManage(RPC_FALSE, queId)) != (IpcQueManage_t*)NULL) {
		return IPC_sweepMsgFromQueInternal(queManage,msgId,msgParam);
	}
	else if((queManage = IPC_getQueManage(RPC_TRUE, queId)) != (IpcQueManage_t*)NULL) {
		return IPC_sweepMsgFromQueInternal(queManage,msgId,msgParam);
	}
	else {
		*msgId = 0;
		return RPC_PARAM_ERROR;
	}
}

extern RpcResult_t IPC_PutMsgToQue(uint32_t queId, uint32_t msgId, RpcMsgParam_t *msgParam, uint32_t timeout) {
	IpcQueManage_t *queManage;

	if((queManage = IPC_getQueManage(RPC_FALSE, queId)) != (IpcQueManage_t*)NULL) {
		return IPC_putMsgToQueInternal(queManage, msgId, msgParam,timeout);
	}
	else if((queManage = IPC_getQueManage(RPC_TRUE, queId)) != (IpcQueManage_t*)NULL) {
		return IPC_putMsgToQueInternal(queManage, msgId, msgParam,timeout);
	}
	else {
		return RPC_PARAM_ERROR;
	}
}

extern RpcResult_t IPC_PutMsgToQueUrgent(uint32_t queId, uint32_t msgId, RpcMsgParam_t *msgParam, uint32_t timeout) {
	IpcQueManage_t *queManage;

	if((queManage = IPC_getQueManage(RPC_FALSE,  queId)) != (IpcQueManage_t*)NULL) {
		return IPC_putMsgToQueUrgentInternal(queManage, msgId, msgParam, timeout);
	}
	else if((queManage = IPC_getQueManage(RPC_TRUE, queId)) != (IpcQueManage_t*)NULL) {
		return IPC_putMsgToQueUrgentInternal(queManage, msgId, msgParam, timeout);
	}
	else {
		return RPC_PARAM_ERROR;
	}
}

extern RpcResult_t IPC_GetNumOfMsg(uint32_t queId, uint32_t *numOfMsg) {
	IpcQueManage_t *queManage;

	if(numOfMsg == (uint32_t*)NULL)
		return RPC_PARAM_ERROR;
	if((queManage = IPC_getQueManage(RPC_FALSE, queId)) != (IpcQueManage_t*)NULL) {
		return IPC_getNumOfMsgInternal(queManage, numOfMsg);
	}
	else if((queManage = IPC_getQueManage(RPC_TRUE, queId)) != (IpcQueManage_t*)NULL) {
		return IPC_getNumOfMsgInternal(queManage, numOfMsg);
	}
	else {
		*numOfMsg = 0;
		return RPC_PARAM_ERROR;
	}
}

#ifdef	USE_RENDEZVOUS
extern IpcRendezvControl_t *IPC_GetRendezvControl(void) {
	void *startAddr;uint32_t gapSize;IpcRendezvControl_t *rcp;

	if(IpcShmMsgQueFd == -1)
		return (IpcRendezvControl_t*)NULL;
	else {
		if(IPC_GetShmGapData(IpcShmMsgQueFd,&startAddr,&gapSize) != RPC_SUCCESS) {
			return (IpcRendezvControl_t*)NULL;
		}
#if	__WORDSIZE == 64
		rcp = (IpcRendezvControl_t*)((uint64_t)startAddr+sizeof(IpcQueControl_t));
#else	/* __WORDSIZE */
		rcp = (IpcRendezvControl_t*)((uint32_t)startAddr+sizeof(IpcQueControl_t));
#endif	/* __WORDSIZE */
		return rcp;
	}
}
#endif	/* USE_RENDEZVOUS */

/*--- SHM MSG QUE APIs ---*/

extern RpcResult_t IPC_InitExtQue(RpcBool_t masterProcess) {
	uint32_t fd; void *addr; uint32_t size;RpcResult_t ret;
	void *startArea;uint32_t gapSize;

//	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"IN IPC_InitExtQue PID:0x%x; masterProcess:%d;",RPC_GetPid(),masterProcess);
	if(IpcShmMsgQueFd != -1) {
		return RPC_SUCCESS;
	}
	if(IPC_GetShmInfo(IPC_MSG_QUE_SHARED_MEM_NAME, &fd, &addr, &size) != RPC_SUCCESS) {
		return RPC_FATAL_ERROR;
	}
	if((fd < 0)||(addr == (void*)NULL)||(size == 0)) {
		return RPC_FATAL_ERROR;
	}
//	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"     FD:0x%x; ADDR:0x%x; SIZE:%d;",fd, addr, size);
	if(masterProcess) {
		if((ret = IPC_InitShmGapArea(fd, IPC_SHM_MSG_QUE_GAP_SIZE)) != RPC_SUCCESS) {
			(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_FATAL,"ERROR IN IPC_InitShmArea:%s;",RPC_LogConvertResultCode(ret));
			return ret;
		}
		if((ret = IPC_InitShmAllocArea(fd, IPC_SHM_MSG_QUE_MEM_SIZE, IPC_SHM_MSG_QUE_NUM_OF_DEV, IPC_SHM_MSG_QUE_MIN_SIZE, IPC_SHM_MSG_QUE_RATE_OF_MAGNIFY)) != RPC_SUCCESS) {
			(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_FATAL,"ERROR IN IPC_InitShmAllocArea:%s;",RPC_LogConvertResultCode(ret));
			return ret;
		}
		if((ret = IPC_GetShmGapData(fd,&startArea,&gapSize)) != RPC_SUCCESS) {
			return RPC_FATAL_ERROR;
		}
		IpcMsgQueShmControl = (IpcQueControl_t*)startArea;
		IpcShmMsgQueFd = fd;
		if((ret = IPC_initQueInternal(RPC_TRUE)) != RPC_SUCCESS) {
			return ret;
		}
		IpcMsgQueShmControl->queIdCounter = IPC_QUE_START_ID;
	}
	else {
		if((ret = IPC_GetShmGapData(fd,&startArea,&gapSize)) != RPC_SUCCESS) {
			return RPC_FATAL_ERROR;
		}
		IpcMsgQueShmControl = (IpcQueControl_t*)startArea;
		IpcShmMsgQueFd = fd;
	}
//	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"OUT IPC_InitExtQue IpcShmMsgQueFd:0x%x; RET:0x%x;",IpcShmMsgQueFd,ret);
	return ret;
}

extern RpcResult_t IPC_CreateExtQue(uint32_t queSize, uint32_t *queId) {
	return IPC_createQueInternal(RPC_TRUE,queSize,queId);
}

extern RpcResult_t IPC_DestroyExtQue(uint32_t queId) {
	return IPC_destroyQueInternal(RPC_TRUE, queId);
}

extern RpcResult_t IPC_EnableExtQue( uint32_t queId) {
	return IPC_enableQueInternal(RPC_TRUE, queId);
}

extern RpcResult_t IPC_DisableExtQue(uint32_t queId) {
	return IPC_disableQueInternal(RPC_TRUE, queId);
}

extern RpcResult_t IPC_GetMsgFromExtQue(uint32_t queId, uint32_t *msgId, RpcMsgParam_t *msgParam, uint32_t timeout) {
	IpcQueManage_t *queManage;

	if((msgId == (uint32_t*)NULL)||(msgParam == (RpcMsgParam_t*)NULL)) {
		return RPC_PARAM_ERROR;
	}
	if((queManage = IPC_getQueManage(RPC_TRUE,queId)) != (IpcQueManage_t*)NULL) {
		return IPC_getMsgFromQueInernal(queManage,msgId,msgParam,timeout);
	}
	else {
		*msgId = 0;
		return RPC_PARAM_ERROR;
	}
}

extern RpcResult_t IPC_SweepMsgFromExtQue(uint32_t queId, uint32_t *msgId, RpcMsgParam_t *msgParam) {
	IpcQueManage_t *queManage;

	if((msgId == (uint32_t*)NULL)||(msgParam == (RpcMsgParam_t*)NULL)) {
		return RPC_PARAM_ERROR;
	}
	if((queManage = IPC_getQueManage(RPC_TRUE,queId)) != (IpcQueManage_t*)NULL) {
		return IPC_sweepMsgFromQueInternal(queManage,msgId,msgParam);
	}
	else {
		*msgId = 0;
		return RPC_PARAM_ERROR;
	}
}

extern RpcResult_t IPC_PutMsgToExtQue(uint32_t queId, uint32_t msgId, RpcMsgParam_t *msgParam, uint32_t timeout) {
	IpcQueManage_t *queManage;

	if((queManage = IPC_getQueManage(RPC_TRUE, queId)) != (IpcQueManage_t*)NULL) {
		return IPC_putMsgToQueInternal(queManage, msgId, msgParam,timeout);
	}
	else {
		return RPC_PARAM_ERROR;
	}
}

extern RpcResult_t IPC_PutMsgToExtQueUrgent(uint32_t queId, uint32_t msgId, RpcMsgParam_t *msgParam, uint32_t timeout) {
	IpcQueManage_t *queManage;

	if((queManage = IPC_getQueManage(RPC_TRUE,queId)) != (IpcQueManage_t*)NULL) {
		return IPC_putMsgToQueUrgentInternal(queManage, msgId, msgParam, timeout);
	}
	else {
		return RPC_PARAM_ERROR;
	}
}

extern RpcResult_t IPC_GetNumOfMsgExt(uint32_t queId, uint32_t *numOfMsg) {
	IpcQueManage_t *queManage;

	if(numOfMsg == (uint32_t*)NULL)
		return RPC_PARAM_ERROR;
	if((queManage = IPC_getQueManage(RPC_TRUE,queId)) != (IpcQueManage_t*)NULL) {
		return IPC_getNumOfMsgInternal(queManage, numOfMsg);
	}
	else {
		*numOfMsg = 0;
		return RPC_PARAM_ERROR;
	}
}

extern void IPC_PrintQueData(void) {
	IpcQueControl_t *gmqcp,*lmqcp;

	gmqcp = IPC_getQueCtrl(RPC_TRUE);
	lmqcp = IPC_getQueCtrl(RPC_FALSE);
	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"---------- PRINT QUE INFO PID:0x%x; ----------",RPC_GetPid());
	if(gmqcp != (IpcQueControl_t*)NULL) {
		(void)RPC_MutexLock(&(gmqcp->queCtrlMutex));
		IPC_printListData(RPC_TRUE,gmqcp);
#ifdef	IPC_USE_HASH_FUNC_FOR_MSG_QUE
		IPC_printQueHash(RPC_TRUE,gmqcp);
#endif	/* IPC_USE_HASH_FUNC_FOR_MSG_QUE */
		(void)RPC_MutexUnlock(&(gmqcp->queCtrlMutex));
	}
	if(lmqcp != (IpcQueControl_t*)NULL) {
		(void)RPC_MutexLock(&(lmqcp->queCtrlMutex));
		IPC_printListData(RPC_FALSE,lmqcp);
#ifdef	IPC_USE_HASH_FUNC_FOR_MSG_QUE
		IPC_printQueHash(RPC_FALSE,lmqcp);
#endif	/* IPC_USE_HASH_FUNC_FOR_MSG_QUE */
		(void)RPC_MutexUnlock(&(lmqcp->queCtrlMutex));
	}
	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"---------------------------------------------------");
}

/* ----- Internal Functions ----- */

static RpcResult_t IPC_initQueInternal(RpcBool_t IpcFlag) {
	IpcQueControl_t *mqcp;int pshared;
#ifdef	IPC_USE_HASH_FUNC_FOR_MSG_QUE
	RpcHashEntry_t *hashEntry;
#endif	/* IPC_USE_HASH_FUNC_FOR_MSG_QUE */

//	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"IN IPC_initQueInternal PID:0x%x; IpcFlag:%d;",RPC_GetPid(),IpcFlag);
	if(IpcFlag) {
		mqcp = IpcMsgQueShmControl;
#ifdef	IPC_USE_HASH_FUNC_FOR_MSG_QUE
		if((hashEntry = IPC_initMsgQueHash(RPC_TRUE,IPC_GLOBAL_MSG_QUE_HASH_TABLE)) == (RpcHashEntry_t*)NULL) {
			(void)IPC_queFreeMem(RPC_TRUE,mqcp);
			return RPC_NO_MORE_RESOURCE;
		}
		mqcp->msgQueHashTable = hashEntry;
#endif	/* IPC_USE_HASH_FUNC_FOR_MSG_QUE */
		pshared = PTHREAD_PROCESS_SHARED;
	}
	else {
		if((mqcp = (IpcQueControl_t*)IPC_queAllocMem(RPC_FALSE,sizeof(IpcQueControl_t))) == (IpcQueControl_t*)NULL) {
			return RPC_NO_MORE_RESOURCE;
		}
		IpcMsgQueLclControl = mqcp;
#ifdef	IPC_USE_HASH_FUNC_FOR_MSG_QUE
		if((hashEntry = IPC_initMsgQueHash(RPC_FALSE,IPC_LOCAL_MSG_QUE_HASH_TABLE)) == (RpcHashEntry_t*)NULL) {
			(void)IPC_queFreeMem(RPC_FALSE,mqcp);
			return RPC_NO_MORE_RESOURCE;
		}
		mqcp->msgQueHashTable = hashEntry;
#endif	/* IPC_USE_HASH_FUNC_FOR_MSG_QUE */
		pshared = PTHREAD_PROCESS_PRIVATE;
	}
	mqcp->queManageTop = (RpcList_t*)NULL;
	if(RPC_MutexAttrInit(&(mqcp->queCtrlMutexAttr)) != RPC_SUCCESS) {
		return RPC_FATAL_ERROR;
	}
#ifdef	_LINUX_
	if(RPC_MutexAttrSetType(&(mqcp->queCtrlMutexAttr), PTHREAD_MUTEX_ADAPTIVE_NP) != RPC_SUCCESS) {
		return RPC_FATAL_ERROR;
	}
#else	/* _LINUX_ */
	if(RPC_MutexAttrSetType(&(mqcp->queCtrlMutexAttr), PTHREAD_MUTEX_RECURSIVE) != RPC_SUCCESS) {
		return RPC_FATAL_ERROR;
	}
#endif	/* _LINUX_ */
	if(RPC_MutexAttrSetPshared(&(mqcp->queCtrlMutexAttr), pshared) != RPC_SUCCESS) {
		return RPC_FATAL_ERROR;
	}
	if(RPC_InitMutex(&(mqcp->queCtrlMutex),&(mqcp->queCtrlMutexAttr)) != RPC_SUCCESS) {
		return RPC_FATAL_ERROR;
	}
//	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"OUT IPC_initQueInternal PID:0x%x; MQCP:0x%x;",RPC_GetPid(),mqcp);
	return RPC_SUCCESS;
}

static RpcResult_t IPC_createQueInternal(RpcBool_t IpcFlag,uint32_t queSize, uint32_t *queId) {
	IpcQueManage_t *queManage;uint32_t *msgIdData;RpcMsgParam_t *msgParamData;
	IpcQueControl_t *mqcp;int pshared;RpcResult_t ret;uint32_t tmp;

//	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG2,"IN IPC_createQueInternal IpcFlag:%d; queSize:%d;",IpcFlag,queSize);
	*queId = IPC_QUE_ID_UNKNOWN;
	if((mqcp = IPC_getQueCtrl(IpcFlag)) == (IpcQueControl_t*)NULL) {
		return RPC_NOT_READY;
	}
	if((queSize > IPC_MSG_QUE_MAX_QUE_SIZE)||(queId == (uint32_t*)NULL))
		return RPC_PARAM_ERROR;
	tmp = IPC_getNewQueId();
	if((msgIdData = (uint32_t*)IPC_queAllocMem(IpcFlag, sizeof(uint32_t)*queSize)) == (uint32_t*)NULL) {
		return RPC_NO_MORE_RESOURCE;
	}
	if((msgParamData = (RpcMsgParam_t*)IPC_queAllocMem(IpcFlag, sizeof(RpcMsgParam_t)*queSize)) == (RpcMsgParam_t*)NULL) {
		IPC_queFreeMem(IpcFlag,(void*)msgIdData);
		return RPC_NO_MORE_RESOURCE;
	}
	if((ret = RPC_MutexLock(&(mqcp->queCtrlMutex))) != RPC_SUCCESS) {
		IPC_queFreeMem(IpcFlag,(void*)msgIdData);
		IPC_queFreeMem(IpcFlag,(void*)msgParamData);
		return ret;
	}
	if((queManage = (IpcQueManage_t*)RPC_AllocListData(&(mqcp->queManageTop),sizeof(IpcQueManage_t),(uint32_t)IpcFlag,IPC_queAllocMem,IPC_queFreeMem)) == (IpcQueManage_t*)NULL) {
		IPC_queFreeMem(IpcFlag,(void*)msgIdData);
		IPC_queFreeMem(IpcFlag,(void*)msgParamData);
		(void)RPC_MutexUnlock(&(mqcp->queCtrlMutex));
		return RPC_NO_MORE_RESOURCE;		
	}
	queManage->msgIdData = msgIdData;
	queManage->msgParamData = msgParamData;
	queManage->queSize = queSize;
	if(IpcFlag) {
		pshared = PTHREAD_PROCESS_SHARED;
	}
	else {
		pshared = PTHREAD_PROCESS_PRIVATE;
	}
	if(RPC_MutexAttrInit(&(queManage->queMutexAttr)) != RPC_SUCCESS) {
		goto fatalError;
	}
#ifdef	_LINUX_
	if(RPC_MutexAttrSetType(&(queManage->queMutexAttr), PTHREAD_MUTEX_ADAPTIVE_NP) != RPC_SUCCESS) {
		goto fatalError;
	}
#else	/* _LINUX_ */
	if(RPC_MutexAttrSetType(&(queManage->queMutexAttr), PTHREAD_MUTEX_RECURSIVE) != RPC_SUCCESS) {
		goto fatalError;
	}
#endif	/* _LINUX_ */
	if(RPC_MutexAttrSetPshared(&(queManage->queMutexAttr), pshared) != RPC_SUCCESS) {
		goto fatalError;
	}
	if(RPC_InitMutex(&(queManage->queMutex),&(queManage->queMutexAttr)) != RPC_SUCCESS) {
		goto fatalError;
	}
#ifdef	USE_DOUBLE_COND_IN_QUE
	if(RPC_CondAttrInit(&(queManage->emptyCondAttr)) != RPC_SUCCESS) {
		goto fatalError;
	}
	if(RPC_CondAttrSetPshared(&(queManage->emptyCondAttr), pshared) != RPC_SUCCESS) {
		goto fatalError;
	}
	if(RPC_InitCond(&(queManage->emptyCondId),&(queManage->emptyCondAttr)) != RPC_SUCCESS) {
		goto fatalError;
	}
	if(RPC_CondAttrInit(&(queManage->fullCondAttr)) != RPC_SUCCESS) {
		goto fatalError;
	}
	if(RPC_CondAttrSetPshared(&(queManage->fullCondAttr), pshared) != RPC_SUCCESS) {
		goto fatalError;
	}
	if(RPC_InitCond(&(queManage->fullCondId),&(queManage->fullCondAttr)) != RPC_SUCCESS) {
		goto fatalError;
	}
#else	/* USE_DOUBLE_COND_IN_QUE */
	if(RPC_CondAttrInit(&(queManage->queCondAttr)) != RPC_SUCCESS) {
		goto fatalError;
	}
	if(RPC_CondAttrSetPshared(&(queManage->queCondAttr), pshared) != RPC_SUCCESS) {
		goto fatalError;
	}
	if(RPC_InitCond(&(queManage->queCondId),&(queManage->queCondAttr)) != RPC_SUCCESS) {
		goto fatalError;
	}
#endif	/* USE_DOUBLE_COND_IN_QUE */
	queManage->queTail = 0;
	queManage->queTop = 0;
	queManage->numOfMsg = 0;
	queManage->enableFlag = RPC_FALSE;
	queManage->useCounter = 0;
	queManage->pid = RPC_GetPid();
	queManage->msgQueId = *queId = tmp;
#ifdef	IPC_USE_HASH_FUNC_FOR_MSG_QUE
	if(mqcp->msgQueHashTable != (RpcHashEntry_t*)NULL) {
		if((ret = RPC_AddHashEntry((void*)mqcp->msgQueHashTable,(void*)queManage,(void*)queId,sizeof(*queId), IpcFlag?IPC_GLOBAL_MSG_QUE_HASH_TABLE:IPC_LOCAL_MSG_QUE_HASH_TABLE)) != RPC_SUCCESS) {
			goto fatalError;
		}
	}
#endif	/* IPC_USE_HASH_FUNC_FOR_MSG_QUE */
	(void)RPC_MutexUnlock(&(mqcp->queCtrlMutex));
//	IPC_printListData(IpcFlag,mqcp);
//	IPC_printQueHash(IpcFlag,mqcp);
//	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG2,"OUT IPC_createQueInternal PID:0x%x; QUE-ID:0x%x;",
//		queManage->pid,*queId);
	return RPC_SUCCESS;

fatalError:
	IPC_queFreeMem(IpcFlag,(void*)msgIdData);
	IPC_queFreeMem(IpcFlag,(void*)msgParamData);
	RPC_FreeListData(&(mqcp->queManageTop),(void*)queManage,(uint32_t)IpcFlag,IPC_queFreeMem);
	(void)RPC_MutexUnlock(&(mqcp->queCtrlMutex));
	return RPC_FATAL_ERROR;
}

static RpcResult_t IPC_destroyQueInternal(RpcBool_t IpcFlag, uint32_t queId) {
	IpcQueManage_t *queManage;IpcQueControl_t *mqcp;

//	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"IN IPC_destroyQueInternal IpcFlag:%d; queId:0x%x;",IpcFlag, queId);
	if((mqcp = IPC_getQueCtrl(IpcFlag)) == (IpcQueControl_t*)NULL) {
		return RPC_NOT_READY;
	}
	if(RPC_MutexLock(&(mqcp->queCtrlMutex)) != RPC_SUCCESS) {
		return RPC_FATAL_ERROR;
	}
#ifdef	IPC_USE_HASH_FUNC_FOR_MSG_QUE
	if(mqcp->msgQueHashTable != (RpcHashEntry_t*)NULL) {
		if((queManage = (IpcQueManage_t*)RPC_SearchEntryByHash((void*)mqcp->msgQueHashTable,(void*)&queId,sizeof(queId), IpcFlag?IPC_GLOBAL_MSG_QUE_HASH_TABLE:IPC_LOCAL_MSG_QUE_HASH_TABLE,IPC_compareQueIdbyHash)) != (IpcQueManage_t*)NULL) {
			if((queManage->useCounter > 0)||(queManage->enableFlag)) {
				(void)RPC_MutexUnlock(&(mqcp->queCtrlMutex));
				return RPC_BUSY_ERROR;
			}
			(void)RPC_DeleteHashEntry((void*)mqcp->msgQueHashTable,(void*)&queId,sizeof(queId),  IpcFlag?IPC_GLOBAL_MSG_QUE_HASH_TABLE:IPC_LOCAL_MSG_QUE_HASH_TABLE,IPC_compareQueIdbyHash);
			IPC_queFreeMem(IpcFlag,(void*)queManage->msgIdData);
			IPC_queFreeMem(IpcFlag,(void*)queManage->msgParamData);
			RPC_FreeListData(&(mqcp->queManageTop),(void*)queManage,(uint32_t)IpcFlag,IPC_queFreeMem);
			(void)RPC_MutexUnlock(&(mqcp->queCtrlMutex));
			return RPC_SUCCESS;
		}
	}
	else {
		if((queManage = (IpcQueManage_t*)RPC_SearchListEntryById((RpcList_t*)mqcp->queManageTop,queId,IPC_compareQueInternalByQueId)) != (IpcQueManage_t*)NULL) {
			if((queManage->useCounter > 0)||(queManage->enableFlag)) {
				(void)RPC_MutexUnlock(&(mqcp->queCtrlMutex));
				return RPC_BUSY_ERROR;
			}
			IPC_queFreeMem(IpcFlag,(void*)queManage->msgIdData);
			IPC_queFreeMem(IpcFlag,(void*)queManage->msgParamData);
			RPC_FreeListData(&(mqcp->queManageTop),(void*)queManage,(uint32_t)IpcFlag,IPC_queFreeMem);
			(void)RPC_MutexUnlock(&(mqcp->queCtrlMutex));
			return RPC_SUCCESS;
		}
	}
#else	/* IPC_USE_HASH_FUNC_FOR_MSG_QUE */
	if((queManage = (IpcQueManage_t*)RPC_SearchListEntryById((RpcList_t*)mqcp->queManageTop,queId,IPC_compareQueInternalByQueId)) != (IpcQueManage_t*)NULL) {
		if((queManage->useCounter > 0)||(queManage->enableFlag)) {
			(void)RPC_MutexUnlock(&(mqcp->queCtrlMutex));
			return RPC_BUSY_ERROR;
		}
		IPC_queFreeMem(IpcFlag,(void*)queManage->msgIdData);
		IPC_queFreeMem(IpcFlag,(void*)queManage->msgParamData);
		RPC_FreeListData(&(mqcp->queManageTop),(void*)queManage,(uint32_t)IpcFlag,IPC_queFreeMem);
		(void)RPC_MutexUnlock(&(mqcp->queCtrlMutex));
		return RPC_SUCCESS;
	}
#endif	/* IPC_USE_HASH_FUNC_FOR_MSG_QUE */
	(void)RPC_MutexUnlock(&(mqcp->queCtrlMutex));
	return RPC_PARAM_ERROR;
}

static RpcResult_t IPC_enableQueInternal(RpcBool_t IpcFlag, uint32_t queId) {
	IpcQueManage_t *queManage;
	IpcQueControl_t *mqcp;

//	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"IN IPC_enableQueInternal IpcFlag:%d; queId:0x%x;",IpcFlag, queId);
	if((mqcp = IPC_getQueCtrl(IpcFlag)) == (IpcQueControl_t*)NULL) {
//		(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"IPC_enableQueInternal:PASS1");
		return RPC_NOT_READY;
	}

//	IPC_printListData(IpcFlag,mqcp );
//	IPC_printQueHash(IpcFlag, mqcp);
//	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG3,"    NOW MUTEX LOCK MUTEX:0x%x;",mqcp->queCtrlMutex);
	if(RPC_MutexLock(&(mqcp->queCtrlMutex)) != RPC_SUCCESS) {
//		(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"IPC_enableQueInternal:PASS2");
		return RPC_FATAL_ERROR;
	}
//	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG3,"    NOW SEARCH QUE");
#ifdef	IPC_USE_HASH_FUNC_FOR_MSG_QUE
	if(mqcp->msgQueHashTable != (RpcHashEntry_t*)NULL) {
		if((queManage = (IpcQueManage_t*)RPC_SearchEntryByHash((void*)mqcp->msgQueHashTable,(void*)&queId,sizeof(queId), IpcFlag?IPC_GLOBAL_MSG_QUE_HASH_TABLE:IPC_LOCAL_MSG_QUE_HASH_TABLE,IPC_compareQueIdbyHash)) == (IpcQueManage_t*)NULL) {
			(void)RPC_MutexUnlock(&(mqcp->queCtrlMutex));
			return RPC_PARAM_ERROR;
		}
	}
	else {
		if((queManage = (IpcQueManage_t*)RPC_SearchListEntryById((RpcList_t*)mqcp->queManageTop,queId,IPC_compareQueInternalByQueId)) == (IpcQueManage_t*)NULL) {
			(void)RPC_MutexUnlock(&(mqcp->queCtrlMutex));
			return RPC_PARAM_ERROR;
		}
	}
#else	/* IPC_USE_HASH_FUNC_FOR_MSG_QUE */
	if((queManage = (IpcQueManage_t*)RPC_SearchListEntryById((RpcList_t*)mqcp->queManageTop,queId,IPC_compareQueInternalByQueId)) == (IpcQueManage_t*)NULL) {
		(void)RPC_MutexUnlock(&(mqcp->queCtrlMutex));
		return RPC_PARAM_ERROR;
	}
#endif	/* IPC_USE_HASH_FUNC_FOR_MSG_QUE */
	if(RPC_MutexLock(&(queManage->queMutex)) != RPC_SUCCESS) {
		(void)RPC_MutexUnlock(&(mqcp->queCtrlMutex));
//		(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"IPC_enableQueInternal:PASS3");
		return RPC_FATAL_ERROR;
	}
	queManage->enableFlag = RPC_TRUE;
	(void)RPC_MutexUnlock(&(queManage->queMutex));
	(void)RPC_MutexUnlock(&(mqcp->queCtrlMutex));
//	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"OUT IPC_enableQueInternal IpcFlag:%d; queId:0x%x;",IpcFlag, queId);
	return RPC_SUCCESS;
}

static RpcResult_t IPC_disableQueInternal(RpcBool_t IpcFlag, uint32_t queId) {
	IpcQueManage_t *queManage;
	IpcQueControl_t *mqcp;

//	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"IN IPC_disableQueInternal IpcFlag:%d; queId:0x%x;",IpcFlag, queId);
	if((mqcp = IPC_getQueCtrl(IpcFlag)) == (IpcQueControl_t*)NULL) {
		return RPC_NOT_READY;
	}
	if(RPC_MutexLock(&(mqcp->queCtrlMutex)) != RPC_SUCCESS) {
		return RPC_FATAL_ERROR;
	}
#ifdef	IPC_USE_HASH_FUNC_FOR_MSG_QUE
	if(mqcp->msgQueHashTable != (RpcHashEntry_t*)NULL) {
		if((queManage = (IpcQueManage_t*)RPC_SearchEntryByHash((void*)mqcp->msgQueHashTable,(void*)&queId,sizeof(queId), IpcFlag?IPC_GLOBAL_MSG_QUE_HASH_TABLE:IPC_LOCAL_MSG_QUE_HASH_TABLE,IPC_compareQueIdbyHash)) == (IpcQueManage_t*)NULL) {
			(void)RPC_MutexUnlock(&(mqcp->queCtrlMutex));
			return RPC_PARAM_ERROR;
		}
	}
	else {
		if((queManage = (IpcQueManage_t*)RPC_SearchListEntryById((RpcList_t*)mqcp->queManageTop,queId,IPC_compareQueInternalByQueId)) == (IpcQueManage_t*)NULL) {
			(void)RPC_MutexUnlock(&(mqcp->queCtrlMutex));
			return RPC_PARAM_ERROR;
		}
	}
#else	/* IPC_USE_HASH_FUNC_FOR_MSG_QUE */
	if((queManage = (IpcQueManage_t*)RPC_SearchListEntryById((RpcList_t*)mqcp->queManageTop,queId,IPC_compareQueInternalByQueId)) == (IpcQueManage_t*)NULL) {
		(void)RPC_MutexUnlock(&(mqcp->queCtrlMutex));
		return RPC_PARAM_ERROR;
	}
#endif	/* IPC_USE_HASH_FUNC_FOR_MSG_QUE */
	if(RPC_MutexLock(&(queManage->queMutex)) != RPC_SUCCESS) {
		return RPC_FATAL_ERROR;
	}
	queManage->enableFlag = RPC_FALSE;
#if	USE_DOUBLE_COND_IN_QUE
	(void)RPC_CondBroadcast(&(queManage->fullCondId));
	(void)RPC_CondBroadcast(&(queManage->emptyCondId));
#else	/* USE_DOUBLE_COND_IN_QUE */
	(void)RPC_CondBroadcast(&(queManage->queCondId));
#endif	/* USE_DOUBLE_COND_IN_QUE */
	(void)RPC_MutexUnlock(&(queManage->queMutex));
	(void)RPC_MutexUnlock(&(mqcp->queCtrlMutex));
	return RPC_SUCCESS;
}

static RpcResult_t IPC_getMsgFromQueInernal(IpcQueManage_t *queManage, uint32_t *msgId, RpcMsgParam_t *msgParam, uint32_t timeout) {
	struct timespec specTime;RpcBool_t waitForever;RpcResult_t ret;

//	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1, "IN IPC_getMsgFromQueInernal queManage:0x%x; msgId:0x%x; msgParam:0x%x; timeout:%d;",queManage,msgId,msgParam,timeout);
	*msgId = 0;
	if(RPC_MutexLock(&(queManage->queMutex)) != RPC_SUCCESS) {
		(queManage->useCounter)--;
		return RPC_FATAL_ERROR;
	}
	if((ret = IPC_checkTimeoutForQue(timeout,&waitForever,&specTime)) != RPC_SUCCESS) {
		(queManage->useCounter)--;
		(void)RPC_MutexUnlock(&(queManage->queMutex));
		return ret;
	}
	if(!(queManage->enableFlag)) {
		(queManage->useCounter)--;
		(void)RPC_MutexUnlock(&(queManage->queMutex));
		return RPC_BUSY_ERROR;
	}
#ifdef	USE_CANCEL_TASK
	RPC_TaskPushCleanup(IPC_msgQueCleanup,(void*)queManage);
#endif	/* USE_CANCEL_TASK */
	for(;;) {
		if(queManage->numOfMsg > 0) {
			break;
		}
		else {
			if(waitForever) {
#if	USE_DOUBLE_COND_IN_QUE
				ret = RPC_CondWait(&(queManage->emptyCondId), &(queManage->queMutex));
#else	/* USE_DOUBLE_COND_IN_QUE */
				ret = RPC_CondWait(&(queManage->queCondId), &(queManage->queMutex));
#endif	/* USE_DOUBLE_COND_IN_QUE */
			}
			else {
#if	USE_DOUBLE_COND_IN_QUE
				ret = RPC_CondWaitTimeout(&(queManage->emptyCondId), &(queManage->queMutex), &specTime);
#else	/* USE_DOUBLE_COND_IN_QUE */
				ret = RPC_CondWaitTimeout(&(queManage->queCondId), &(queManage->queMutex), &specTime);
#endif	/* USE_DOUBLE_COND_IN_QUE */
			}
			if(ret == RPC_SUCCESS) {
				if(!(queManage->enableFlag)) {
					(queManage->useCounter)--;
					(void)RPC_MutexUnlock(&(queManage->queMutex));
					return RPC_BUSY_ERROR;
				}
				continue;
			}
			else if(ret == RPC_TIMEOUT_ERROR) {
				(queManage->useCounter)--;
				(void)RPC_MutexUnlock(&(queManage->queMutex));
				return RPC_TIMEOUT_ERROR;
			}
			else {
				(queManage->useCounter)--;
				(void)RPC_MutexUnlock(&(queManage->queMutex));
				return RPC_FATAL_ERROR;
			}
		}
	}
#ifdef	USE_CANCEL_TASK
	RPC_TaskPopCleanup(0);
#endif	/* USE_CANCEL_TASK */
	*msgId = queManage->msgIdData[queManage->queTop];
	(void)memcpy((void*)msgParam,(void*)&(queManage->msgParamData[queManage->queTop]),sizeof(RpcMsgParam_t));
	(queManage->numOfMsg)--;
	queManage->queTop = ((queManage->queTop)+1)%(queManage->queSize);
#if	0
#ifdef	USE_DOUBLE_COND_IN_QUE
	(void)RPC_CondSignal(&(queManage->fullCondId));
#else	/* USE_DOUBLE_COND_IN_QUE */
	(void)RPC_CondBroadcast(&(queManage->queCondId));
#endif	/* USE_DOUBLE_COND_IN_QUE */
	(queManage->useCounter)--;
	(void)RPC_MutexUnlock(&(queManage->queMutex));
#else	/* 0 */
	(queManage->useCounter)--;
	(void)RPC_MutexUnlock(&(queManage->queMutex));
#ifdef	USE_DOUBLE_COND_IN_QUE
	(void)RPC_CondSignal(&(queManage->fullCondId));
#else	/* USE_DOUBLE_COND_IN_QUE */
	(void)RPC_CondBroadcast(&(queManage->queCondId));
#endif	/* USE_DOUBLE_COND_IN_QUE */
#endif	/* 0 */
	return RPC_SUCCESS;
}

static RpcResult_t IPC_sweepMsgFromQueInternal(IpcQueManage_t *queManage, uint32_t *msgId, RpcMsgParam_t *msgParam) {
	*msgId = 0;
	if(RPC_MutexLock(&(queManage->queMutex)) != RPC_SUCCESS) {
		(queManage->useCounter)--;
		return RPC_FATAL_ERROR;
	}
	if(queManage->numOfMsg <= 0) {
		(queManage->useCounter)--;
		(void)RPC_MutexUnlock(&(queManage->queMutex));
		return RPC_NO_MORE_RESOURCE;
	}
	*msgId = queManage->msgIdData[queManage->queTop];
	(void)memcpy((void*)msgParam,(void*)&(queManage->msgParamData[queManage->queTop]),sizeof(RpcMsgParam_t));
	(queManage->numOfMsg)--;
	queManage->queTop = ((queManage->queTop)+1)%(queManage->queSize);
#if	0
#ifdef	USE_DOUBLE_COND_IN_QUE
	(void)RPC_CondSignal(&(queManage->fullCondId));
#else	/* USE_DOUBLE_COND_IN_QUE */
	(void)RPC_CondBroadcast(&(queManage->queCondId));
#endif	/* USE_DOUBLE_COND_IN_QUE */
	(queManage->useCounter)--;
	(void)RPC_MutexUnlock(&(queManage->queMutex));
#else	/* 0 */
	(queManage->useCounter)--;
	(void)RPC_MutexUnlock(&(queManage->queMutex));
#ifdef	USE_DOUBLE_COND_IN_QUE
	(void)RPC_CondSignal(&(queManage->fullCondId));
#else	/* USE_DOUBLE_COND_IN_QUE */
	(void)RPC_CondBroadcast(&(queManage->queCondId));
#endif	/* USE_DOUBLE_COND_IN_QUE */
#endif	/* 0 */
	return RPC_SUCCESS;
}

static RpcResult_t IPC_putMsgToQueInternal(IpcQueManage_t *queManage, uint32_t msgId, RpcMsgParam_t *msgParam, uint32_t timeout) {
	struct timespec specTime;RpcBool_t waitForever;RpcResult_t ret;

	if(RPC_MutexLock(&(queManage->queMutex)) != RPC_SUCCESS) {
		(queManage->useCounter)--;
		return RPC_FATAL_ERROR;
	}
	if((ret = IPC_checkTimeoutForQue(timeout,&waitForever,&specTime)) != RPC_SUCCESS) {
		(queManage->useCounter)--;
		(void)RPC_MutexUnlock(&(queManage->queMutex));
		return ret;
	}
	if(!(queManage->enableFlag)) {
		(queManage->useCounter)--;
		(void)RPC_MutexUnlock(&(queManage->queMutex));
		return RPC_BUSY_ERROR;
	}
#ifdef	USE_CANCEL_TASK
	RPC_TaskPushCleanup(IPC_msgQueCleanup,(void*)queManage);
#endif	/* USE_CANCEL_TASK */
	for(;;) {
		if(queManage->numOfMsg < queManage->queSize) {
			break;
		}
		else {
			if(waitForever) {
#ifdef	USE_DOUBLE_COND_IN_QUE
				ret = RPC_CondWait(&(queManage->fullCondId), &(queManage->queMutex));
#else	/* USE_DOUBLE_COND_IN_QUE */
				ret = RPC_CondWait(&(queManage->queCondId), &(queManage->queMutex));
#endif	/* UDE_DOUBLE_COND_IN_QUE */
			}
			else {
#ifdef	USE_DOUBLE_COND_IN_QUE
				ret = RPC_CondWaitTimeout(&(queManage->fullCondId), &(queManage->queMutex), &specTime);
#else	/* USE_DOUBLE_COND_IN_QUE */
				ret = RPC_CondWaitTimeout(&(queManage->queCondId), &(queManage->queMutex), &specTime);
#endif	/* UDE_DOUBLE_COND_IN_QUE */
			}
			if(ret == RPC_SUCCESS) {
				if(!(queManage->enableFlag)) {
					(queManage->useCounter)--;
					(void)RPC_MutexUnlock(&(queManage->queMutex));
					return RPC_BUSY_ERROR;
				}
				continue;
			}
			else if(ret == RPC_TIMEOUT_ERROR) {
				(queManage->useCounter)--;
				(void)RPC_MutexUnlock(&(queManage->queMutex));
				return RPC_TIMEOUT_ERROR;
			}
			else {
				(queManage->useCounter)--;
				(void)RPC_MutexUnlock(&(queManage->queMutex));
				return RPC_FATAL_ERROR;
			}
		}
	}
#ifdef	USE_CANCEL_TASK
	RPC_TaskPopCleanup(0);
#endif	/* USE_CANCEL_TASK */
	queManage->msgIdData[queManage->queTail] = msgId;
	if(msgParam == (RpcMsgParam_t*)NULL) {
		(void)memset((void*)&(queManage->msgParamData[queManage->queTail]),0,sizeof(RpcMsgParam_t));
	}
	else {
		(void)memcpy((void*)&(queManage->msgParamData[queManage->queTail]),(void*)msgParam,sizeof(RpcMsgParam_t));
	}
	(queManage->numOfMsg)++;
	queManage->queTail = ((queManage->queTail)+1)%(queManage->queSize);
#if	0
#ifdef	USE_DOUBLE_COND_IN_QUE
	(void)RPC_CondSignal(&(queManage->emptyCondId));
#else	/* USE_DOUBLE_COND_IN_QUE */
	(void)RPC_CondBroadcast(&(queManage->queCondId));
#endif	/* USE_DOUBLE_COND_IN_QUE */
	(queManage->useCounter)--;
	(void)RPC_MutexUnlock(&(queManage->queMutex));
#else	/* 0 */
	(queManage->useCounter)--;
	(void)RPC_MutexUnlock(&(queManage->queMutex));
#ifdef	USE_DOUBLE_COND_IN_QUE
	(void)RPC_CondSignal(&(queManage->emptyCondId));
#else	/* USE_DOUBLE_COND_IN_QUE */
	(void)RPC_CondBroadcast(&(queManage->queCondId));
#endif	/* USE_DOUBLE_COND_IN_QUE */
#endif	/* 0 */
	return RPC_SUCCESS;
}

static RpcResult_t IPC_putMsgToQueUrgentInternal(IpcQueManage_t *queManage, uint32_t msgId, RpcMsgParam_t *msgParam, uint32_t timeout) {
	struct timespec specTime;RpcBool_t waitForever;RpcResult_t ret;

	if(RPC_MutexLock(&(queManage->queMutex)) != RPC_SUCCESS) {
		(queManage->useCounter)--;
		return RPC_FATAL_ERROR;
	}
	if((ret = IPC_checkTimeoutForQue(timeout,&waitForever,&specTime)) != RPC_SUCCESS) {
		(queManage->useCounter)--;
		(void)RPC_MutexUnlock(&(queManage->queMutex));
		return ret;
	}
	if(!(queManage->enableFlag)) {
		(queManage->useCounter)--;
		(void)RPC_MutexUnlock(&(queManage->queMutex));
		return RPC_BUSY_ERROR;
	}
#ifdef	USE_CANCEL_TASK
	RPC_TaskPushCleanup(IPC_msgQueCleanup,(void*)queManage);
#endif	/* USE_CANCEL_TASK */
	for(;;) {
		if(queManage->numOfMsg < queManage->queSize) {
			break;
		}
		else {
			if(waitForever) {
#ifdef	USE_DOUBLE_COND_IN_QUE
				ret = RPC_CondWait(&(queManage->fullCondId), &(queManage->queMutex));
#else	/* USE_DOUBLE_COND_IN_QUE */
				ret = RPC_CondWait(&(queManage->queCondId), &(queManage->queMutex));
#endif	/* USE_DOUBLE_COND_IN_QUE */
			}
			else {
#ifdef	USE_DOUBLE_COND_IN_QUE
				ret = RPC_CondWaitTimeout(&(queManage->fullCondId), &(queManage->queMutex), &specTime);
#else	/* USE_DOUBLE_COND_IN_QUE */
				ret = RPC_CondWaitTimeout(&(queManage->queCondId), &(queManage->queMutex), &specTime);
#endif	/* USE_DOUBLE_COND_IN_QUE */
			}
			if(ret == RPC_SUCCESS) {
				if(!(queManage->enableFlag)) {
					(queManage->useCounter)--;
					(void)RPC_MutexUnlock(&(queManage->queMutex));
					return RPC_BUSY_ERROR;
				}
				continue;
			}
			else if(ret == RPC_TIMEOUT_ERROR) {
				(queManage->useCounter)--;
				(void)RPC_MutexUnlock(&(queManage->queMutex));
				return RPC_TIMEOUT_ERROR;
			}
			else {
				(queManage->useCounter)--;
				(void)RPC_MutexUnlock(&(queManage->queMutex));
				return RPC_FATAL_ERROR;
			}
		}
	}
#ifdef	USE_CANCEL_TASK
	RPC_TaskPopCleanup(0);
#endif	/* USE_CANCEL_TASK */
	if(queManage->queTop == 0)
		queManage->queTop = queManage->queSize - 1;
	else
		queManage->queTop -= 1;
	queManage->msgIdData[queManage->queTop] = msgId;
	if(msgParam == (RpcMsgParam_t*)NULL) {
		(void)memset((void*)&(queManage->msgParamData[queManage->queTop]),0,sizeof(RpcMsgParam_t));
	}
	else {
		(void)memcpy((void*)&(queManage->msgParamData[queManage->queTop]),(void*)msgParam,sizeof(RpcMsgParam_t));
	}
	(queManage->numOfMsg)++;
#if	0
#ifdef	USE_DOUBLE_COND_IN_QUE
	(void)RPC_CondSignal(&(queManage->emptyCondId));
#else	/* USE_DOUBLE_COND_IN_QUE */
	(void)RPC_CondBroadcast(&(queManage->queCondId));
#endif	/* USE_DOUBLE_COND_IN_QUE */
	(queManage->useCounter)--;
	(void)RPC_MutexUnlock(&(queManage->queMutex));
#else	/* 0 */
	(queManage->useCounter)--;
	(void)RPC_MutexUnlock(&(queManage->queMutex));
#ifdef	USE_DOUBLE_COND_IN_QUE
	(void)RPC_CondSignal(&(queManage->emptyCondId));
#else	/* USE_DOUBLE_COND_IN_QUE */
	(void)RPC_CondBroadcast(&(queManage->queCondId));
#endif	/* USE_DOUBLE_COND_IN_QUE */
#endif	/* 0 */
	return RPC_SUCCESS;
}

static RpcResult_t IPC_getNumOfMsgInternal(IpcQueManage_t *queManage, uint32_t *numOfMsg) {
	*numOfMsg = 0;
	if(RPC_MutexLock(&(queManage->queMutex)) != RPC_SUCCESS) {
		(queManage->useCounter)--;
		return RPC_FATAL_ERROR;
	}
	if(!(queManage->enableFlag)) {
		(queManage->useCounter)--;
		(void)RPC_MutexUnlock(&(queManage->queMutex));
		return RPC_BUSY_ERROR;
	}
	*numOfMsg = queManage->numOfMsg;
	(queManage->useCounter)--;
	(void)RPC_MutexUnlock(&(queManage->queMutex));
	return RPC_SUCCESS;
}

static RpcResult_t IPC_checkTimeoutForQue(uint32_t timeout,RpcBool_t *waitForever,struct timespec *specTime) {
	struct timeval absTime;

	*waitForever = RPC_FALSE;
	if(timeout == 0)
		timeout = IPC_MSG_QUE_DEFAULT_TIMEOUT;
	else if(timeout == IPC_MSG_QUE_WAIT_FOREVER) {
		timeout = IPC_MSG_QUE_DEFAULT_TIMEOUT;
		*waitForever = RPC_TRUE;
	}
	if(!(*waitForever)) {
		if(!RPC_SetTimeout(timeout,&absTime)) {
			return RPC_SYSCALL_ERROR;
		}
		if(!RPC_CheckTimeout(&absTime)) {
			return RPC_TIMEOUT_ERROR;
		}
		RPC_ConvertTime(&absTime,specTime);
	}
	return RPC_SUCCESS;
}

static uint32_t IPC_getNewQueId(void) {
	uint32_t ret;IpcQueControl_t *gmqcp,*lmqcp;

	gmqcp = IPC_getQueCtrl(RPC_TRUE);
	lmqcp = IPC_getQueCtrl(RPC_FALSE);
	if(gmqcp == (IpcQueControl_t*)NULL) {
		return IPC_QUE_ID_UNKNOWN;
	}
	if(RPC_MutexLock(&(gmqcp->queCtrlMutex)) != RPC_SUCCESS) {
		return IPC_QUE_ID_UNKNOWN;
	}
	if(lmqcp != (IpcQueControl_t*)NULL) {
		if(RPC_MutexLock(&(lmqcp->queCtrlMutex)) != RPC_SUCCESS) {
			(void)RPC_MutexUnlock(&(gmqcp->queCtrlMutex));
			return IPC_QUE_ID_UNKNOWN;
		}
	}
//	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG2,"  OK NOW ASSIGN NEW ID COUNTER:0x%x; VAL:%d;",
//		&(gmqcp->queIdCounter),gmqcp->queIdCounter);
	for(;;) {
		ret = (gmqcp->queIdCounter)++;
		if((ret == IPC_QUE_ID_UNKNOWN)||(ret == IPC_QUE_ID_MAX)) {
//			(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG2,"  RESET THE QUE ID COUNTER NUM IS 1 COUNTER:0x%x; VAL:%d;",
//				&(gmqcp->queIdCounter),gmqcp->queIdCounter);
			ret = gmqcp->queIdCounter = IPC_QUE_START_ID;
		}
		if(IPC_checkDuplicateQueId(gmqcp, lmqcp,ret))
			break;
	}
	(void)RPC_MutexUnlock(&(gmqcp->queCtrlMutex));
	if(lmqcp != (IpcQueControl_t*)NULL) (void)RPC_MutexUnlock(&(lmqcp->queCtrlMutex));
//	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG2,"   ASSIGN NEW NUM:0x%x;",ret);
	return ret;
}

static RpcBool_t IPC_checkDuplicateQueId(IpcQueControl_t *gmqcp, IpcQueControl_t *lmqcp,uint32_t queId) {
//	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG3,"IN IPC_checkDuplicateQueId PID:0x%x; queId:0x%x;",RPC_GetPid(), queId);
//	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG3,"   NOW CHECK GLOBAL QUE");
	if(gmqcp != NULL) {
#ifdef	IPC_USE_HASH_FUNC_FOR_MSG_QUE
		if(gmqcp->msgQueHashTable != (RpcHashEntry_t*)NULL) {
			if(RPC_SearchEntryByHash((void*)gmqcp->msgQueHashTable,(void*)&queId,sizeof(queId), IPC_GLOBAL_MSG_QUE_HASH_TABLE,IPC_compareQueIdbyHash) != (void*)NULL) {
				return RPC_FALSE;
			}
		}
		else {
			if(RPC_SearchListEntryById((void*)(gmqcp->queManageTop),(uint32_t)queId,IPC_compareQueInternalByQueId) != (void*)NULL) {
				return RPC_FALSE;
			}
		}
#else	/* IPC_USE_HASH_FUNC_FOR_MSG_QUE */
		if(RPC_SearchListEntryById((void*)(gmqcp->queManageTop),(uint32_t)queId,IPC_compareQueInternalByQueId) != (void*)NULL) {
			return RPC_FALSE;
		}
#endif	/*IPC_USE_HASH_FUNC_FOR_MSG_QUE */
	}
//	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG3,"   NOW CHECK LOCAL QUE");
	if(lmqcp != NULL) {
#ifdef	IPC_USE_HASH_FUNC_FOR_MSG_QUE
		if(lmqcp->msgQueHashTable != (RpcHashEntry_t*)NULL) {
			if(RPC_SearchEntryByHash((void*)lmqcp->msgQueHashTable,(void*)&queId,sizeof(queId), IPC_LOCAL_MSG_QUE_HASH_TABLE,IPC_compareQueIdbyHash) != (void*)NULL) {
				return RPC_FALSE;
			}
		}
		else {
			if(RPC_SearchListEntryById((void*)(lmqcp->queManageTop),(uint32_t)queId,IPC_compareQueInternalByQueId) != (void*)NULL) {
				return RPC_FALSE;
			}
		}
#else	/* IPC_USE_HASH_FUNC_FOR_MSG_QUE */
		if(RPC_SearchListEntryById((void*)(lmqcp->queManageTop),(uint32_t)queId,IPC_compareQueInternalByQueId) != (void*)NULL) {
			return RPC_FALSE;
		}
#endif	/* IPC_USE_HASH_FUNC_FOR_MSG_QUE */
	}
//	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG3,"OUT IPC_checkDuplicateQueId PID:0x%x;",RPC_GetPid());
	return RPC_TRUE;
}

static IpcQueManage_t *IPC_getQueManage(RpcBool_t IpcFlag, uint32_t queId) {
	IpcQueControl_t *mqcp;IpcQueManage_t *queManage;

//	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1, "IN IPC_getQueManage IpcFlag:%d; queId:0x%x;",IpcFlag,queId);
	if((mqcp = IPC_getQueCtrl(IpcFlag)) == (IpcQueControl_t*)NULL) {
		return (IpcQueManage_t*)NULL;
	}
//	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1, "     QUE CONTROL:0x%x;",mqcp);
	if(RPC_MutexLock(&(mqcp->queCtrlMutex)) != RPC_SUCCESS) {
		return (IpcQueManage_t*)NULL;
	}
#ifdef	IPC_USE_HASH_FUNC_FOR_MSG_QUE
	if(mqcp->msgQueHashTable != (RpcHashEntry_t*)NULL) {
		if((queManage = (IpcQueManage_t*)RPC_SearchEntryByHash((void*)mqcp->msgQueHashTable,(void*)&queId,sizeof(queId), IpcFlag?IPC_GLOBAL_MSG_QUE_HASH_TABLE:IPC_LOCAL_MSG_QUE_HASH_TABLE,IPC_compareQueIdbyHash)) != (IpcQueManage_t*)NULL) {
			(queManage->useCounter)++;
			(void)RPC_MutexUnlock(&(mqcp->queCtrlMutex));
//			(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1, "OUT IPC_getQueManage  ##### FIND #####");
			return queManage;
		}
	}
	else {
		if((queManage = (IpcQueManage_t*)RPC_SearchListEntryById((RpcList_t*)mqcp->queManageTop,queId,IPC_compareQueInternalByQueId)) != (IpcQueManage_t*)NULL) {
			(queManage->useCounter)++;
			(void)RPC_MutexUnlock(&(mqcp->queCtrlMutex));
//			(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1, "OUT IPC_getQueManage  ##### FIND #####");
			return queManage;
		}
	}
#else	/* IPC_USE_HASH_FUNC_FOR_MSG_QUE */
	if((queManage = (IpcQueManage_t*)RPC_SearchListEntryById((RpcList_t*)mqcp->queManageTop,queId,IPC_compareQueInternalByQueId)) != (IpcQueManage_t*)NULL) {
		(queManage->useCounter)++;
		(void)RPC_MutexUnlock(&(mqcp->queCtrlMutex));
//		(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1, "OUT IPC_getQueManage  ##### FIND #####");
		return queManage;
	}
#endif	/* IPC_USE_HASH_FUNC_FOR_MSG_QUE */
	(void)RPC_MutexUnlock(&(mqcp->queCtrlMutex));
//	IPC_printListData(IpcFlag, mqcp);
//	IPC_printQueHash(IpcFlag,mqcp);
//	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1, "OUT IPC_getQueManage  ##### NOT FIND #####");
	return (IpcQueManage_t*)NULL;
}

static void *IPC_queAllocMem(RpcBool_t IpcFlag,uint32_t size) {
	if(IpcFlag) {
		if(IpcShmMsgQueFd == -1) {
			return (void*)NULL;
		}
		else {
//			static int totalSize = 0;
//			totalSize += size;
//			(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"ALLOC FROM SHM PID:0x%x; IpcFlag:%d; size:%d; TOTAL:%d;",RPC_GetPid(),IpcFlag,size,totalSize);
			return IPC_AllocShmMem(IpcShmMsgQueFd, size);
		}
	}
	else {
		return RPC_AllocMem(size);
	}
}

static void IPC_queFreeMem(RpcBool_t IpcFlag,void *addr) {
	if(IpcFlag) {
		if(IpcShmMsgQueFd == -1) {
			return;
		}
		else {
			IPC_FreeShmMem(IpcShmMsgQueFd, addr);
		}
	}
	else {
		RPC_FreeMem(addr);
	}
	return;
}

static IpcQueControl_t *IPC_getQueCtrl(RpcBool_t IpcFlag) {
	if(IpcFlag) {
		return IpcMsgQueShmControl;
	}
	else {
		return IpcMsgQueLclControl;
	}
}

static RpcBool_t IPC_compareQueInternalByQueId(RpcList_t *list,uint32_t queId) {
	if(((IpcQueManage_t*)(list->entry))->msgQueId == queId) {
		return RPC_TRUE;
	}
	return RPC_FALSE;
}

#ifdef	USE_CANCEL_TASK
static void IPC_msgQueCleanup(void *arg) {
	IpcQueManage_t *queManage;

	queManage = (IpcQueManage_t*)arg;
	(queManage->useCounter)--;
	(void)RPC_MutexUnlock(&(queManage->queMutex));
}
#endif	/* USE_CANCEL_TASK */

#ifdef	IPC_USE_HASH_FUNC_FOR_MSG_QUE
static RpcHashEntry_t *IPC_initMsgQueHash(RpcBool_t IpcFlag,uint32_t hashTableSize) {
	RpcHashEntry_t *hashEntry;int i;

	if((hashEntry = (RpcHashEntry_t*)IPC_queAllocMem(IpcFlag,hashTableSize*sizeof(RpcHashEntry_t))) == (RpcHashEntry_t*)NULL) {
		return (RpcHashEntry_t*)NULL;
	}
	for(i = 0;i < hashTableSize;i++) {
		hashEntry[i].entry = (void*)NULL;
		hashEntry[i].usedFlag = RPC_FALSE;
	}
	return hashEntry;
}

static RpcBool_t IPC_compareQueIdbyHash(void *entry, uint8_t *val, uint32_t valSize) {
	return (memcmp((void*)&(((IpcQueManage_t*)entry)->msgQueId),val,valSize)==0)?RPC_TRUE:RPC_FALSE;
}
#endif	/* IPC_USE_HASH_FUNC_FOR_MSG_QUE */

#if	1
static void IPC_printListData(RpcBool_t IpcFlag, IpcQueControl_t *mqcp ) {
	RpcList_t *list;RpcList_t *listTop;

	listTop = mqcp->queManageTop;
//	(void)RPC_MutexLock(&(mqcp->queCtrlMutex));
	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1, "######## PRINT LIST FLAG:%d; TOP:0x%x; ########",IpcFlag, listTop);
	for(list = listTop;list != (RpcList_t*)NULL;list = list->next) {
		(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1, "    entry:0x%x; pid:0x%x; queId:0x%x; next:0x%x;",
			list->entry, ((IpcQueManage_t*)list->entry)->pid,((IpcQueManage_t*)list->entry)->msgQueId,list->next);
	}
	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"######### PRINT LIST END #########");
//	(void)RPC_MutexUnlock(&(mqcp->queCtrlMutex));
}

#ifdef	IPC_USE_HASH_FUNC_FOR_MSG_QUE
static void IPC_printQueHash(RpcBool_t IpcFlag, IpcQueControl_t *mqcp) {
	int i;uint32_t tblSize;RpcHashEntry_t *entryTop;

	entryTop = mqcp->msgQueHashTable;
	if(IpcFlag)
		tblSize = IPC_GLOBAL_MSG_QUE_HASH_TABLE;
	else
		tblSize = IPC_LOCAL_MSG_QUE_HASH_TABLE;
//	(void)RPC_MutexLock(&(mqcp->queCtrlMutex));
	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1, "######## PRINT HASH TBL FLAG:%d; TOP:0x%x; SIZE:%d; ########",IpcFlag, entryTop, tblSize);
	if(entryTop != NULL) {
		for(i = 0;i < tblSize;i++) {
			if(entryTop[i].entry != (void*)NULL) {
				(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"     I:%d; ENTRY:0x%x; FLAG:%d; QUE-MANAGE:0x%x;  -> PID:0x%x; QUEID:0x%x;",
					i, &(entryTop[i]), entryTop[i].usedFlag, entryTop[i].entry, ((IpcQueManage_t*)(entryTop[i].entry))->pid,((IpcQueManage_t*)(entryTop[i].entry))->msgQueId);
			}
		}
	}
	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"######### PRINT HASH TBL END #########");
//	(void)RPC_MutexUnlock(&(mqcp->queCtrlMutex));
}
#endif	/* IPC_USE_HASH_FUNC_FOR_MSG_QUE */
#endif	/* 0 */

/* ----- TEST Functions ----- */

#ifdef	DEBUG
static RpcResult_t globalQueTest(void);
static RpcResult_t localQueTest(void);
static void *queTestSendTask(void *param);
static void *queTestRecvTask(void *param);
static uint32_t getSleepTime(void);
static RpcBool_t getOnOff(void);

RpcResult_t queTest(RpcBool_t globalFlag);

RpcResult_t queTest(RpcBool_t globalFlag) {
	if(globalFlag)
		return globalQueTest();
	else
		return localQueTest();
}

static RpcResult_t globalQueTest(void) {
	RpcResult_t ret;uint32_t queId;

#if	0
	if((ret = IPC_InitSharedMem()) != RPC_SUCCESS) {
		(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_FATAL,"ERROR IN IPC_InitSharedMem ret:%s;",RPC_LogConvertResultCode(ret));
		return ret;
	}
	if((ret = IPC_AttachSharedMem()) != RPC_SUCCESS) {
		(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_FATAL,"ERROR IN IPC_AttachSharedMem ret:%s;",RPC_LogConvertResultCode(ret));
		(void)IPC_DestroySharedMem();
		return ret;
	}
	if((ret = IPC_InitQue(RPC_TRUE,RPC_TRUE)) != RPC_SUCCESS) {
//		fprintf(stderr,"IPC_QUE: ERROR IN IPC_InitQue\n");
		(void)IPC_DettachSharedMem();
		(void)IPC_DestroySharedMem();
		(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_FATAL,"ERROR IN IPC_InitQue ret:%s;",RPC_LogConvertResultCode(ret));
		return ret;
	}
#endif	/* 0 */
	if((ret = IPC_CreateQue(RPC_TRUE, 32, &queId)) != RPC_SUCCESS) {
//		fprintf(stderr,"IPC_QUE: ERROR IN IPC_CreateQue\n");
		(void)IPC_DettachSharedMem();
		(void)IPC_DestroySharedMem();
		(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_FATAL,"ERROR IN IPC_CreateQue:%s;",RPC_LogConvertResultCode(ret));
		return ret;
	}
	if((ret = IPC_EnableQue(queId)) != RPC_SUCCESS) {
		(void)IPC_DettachSharedMem();
		(void)IPC_DestroySharedMem();
		(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_FATAL,"ERROR IN EnableQue:%s;",RPC_LogConvertResultCode(ret));
		return ret;
	}



	if((ret = IPC_DisableQue(queId)) != RPC_SUCCESS) {
		(void)IPC_DettachSharedMem();
		(void)IPC_DestroySharedMem();
		(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_FATAL,"ERROR IN DisableQue:%s;",RPC_LogConvertResultCode(ret));
		return ret;
	}
	if((ret = IPC_DestroyQue(queId)) != RPC_SUCCESS) {
		(void)IPC_DettachSharedMem();
		(void)IPC_DestroySharedMem();
		(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_FATAL,"ERROR IN DestroyQue:%s;",RPC_LogConvertResultCode(ret));
		return ret;
	}
	(void)IPC_DettachSharedMem();
	(void)IPC_DestroySharedMem();
	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"END OF TEST");
	return RPC_SUCCESS;
}

static RpcResult_t localQueTest(void) {
	RpcResult_t ret;static uint32_t queId;
	RpcTaskID_t sendTask,recvTask;RpcTaskAttribute_t sendTaskAttr,recvTaskAttr;
	struct timeval curTime;
//	struct timeval sleepTime;
	uint32_t errCode;
//	uint32_t sTime;
	void *retVal;

#if	0
	if((ret = IPC_InitQue(RPC_TRUE,RPC_FALSE)) != RPC_SUCCESS) {
//		fprintf(stderr,"IPC_QUE: ERROR IN IPC_InitQue\n");
		(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_FATAL,"ERROR IN IPC_InitQue:0x%x;",ret);
		return ret;
	}
#endif	/* 0 */
	if((ret = IPC_CreateQue(RPC_FALSE, 32, &queId)) != RPC_SUCCESS) {
//		fprintf(stderr,"IPC_QUE: ERROR IN IPC_CreateQue\n");
		(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_FATAL,"ERROR IN IPC_CreateQue:%s;",RPC_LogConvertResultCode(ret));
		return ret;
	}
	if((ret = IPC_EnableQue(queId)) != RPC_SUCCESS) {
		(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_FATAL,"ERROR IN EnableQue:%s;",RPC_LogConvertResultCode(ret));
		return ret;
	}
	if((ret = RPC_TaskAttrInit(&sendTaskAttr)) != RPC_SUCCESS) {
		(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_FATAL,"ERROR IN TaskAttrInit:%s;",RPC_LogConvertResultCode(ret));
		return ret;
	}
	if((ret = RPC_TaskAttrInit(&recvTaskAttr)) != RPC_SUCCESS) {
		(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_FATAL,"ERROR IN TaskAttrInit:%s;",RPC_LogConvertResultCode(ret));
		return ret;
	}
	if((ret = RPC_CreateTask(&sendTask, &sendTaskAttr, queTestSendTask, (void*)&queId)) != RPC_SUCCESS) {
		(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_FATAL,"ERROR IN CreateTask:%s;",RPC_LogConvertResultCode(ret));
		return ret;
	}
	if((ret = RPC_CreateTask(&recvTask, &recvTaskAttr, queTestRecvTask, (void*)&queId)) != RPC_SUCCESS) {
		(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_FATAL,"ERROR IN CreateTask:%s;",RPC_LogConvertResultCode(ret));
		return ret;
	}
	if((ret == RPC_GetTimeOfDay(&curTime,NULL,&errCode)) != RPC_SUCCESS) {
		(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_FATAL,"ERROR IN GetTimeOfDay:%s; errCode:%d;",RPC_LogConvertResultCode(ret),errCode);
		return ret;
	}
	RPC_Srand((uint32_t)(curTime.tv_sec+curTime.tv_usec));
	if((ret = RPC_JoinTask(recvTask, &retVal)) != RPC_SUCCESS) {
		(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_FATAL,"ERROR IN JoinTask:%s;",RPC_LogConvertResultCode(ret));
		return ret;
	}
#if	0
	for(;;) {
		sTime = getSleepTime();
		RPC_ConvertTimeoutToTimeval(sTime,&sleepTime);
		if((ret = RPC_TaskSleep(&sleepTime,NULL)) != RPC_SUCCESS) {
			(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_FATAL,"ERROR IN Sleep:%s;",RPC_LogConvertResultCode(ret));
			return ret;
		}
	}
#endif	/* 0 */
	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"END OF TEST");
	return RPC_SUCCESS;
}

static void *queTestSendTask(void *param) {
	uint32_t queId;RpcBool_t onOff;uint32_t timeout;
	uint32_t msgId = 0;RpcMsgParam_t msgParam;int i;
	uint32_t pid;RpcResult_t ret = RPC_SUCCESS;
	uint32_t sTime;struct timeval sleepTime;

	pid = getpid();
	queId = *((uint32_t*)param);
	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"NOW START TEST TASK FOR SEND MSG TO QUE:0x%x;",queId);
	for(i = 0;i < 100;i++) {
		sTime = getSleepTime();
		sleepTime.tv_sec = sTime/10000;
		sleepTime.tv_usec = (sTime%10000) * 1000;
		(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"NOW SLEEP SEND TASK TIME:%d.%d;",sleepTime.tv_sec,sleepTime.tv_usec);
		(void)RPC_TaskSleep(&sleepTime,NULL);
		onOff = getOnOff();
		timeout = getSleepTime();
		if(ret == RPC_SUCCESS) {
			msgId = msgId+1;
			msgParam.u.msgParam.funcId = i;
			msgParam.u.msgParam.srcPid = pid;
			msgParam.u.msgParam.srcQueId = queId;
			msgParam.u.msgParam.seqNum = i;
			msgParam.u.msgParam.extData = 0;
			msgParam.u.msgParam.extParam = NULL;
		}
		if(onOff) {
//			(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"NOW SEND");
			if((ret = IPC_PutMsgToQue(queId,msgId,&msgParam,timeout)) != RPC_SUCCESS) {
				if(ret == RPC_TIMEOUT_ERROR) {
					(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"TIMEOUT IN MSG SEND timeout:%d;",timeout);
				}
				else {
					(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_FATAL,"ERROR IN PutMsgFromQue:%s;",RPC_LogConvertResultCode(ret));
					return (void*)ret;
				}
			}
			else {
				(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"SEND-MSG ID:0x%x; PARAM: FUNC:0x%x; SPID:0x%x; SQID:0x%x; SEQ-NUM:%d; EX-DATA:0x%x; EX-PARAM:0x%x;",
					msgId,msgParam.u.msgParam.funcId,msgParam.u.msgParam.srcPid,msgParam.u.msgParam.srcQueId,msgParam.u.msgParam.seqNum,msgParam.u.msgParam.extData,msgParam.u.msgParam.extParam);
			}
		}
		else {
//			(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"NOW SEND-URGET");
			if((ret = IPC_PutMsgToQueUrgent(queId,msgId,&msgParam,timeout)) != RPC_SUCCESS) {
				if(ret == RPC_TIMEOUT_ERROR) {
					(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"TIMEOUT IN MSG SEND URGENT timeout:%d;",timeout);
				}
				else {
					(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_FATAL,"ERROR IN PutMsgFromQueUrgent:%s;",RPC_LogConvertResultCode(ret));
					return (void*)ret;
				}
			}
			else {
				(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"SEND-MSG-URGET ID:0x%x; PARAM: FUNC:0x%x; SPID:0x%x; SQID:0x%x; SEQ-NUM:%d; EX-DATA:0x%x; EX-PARAM:0x%x;",
					msgId,msgParam.u.msgParam.funcId,msgParam.u.msgParam.srcPid,msgParam.u.msgParam.srcQueId,msgParam.u.msgParam.seqNum,msgParam.u.msgParam.extData,msgParam.u.msgParam.extParam);
			}
		}
	}
	if((ret = IPC_DisableQue(queId)) != RPC_SUCCESS) {
		(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_FATAL,"ERROR IN DisableQue:%s;",RPC_LogConvertResultCode(ret));
		return (void*)ret;
	}
	return (void*)NULL;
}

static void *queTestRecvTask(void *param) {
	uint32_t queId;RpcResult_t ret;uint32_t msgId;RpcMsgParam_t msgParam;uint32_t timeout;
	uint32_t sTime;struct timeval sleepTime;;RpcBool_t flag = RPC_TRUE;

	queId = *((uint32_t*)param);
	(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"NOW START TEST TASK FOR RECV MSG TO QUE:0x%x;",queId);
	for(;;) {
		if(flag) {
			sTime = getSleepTime();
			sleepTime.tv_sec = sTime/2000;
			sleepTime.tv_usec = (sTime%2000) * 1000;
			(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"NOW SLEEP RECV TASK TIME:%d.%d;",sleepTime.tv_sec,sleepTime.tv_usec);
			(void)RPC_TaskSleep(&sleepTime,NULL);
			timeout = getSleepTime();
			if((ret = IPC_GetMsgFromQue(queId,&msgId,&msgParam,timeout))!= RPC_SUCCESS) {
				if(ret == RPC_TIMEOUT_ERROR) {
					(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"TIMEOUT IN MSG RECV timeout:%d;",timeout);
				}
				else {
					(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_FATAL,"ERROR IN GetMsgFromQue:%s;",RPC_LogConvertResultCode(ret));
					flag = RPC_FALSE;
				}
			}
			else {
				(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"RECV-MSG ID:0x%x; PARAM: FUNC:0x%x; SPID:0x%x; SQID:0x%x; SEQ-NUM:%d; EX-DATA:0x%x; EX-PARAM:0x%x;",
					msgId,msgParam.u.msgParam.funcId,msgParam.u.msgParam.srcPid,msgParam.u.msgParam.srcQueId,msgParam.u.msgParam.seqNum,msgParam.u.msgParam.extData,msgParam.u.msgParam.extParam);
			}
		}
		else {
			if((ret = IPC_SweepMsgFromQue(queId,&msgId,&msgParam)) != RPC_SUCCESS) {
				(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_FATAL,"ERROR IN SweepMsgFromQue:%s;",RPC_LogConvertResultCode(ret));
				break;
			}
			else {
				(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_DEBUG1,"SWEEP-MSG ID:0x%x; PARAM: FUNC:0x%x; SPID:0x%x; SQID:0x%x; SEQ-NUM:%d; EX-DATA:0x%x; EX-PARAM:0x%x;",
					msgId,msgParam.u.msgParam.funcId,msgParam.u.msgParam.srcPid,msgParam.u.msgParam.srcQueId,msgParam.u.msgParam.seqNum,msgParam.u.msgParam.extData,msgParam.u.msgParam.extParam);
			}
		}
	}
	if((ret = IPC_DestroyQue(queId)) != RPC_SUCCESS) {
		(void)RPC_LogPrint(RPC_LOG_MODULE_MSG_QUE,RPC_LOG_LEVEL_FATAL,"ERROR IN DestroyQue:%s;",RPC_LogConvertResultCode(ret));
	}
	return (void*)NULL;
}

static uint32_t getSleepTime(void) {
	uint32_t sTime;

	do {
		sTime = RPC_Rand();
	} while((sTime < 0)||(sTime > 10000));
	return sTime;
}

static RpcBool_t getOnOff(void) {
	uint32_t sTime;

	sTime = getSleepTime();
	if(sTime > 5000)
		return RPC_TRUE;
	else
		return RPC_FALSE;
}

#endif	/* DEBUG */
