/*
 * 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_SHM_MAIN

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

#include	"ipcInfo.h"
#include	"ipcType.h"
#include	"ipcLog.h"
#include	"ipcShm.h"

static RpcBool_t IPC_MasterProcess = RPC_TRUE;

typedef struct {
	char *name;
	uint32_t length;
	int fd;
	void *addr;
} IpcShmManage_t;

typedef struct {
	void *startOfIpcAreaManageInfo;
	void *startOfGap;
	uint32_t gapSize;
	uint32_t alignment;
} IpcShmManageArea_t;

typedef struct {
	uint32_t numOfBlocks;
	uint32_t sizeOfBlock;
	void *topAddr;
	void *tailAddr;
	void *freeListTop;
} IpcFixedAreaInfo_t;

typedef struct {
	void *topAddr;
	void *tailAddr;
	void *freeListTop;
	void *usedListTop;
} IpcFreeAreaInfo_t;

typedef struct {
	union {
		IpcFixedAreaInfo_t fixedAreaInfo;
		IpcFreeAreaInfo_t freeAreaInfo;
	} info;
} IpcAreaInfo_t;

typedef struct {
	uint32_t size;
	void *nextBlock;
} IpcBlockList_t;

typedef struct {
	uint32_t numOfBlocks;
	void *nextFreeArea;
} IpcFixedAreaFreeInfo_t;

typedef IpcBlockList_t IpcFreeAreaFreeInfo_t;
typedef IpcBlockList_t IpcFreeAreaUsedInfo_t;

#if	0
typedef struct {
	uint32_t blocksize;
	void *nextFreeArea;
} IpcFreeAreaFreeInfo_t;
#endif	/* 0 */

typedef struct {
	uint32_t areaSize;
	uint32_t numOfDev;
	uint32_t sizeOfMinDev;
	uint32_t rateOfMagnify;
	RpcMutexID_t mutexId;
	RpcMutexAttribute_t mutexAttr;
/*
	tCondID fullCondId;
	tCondAttribute fullCondAttr;
	tCondID emptyCondId;
	tCondAttribute emptyCondAttr;
*/
	IpcAreaInfo_t *areaInfo;
} IpcAreaManageInfo_t;

static IpcShmManage_t IpcShmManage[IPC_SHARED_MEM_NUM] = {
	{(char*)NULL,0,-1,(void*)NULL},
	{(char*)NULL,0,-1,(void*)NULL},
	{(char*)NULL,0,-1,(void*)NULL}
};

static RpcResult_t IPC_getShmAddrSize(int32_t fd, void **addr, uint32_t *size);

#ifdef	DEBUG
static void IPC_printFixedAreaList(int fd);
static void IPC_printFreeAreaList(int fd);
#endif	/* DEBUG */

/* ----- SHM APIs - Global Functions ----- */

extern RpcResult_t IPC_InitSharedMem(RpcBool_t masterProcess) {
	static RpcBool_t fInitFlag = RPC_FALSE;int i;uint32_t errCode;
	struct stat statBuff;

//	(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"IN IPC_InitSharedMem PID:0x%x; masterProcess:%d;",RPC_GetPid(),masterProcess);
	if(fInitFlag) {
		return RPC_FATAL_ERROR;
	}
	if(masterProcess) {
		IPC_MasterProcess = RPC_TRUE;
	}
	else {
		IPC_MasterProcess = RPC_FALSE;
	}
	IpcShmManage[0].name = IPC_MSG_QUE_SHARED_MEM_NAME;
	IpcShmManage[1].name = IPC_DATABASE_SHARED_MEM_NAME;
	IpcShmManage[2].name = IPC_MARSHAL_SHARED_MEM_NAME;
	IpcShmManage[0].length = IPC_MSG_QUE_SHARED_MEM_SIZE;
	IpcShmManage[1].length = IPC_DATABASE_SHARED_MEM_SIZE;
	IpcShmManage[2].length = IPC_MARSHAL_SHARED_MEM_SIZE;
	/* */
	IpcShmManage[0].addr = (void*)IPC_MSG_QUE_SHARED_MEM_ADDR;
	IpcShmManage[1].addr = (void*)IPC_DATABASE_SHARED_MEM_ADDR;
	IpcShmManage[2].addr = (void*)IPC_MARSHAL_SHARED_MEM_ADDR;
	/* */
	for(i = 0;i < IPC_SHARED_MEM_NUM;i++) {
		if(IPC_MasterProcess) {
			(void)RPC_ShmUnlink(IpcShmManage[i].name,&errCode);
//			(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"NOW RPC_ShmOpen MASTER PID:0x%x;",RPC_GetPid());
			if(RPC_ShmOpen(IpcShmManage[i].name, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH,
					&(IpcShmManage[i].fd), &errCode) != RPC_SUCCESS) {
				(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_FATAL,"ERROR In RPC_ShmOpen ErrCode:%s;",RPC_LogConvertErrCode(errCode));
				(void)IPC_DestroySharedMem();
				return RPC_SYSCALL_ERROR;
			}
//			(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"END RPC_ShmOpen fd:%d;",IpcShmManage[i].fd);
//			(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"NOW RPC_ShmFtruncate NAME:%s; fd:%d; length:%d;",
//					IpcShmManage[i].name, IpcShmManage[i].fd, IpcShmManage[i].length);
			if(RPC_ShmFtruncate(IpcShmManage[i].fd,IpcShmManage[i].length, &errCode) != RPC_SUCCESS) {
				(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_FATAL,"ERROR In RPC_ShmFtruncate ErrCode:%s;",RPC_LogConvertErrCode(errCode));
				(void)IPC_DestroySharedMem();
				return RPC_SYSCALL_ERROR;
			}
		}
		else {
//			(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"NOW RPC_ShmOpen SLAVE PID:0x%x;",RPC_GetPid());
			if(RPC_ShmOpen(IpcShmManage[i].name,O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH,
					&(IpcShmManage[i].fd), &errCode) != RPC_SUCCESS) {
				(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_FATAL,"ERROR In RPC_ShmOpen ErrCode:%s;",RPC_LogConvertErrCode(errCode));
				(void)IPC_DestroySharedMem();
				return RPC_SYSCALL_ERROR;
			}
			if(RPC_ShmFstat(IpcShmManage[i].fd, &statBuff, &errCode) != RPC_SUCCESS) {
				(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_FATAL,"ERROR In RPC_ShmFstat ErrCode:%s;",RPC_LogConvertErrCode(errCode));
				(void)IPC_DestroySharedMem();
				return RPC_SYSCALL_ERROR;
			}
			if(IpcShmManage[i].length != statBuff.st_size) {
				(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_FATAL,"ERROR ILLEGAL SHM LENGTH LENGTH:%d REAL:%d;",IpcShmManage[i].length,statBuff.st_size);
				(void)IPC_DestroySharedMem();
				return RPC_SYSCALL_ERROR;
			}
		}
//		(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"     PROCESS SET SHM NAME:%s; FD:0x%x; LENGTH:%d",
//			IpcShmManage[i].name, IpcShmManage[i].fd, IpcShmManage[i].length);
	}
	fInitFlag = RPC_TRUE;
//	(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"OUT IPC_InitSharedMem PID:0x%x;",RPC_GetPid());
	return RPC_SUCCESS;
}

extern RpcResult_t IPC_DestroySharedMem(void) {
	int i;uint32_t errCode;

	for(i = 0;i < IPC_SHARED_MEM_NUM;i++) {
		(void)RPC_ShmClose(IpcShmManage[i].fd,&errCode);
		if(IPC_MasterProcess) {
			(void)RPC_ShmUnlink(IpcShmManage[i].name,&errCode);
		}
		IpcShmManage[i].fd = -1;
		IpcShmManage[i].length = 0;
		IpcShmManage[i].name = (char*)NULL;
		IpcShmManage[i].addr = (char*)NULL;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t IPC_AttachSharedMem(void) {
	int i;uint32_t errCode;void *retAddr;

//	(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"IN IPC_AttachSharedMem PID:0x%x;",RPC_GetPid());
	for(i = 0;i < IPC_SHARED_MEM_NUM;i++) {
//		if(RPC_ShmMap((void*)NULL, IpcShmManage[i].length, PROT_READ|PROT_WRITE, MAP_SHARED,
//				IpcShmManage[i].fd, 0, &(IpcShmManage[i].addr), &errCode) != RPC_SUCCESS) {
		if(RPC_ShmMap(IpcShmManage[i].addr, IpcShmManage[i].length, PROT_READ|PROT_WRITE, MAP_SHARED,
				IpcShmManage[i].fd, 0, &retAddr, &errCode) != RPC_SUCCESS) {
			(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_FATAL,"ERROR In IPC_ShmShmMap ErrCode:%s;",RPC_LogConvertErrCode(errCode));
			(void)IPC_DestroySharedMem();
			return RPC_SYSCALL_ERROR;
		}
		if((IpcShmManage[i].addr != (void*)NULL)&&(IpcShmManage[i].addr != retAddr)) {
			(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_FATAL,"ERROR ILLEGAL ALLOADED ADDRESS IN SHM EXPECTEXD-ADDR:0x%x; REAL-ADDR:0x%x;",IpcShmManage[i].addr,retAddr);
			(void)IPC_DestroySharedMem();
			return RPC_SYSCALL_ERROR;
		}
//		(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"     MMAP ->  FD:0x%x; ADDR:0x%x;",
//			IpcShmManage[i].fd,IpcShmManage[i].addr);
	}
//	(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"OUT IPC_AttachSharedMem");
	return RPC_SUCCESS;
}

extern RpcResult_t IPC_DettachSharedMem(void) {
	int i;uint32_t errCode;

	for(i = 0;i < IPC_SHARED_MEM_NUM;i++) {
		if(RPC_ShmUnmap(IpcShmManage[i].addr, IpcShmManage[i].length, &errCode) != RPC_SUCCESS) {
			(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_FATAL,"ERROR In IPC_ShmShmUnmap ErrCode:%s;",RPC_LogConvertErrCode(errCode));
			return RPC_SYSCALL_ERROR;
		}
		IpcShmManage[i].addr = (void*)NULL;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t IPC_GetShmInfo(char *name, int32_t *fd, void **addr, uint32_t *size) {
	int i;

	for(i = 0;i < IPC_SHARED_MEM_NUM;i++) {
		if(strcmp(name, IpcShmManage[i].name) == 0) {
			if(fd != (int32_t*)NULL)
				*fd = IpcShmManage[i].fd;
			if(addr != (void**)NULL)
				*addr = IpcShmManage[i].addr;
			if(size != (uint32_t*)NULL)
				*size = IpcShmManage[i].length;
			return RPC_SUCCESS;
		}
	}
	if(fd != (int32_t*)NULL)
		*fd = -1;
	if(addr != (void**)NULL)
		*addr = (void*)NULL;
	if(size != (uint32_t*)NULL)
		*size = 0;
	return RPC_PARAM_ERROR;
}

extern RpcResult_t IPC_InitShmGapArea(int fd, uint32_t gapSize) {
	IpcShmManageArea_t *ap;void *mp;void *addr;uint32_t size;

//	(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"IN IPC_InitShmGapArea PID:0x%x; FD:0x%x; gapSize:%d;",
//		RPC_GetPid(), fd, gapSize);
	if(IPC_getShmAddrSize(fd, &addr, &size) != RPC_SUCCESS) {
		return RPC_PARAM_ERROR;
	}
//	(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"    Addr:0x%x;",addr);	
	ap = (IpcShmManageArea_t*)addr;
#if	__WORDSIZE == 64
	mp = (void*)((uint64_t)addr + IPC_ALIGNMENT(gapSize) + sizeof(IpcShmManageArea_t));
	ap->startOfIpcAreaManageInfo = (void*)mp;
	ap->startOfGap = (void*)((uint64_t)addr + sizeof(IpcShmManageArea_t));
#else	/* __WORDSIZE */
	mp = (void*)((uint32_t)addr + IPC_ALIGNMENT(gapSize) + sizeof(IpcShmManageArea_t));
	ap->startOfIpcAreaManageInfo = (void*)mp;
	ap->startOfGap = (void*)((uint32_t)addr + sizeof(IpcShmManageArea_t));
#endif	/* __WORDSIZE */
	ap->gapSize = gapSize;
//	(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"END IPC_InitShmGapArea PID:0x%x; ap:0x%x; offsetIpcAreaManageInfo:0x%x; offsetGap:0x%x; gapSize:0x%x;",
//		RPC_GetPid(),ap, ap->offsetOfIpcAreaManageInfo, ap->offsetOfGap, ap->gapSize);
	return RPC_SUCCESS;
}

extern RpcResult_t IPC_GetShmGapData(int fd,void **startArea, uint32_t *gapSize) {
	void *addr;uint32_t totalSize;IpcShmManageArea_t *ap;

//	(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"IN IPC_GetShmGapData PID:0x%x; FD:0x%x;",
//		RPC_GetPid(), fd);
	if(IPC_getShmAddrSize(fd, &addr, &totalSize) != RPC_SUCCESS) {
		return RPC_PARAM_ERROR;;
	}
	ap = (IpcShmManageArea_t*)addr;
	*startArea = ap->startOfGap;
	*gapSize = ap->gapSize;
//	(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"OUT IPC_GetShmGapData PID:0x%x; startArea:0x%x; gapSize:0x%x;",
//		RPC_GetPid(), *startArea,*gapSize);
	return RPC_SUCCESS;
}

extern RpcResult_t IPC_InitShmAllocArea(int fd, uint32_t memSize, uint32_t numOfDev, uint32_t minSize, uint32_t rateOfMagnify) {
	void *addr;uint32_t size;IpcAreaInfo_t *areaInfo;IpcAreaManageInfo_t *manageInfo;
	void *topAddr;uint32_t blockSize;uint32_t blockNum;uint32_t bSize;
	int i;IpcShmManageArea_t *ap;

//	(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"IN IPC_InitShmAllocArea PID:0x%x; FD:0x%x; memSize:%d; numOfDev:%d; minSize:%d; rateOfMagnify:%d;",
//		RPC_GetPid(), fd, memSize, numOfDev, minSize, rateOfMagnify);
	if(!IPC_MasterProcess) {
		return RPC_SUCCESS;
	}
	if(IPC_getShmAddrSize(fd, &addr, &size) != RPC_SUCCESS) {
		return RPC_PARAM_ERROR;
	}
	if(numOfDev < 1) {
		return RPC_PARAM_ERROR;
	}
	ap = (IpcShmManageArea_t*)addr;
	if(size < (memSize+ IPC_ALIGNMENT(ap->gapSize) + sizeof(IpcShmManageArea_t) + sizeof(IpcAreaManageInfo_t) + sizeof(IpcAreaInfo_t)*numOfDev)) {
		return RPC_NO_MORE_RESOURCE;
	}
	manageInfo = (IpcAreaManageInfo_t*)(ap->startOfIpcAreaManageInfo);
	manageInfo->areaSize = memSize;
	manageInfo->numOfDev = numOfDev;
	manageInfo->rateOfMagnify = rateOfMagnify;
	manageInfo->sizeOfMinDev = minSize;
	if(RPC_MutexAttrInit(&(manageInfo->mutexAttr)) != RPC_SUCCESS) {
		goto fatalError;
	}
#ifdef	_LINUX_
	if(RPC_MutexAttrSetType(&(manageInfo->mutexAttr), PTHREAD_MUTEX_ADAPTIVE_NP) != RPC_SUCCESS) {
		goto fatalError;
	}
#else	/* _LINUX_ */
	if(RPC_MutexAttrSetType(&(manageInfo->mutexAttr), PTHREAD_MUTEX_RECURSIVE) != RPC_SUCCESS) {
		goto fatalError;
	}
#endif	/* _LINUX_ */
	if(RPC_MutexAttrSetPshared(&(manageInfo->mutexAttr), PTHREAD_PROCESS_SHARED) != RPC_SUCCESS) {
		goto fatalError;
	}
	if(RPC_InitMutex(&(manageInfo->mutexId),&(manageInfo->mutexAttr)) != RPC_SUCCESS) {
		goto fatalError;
	}
/*
	if(RPC_CondAttrInit(&(manageInfo->emptyCondAttr)) != RPC_SUCCESS) {
		goto fatalError;
	}
	if(IPC_CondAttrSetPshared(&(manageInfo->emptyCondAttr), PTHREAD_PROCESS_SHARED) != RPC_SUCCESS) {
		goto fatalError;
	}
	if(RPC_InitCond(&(manageInfo->emptyCondId),&(manageInfo->emptyCondAttr)) != RPC_SUCCESS) {
		goto fatalError;
	}
	if(RPC_CondAttrInit(&(manageIRVnfo->fullCondAttr)) != RPC_SUCCESS) {
		goto fatalError;
	}
	if(IPC_CondAttrSetPshared(&(manageInfo->fullCondAttr), PTHREAD_PROCESS_SHARED) != RPC_SUCCESS) {
		goto fatalError;
	}
	if(RPC_InitCond(&(manageInfo->fullCondId),&(manageInfo->fullCondAttr)) != RPC_SUCCESS) {
		goto fatalError;
	}
*/
#if	__WORDSIZE == 64
	areaInfo = manageInfo->areaInfo = (IpcAreaInfo_t*)((uint64_t)manageInfo + sizeof(IpcAreaManageInfo_t));
	topAddr = (void*)((uint64_t)areaInfo + sizeof(IpcAreaInfo_t)*numOfDev);
#else	/* __WORDSIZE */
	areaInfo = manageInfo->areaInfo = (IpcAreaInfo_t*)((uint32_t)manageInfo + sizeof(IpcAreaManageInfo_t));
	topAddr = (void*)((uint32_t)areaInfo + sizeof(IpcAreaInfo_t)*numOfDev);
#endif	/* __WORDSIZE */
	blockSize = memSize/(1<<(numOfDev-1));
	bSize = minSize;
	blockNum = blockSize / bSize;
	for(i = 0;i < (numOfDev-1);i++) {
		areaInfo->info.fixedAreaInfo.topAddr = topAddr;
#if	__WORDSIZE == 64
		areaInfo->info.fixedAreaInfo.tailAddr = (void*)((uint64_t)topAddr + blockSize - 1);
#else	/* __WORDSIZE */
		areaInfo->info.fixedAreaInfo.tailAddr = (void*)((uint32_t)topAddr + blockSize - 1);
#endif	/* __WORDSIZE */
		areaInfo->info.fixedAreaInfo.numOfBlocks = blockNum;
		areaInfo->info.fixedAreaInfo.sizeOfBlock = bSize;
		areaInfo->info.fixedAreaInfo.freeListTop = topAddr;
		*((uint32_t*)topAddr) = blockNum;
#if	__WORDSIZE == 64
		*((uint32_t*)((int64_t)topAddr + sizeof(uint32_t))) = 0;
		areaInfo++;
		topAddr = (void*)((uint64_t)topAddr + blockSize);
#else	/* __WORDSIZE */
		*((uint32_t*)((int32_t)topAddr + sizeof(uint32_t))) = 0;
		areaInfo++;
		topAddr = (void*)((uint32_t)topAddr + blockSize);
#endif	/* __WORDSIZE */
		blockSize = memSize/(1<<(numOfDev-1-i));
		bSize = bSize * rateOfMagnify;
		blockNum = blockSize/bSize;
	}
	areaInfo->info.freeAreaInfo.topAddr = topAddr;
#if	__WORDSIZE == 64
	areaInfo->info.freeAreaInfo.tailAddr = (void*)((uint64_t)topAddr + blockSize - 1);
#else	/* __WORDSIZE */
	areaInfo->info.freeAreaInfo.tailAddr = (void*)((uint32_t)topAddr + blockSize - 1);
#endif	/* __WORDSIZe */
	areaInfo->info.freeAreaInfo.freeListTop = topAddr;
	areaInfo->info.freeAreaInfo.usedListTop = (void*)NULL;
	*((uint32_t*)(topAddr)) = blockSize;
#if	__WORDSIZE == 64
	*((uint32_t*)((int64_t)topAddr + sizeof(uint32_t))) = 0;
#else	/* __WORDSIZE */
	*((uint32_t*)((int32_t)topAddr + sizeof(uint32_t))) = 0;
#endif	/* __WORDSIZE */
//	(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"END IPC_InitShmAllocArea PID:0x%x; START-ADDR:0x%x;", 
//		RPC_GetPid(), addr);
//	(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"   AREA-INFO:0x%x; TopAddr:0x%x; TailAddr:0x%x; FreeListTop:0x%x; UsedListTop:0x%x;", 
//		areaInfo,areaInfo->info.freeAreaInfo.offsetTopAddr,areaInfo->info.freeAreaInfo.offsetTailAddr,areaInfo->info.freeAreaInfo.offsetFreeListTop,areaInfo->info.freeAreaInfo.offsetUsedListTop );
	return RPC_SUCCESS;
fatalError:
	return RPC_FATAL_ERROR;
}

extern void *IPC_AllocShmMem(int fd, uint32_t size) {
	void *addr;uint32_t totalSize;IpcAreaInfo_t *areaInfo;IpcAreaManageInfo_t *manageInfo;
	int i;void *retAddr;IpcFixedAreaFreeInfo_t *fixedInfo;
	IpcFreeAreaFreeInfo_t *freeInfo,*preFreeInfo,*newFreeInfo;
	IpcFreeAreaUsedInfo_t *newUsedInfo,*usedInfo,*preUsedInfo;
	IpcShmManageArea_t *ap;

//	(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"IN IPC_AllocShmMem PID:0x%x; FD:0x%x; size:%d;",RPC_GetPid(),fd,size);
	if(IPC_getShmAddrSize(fd, &addr, &totalSize) != RPC_SUCCESS) {
		(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_FATAL,"CAN NOT GET SHM ADDR FD:0x%x;",fd);
		return (void*)NULL;
	}
	ap = (IpcShmManageArea_t*)addr;
//	(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"   MANAGE AREA: AP:0x%x; OffsetOfIpcAreaManageInfo:0x%x; OffsetOfGap:0x%x; gapSize:0x%x;",
//		ap, ap->offsetOfIpcAreaManageInfo,ap->offsetOfGap, ap->gapSize);
	manageInfo = (IpcAreaManageInfo_t*)(ap->startOfIpcAreaManageInfo);
//	(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"   ADDR:0x%x,TOTAL-SIZE:%d; manageInfo:0x%x; AreaSize:%d; NumOfDev:%d;",
//		addr,totalSize,manageInfo,manageInfo->areaSize, manageInfo->numOfDev);
	if((size == 0)||(size > (manageInfo->areaSize / IPC_DEVIDE_MAX_ALLOC_SIZE))) {
		(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_FATAL,"SIZE ERROR SIZE:%d;",size);
		return (void*)NULL;
	}
	if(RPC_MutexLock(&(manageInfo->mutexId)) != RPC_SUCCESS) {
		(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_FATAL,"MUTEX ERROR");
		return (void*)NULL;
	}
#if	__WORDSIZE == 64
	areaInfo = (IpcAreaInfo_t*)((uint64_t)manageInfo + sizeof(IpcAreaManageInfo_t));
#else	/* __WORDSIZE */
	areaInfo = (IpcAreaInfo_t*)((uint32_t)manageInfo + sizeof(IpcAreaManageInfo_t));
#endif	/* __WORDSIZE */
//	(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"   BEFORE AREA-INFO AreaInfo:0x%x; TopAddr:0x%x; TailAddr:0x%x; freeInfo:0x%x; usedInfo:0x%x;",
//		areaInfo, areaInfo->info.freeAreaInfo.topAddr, areaInfo->info.freeAreaInfo.tailAddr, 
//		areaInfo->info.freeAreaInfo.freeListTop, areaInfo->info.freeAreaInfo.usedListTop);
	for(i = 0;i < (manageInfo->numOfDev-1);i++) {
		if((areaInfo->info.fixedAreaInfo.sizeOfBlock >= size)&&
		   (areaInfo->info.fixedAreaInfo.freeListTop != (void*)NULL)) {
			retAddr = areaInfo->info.fixedAreaInfo.freeListTop;
			fixedInfo = (IpcFixedAreaFreeInfo_t*)areaInfo->info.fixedAreaInfo.freeListTop;
			(fixedInfo->numOfBlocks)--;
			if(fixedInfo->numOfBlocks == 0) {
				areaInfo->info.fixedAreaInfo.freeListTop = fixedInfo->nextFreeArea;
			}
			else {
#if	__WORDSIZE == 64
				areaInfo->info.fixedAreaInfo.freeListTop = (void*)((uint64_t)areaInfo->info.fixedAreaInfo.freeListTop+
						areaInfo->info.fixedAreaInfo.sizeOfBlock);
#else	/* __WORDSIZE */
				areaInfo->info.fixedAreaInfo.freeListTop = (void*)((uint32_t)areaInfo->info.fixedAreaInfo.freeListTop+
						areaInfo->info.fixedAreaInfo.sizeOfBlock);
#endif	/* __WORDSIZE */
				((IpcFixedAreaFreeInfo_t*)areaInfo->info.fixedAreaInfo.freeListTop)->numOfBlocks = fixedInfo->numOfBlocks;
				((IpcFixedAreaFreeInfo_t*)areaInfo->info.fixedAreaInfo.freeListTop)->nextFreeArea = fixedInfo->nextFreeArea;
			}
			(void)RPC_MutexUnlock(&(manageInfo->mutexId));
//			IPC_printFixedAreaList(fd);
			return retAddr;
		}
		areaInfo++;
	}
//	(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"   AREA-INFO AreaInfo:0x%x; TopAddr:0x%x; TailAddr:0x%x; freeInfo:0x%x; usedInfo:0x%x;",
//		areaInfo, areaInfo->info.freeAreaInfo.topAddr, areaInfo->info.freeAreaInfo.tailAddr, 
//		areaInfo->info.freeAreaInfo.freeListTop, areaInfo->info.freeAreaInfo.usedListTop);
	freeInfo = (IpcFreeAreaFreeInfo_t*)areaInfo->info.freeAreaInfo.freeListTop;
	usedInfo = (IpcFreeAreaUsedInfo_t*)areaInfo->info.freeAreaInfo.usedListTop;
//	(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"   FreeInfo:0x%x; size:0x%x; nextBlock:0x%x;   UsedInfo:0x%x; size:0x%x; nextBlock:0x%x",
//		freeInfo, freeInfo==NULL?0:freeInfo->size, freeInfo==NULL?0:freeInfo->nextBlock, usedInfo, usedInfo==NULL?0:usedInfo->size, usedInfo==NULL?0:usedInfo->nextBlock);
	preFreeInfo = (IpcFreeAreaFreeInfo_t*)NULL;
	while(freeInfo != (IpcFreeAreaFreeInfo_t*)NULL) {
		if(freeInfo->size >= (size+sizeof(IpcFreeAreaFreeInfo_t))) {
			if((freeInfo->size - (size+sizeof(IpcFreeAreaFreeInfo_t)+IPC_SHM_MIN_FREE_SIZE)) <= 0) {
				size = freeInfo->size - sizeof(IpcFreeAreaFreeInfo_t);
				if(preFreeInfo == (IpcFreeAreaFreeInfo_t*)NULL) {
					areaInfo->info.freeAreaInfo.freeListTop = freeInfo->nextBlock;
				}
				else {
					preFreeInfo->nextBlock = freeInfo->nextBlock;
				}
			}
			else {
				size = IPC_ALIGNMENT(size);
#if	__WORDSIZE == 64
				newFreeInfo = (IpcFreeAreaFreeInfo_t*)((uint64_t)freeInfo+size+sizeof(IpcFreeAreaFreeInfo_t));
#else	/* __WORDSIZE */
				newFreeInfo = (IpcFreeAreaFreeInfo_t*)((uint32_t)freeInfo+size+sizeof(IpcFreeAreaFreeInfo_t));
#endif	/* __WORDSIZE */
				newFreeInfo->size = freeInfo->size - (size+sizeof(IpcFreeAreaFreeInfo_t));
				newFreeInfo->nextBlock = freeInfo->nextBlock;
				if(preFreeInfo == (IpcFreeAreaFreeInfo_t*)NULL) {
					areaInfo->info.freeAreaInfo.freeListTop = (void*)newFreeInfo;
				}
				else {
					preFreeInfo->nextBlock = (void*)newFreeInfo;
				}
			}
			newUsedInfo = (IpcFreeAreaUsedInfo_t*)freeInfo;
			preUsedInfo = (IpcFreeAreaUsedInfo_t*)NULL;
			while((usedInfo != (IpcFreeAreaUsedInfo_t*)NULL)&&(usedInfo < newUsedInfo)) {
				preUsedInfo = usedInfo;
				usedInfo = (IpcFreeAreaUsedInfo_t*)usedInfo->nextBlock;
			}
			if(preUsedInfo == (IpcFreeAreaUsedInfo_t*)NULL) {
				areaInfo->info.freeAreaInfo.usedListTop = newUsedInfo;
			}
			else {
				preUsedInfo->nextBlock = (void*)newUsedInfo;
			}
			newUsedInfo->nextBlock = (void*)usedInfo;
			newUsedInfo->size = size;
#if	__WORDSIZE == 64
			retAddr = (void*)((uint64_t)newUsedInfo+sizeof(IpcFreeAreaUsedInfo_t));
#else	/* __WORSIZE */
			retAddr = (void*)((uint32_t)newUsedInfo+sizeof(IpcFreeAreaUsedInfo_t));
#endif	/* __WORDSIZE */
//			(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"   END AREA-INFO AreaInfo:0x%x; TopAddr:0x%x; TailAddr:0x%x; freeInfo:0x%x; usedInfo:0x%x;",
//				areaInfo, areaInfo->info.freeAreaInfo.topAddr, areaInfo->info.freeAreaInfo.tailAddr, 
//				areaInfo->info.freeAreaInfo.freeListTop, areaInfo->info.freeAreaInfo.usedListTop);
//			(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"   END FreeInfo:0x%x; size:0x%x; nextBlock:0x%x;   NEW UsedInfo:0x%x; size:0x%x; nextBlock:0x%x",
//				freeInfo, freeInfo==NULL?0:freeInfo->size, freeInfo==NULL?0:freeInfo->nextBlock, newUsedInfo, newUsedInfo==NULL?0:newUsedInfo->size, newUsedInfo==NULL?0:newUsedInfo->nextBlock);
			(void)RPC_MutexUnlock(&(manageInfo->mutexId));
//			IPC_printFreeAreaList(fd);
//			(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"END IPC_AllocShmMem PID:0x%x; ADDR:0x%x;",
//				RPC_GetPid(),retAddr);
			return retAddr;
		}
		preFreeInfo = freeInfo;
		freeInfo = (IpcFreeAreaFreeInfo_t*)freeInfo->nextBlock;
//		(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"   LOOP FreeInfo:0x%x; size:0x%x; nextBlock:0x%x;   UsedInfo:0x%x; size:0x%s; nextBlock:0x%x",
//			freeInfo, freeInfo==NULL?0:freeInfo->size, freeInfo==NULL?0:freeInfo->nextBlock, usedInfo, usedInfo==NULL?0:usedInfo->size, usedInfo==NULL?0:usedInfo->nextBlock);
	}
//	(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_FATAL,"CAN NOT ALLOCATEE SHM MEM AREA SIZE:%d;",size);
	(void)RPC_MutexUnlock(&(manageInfo->mutexId));
	return (void*)NULL;
}

extern void IPC_FreeShmMem(int fd, void *addr) {
	void *topAddr;uint32_t totalSize;IpcAreaInfo_t *areaInfo;IpcAreaManageInfo_t *manageInfo;
	int i;IpcFixedAreaFreeInfo_t *fixedInfo,*preFixedInfo;
	IpcFreeAreaFreeInfo_t *freeInfo,*preFreeInfo;
	IpcFreeAreaUsedInfo_t *usedInfo,*preUsedInfo;
	IpcShmManageArea_t *ap;

	if(IPC_getShmAddrSize(fd, &topAddr, &totalSize) != RPC_SUCCESS) {
		return;
	}
	ap = (IpcShmManageArea_t*)topAddr;
	manageInfo = (IpcAreaManageInfo_t*)(ap->startOfIpcAreaManageInfo);
	if(RPC_MutexLock(&(manageInfo->mutexId)) != RPC_SUCCESS) {
		return;
	}
#if	__WORDSIZE == 64
	areaInfo = (IpcAreaInfo_t*)((uint64_t)manageInfo + sizeof(IpcAreaManageInfo_t));
#else	/* __WORDSIZE */
	areaInfo = (IpcAreaInfo_t*)((uint32_t)manageInfo + sizeof(IpcAreaManageInfo_t));
#endif	/* __WORDSIZE */
	for(i = 0;i < (manageInfo->numOfDev-1);i++) {
		if((addr >= areaInfo->info.fixedAreaInfo.topAddr)&&(addr < areaInfo->info.fixedAreaInfo.tailAddr)) {
			preFixedInfo = (IpcFixedAreaFreeInfo_t*)NULL;
			fixedInfo = (IpcFixedAreaFreeInfo_t*)areaInfo->info.fixedAreaInfo.freeListTop;
			while(fixedInfo != (IpcFixedAreaFreeInfo_t*)NULL) {
				if((void*)fixedInfo > addr) {
					((IpcFixedAreaFreeInfo_t*)addr)->nextFreeArea = fixedInfo;
					((IpcFixedAreaFreeInfo_t*)addr)->numOfBlocks = 1;
					if(preFixedInfo == (IpcFixedAreaFreeInfo_t*)NULL) {
						areaInfo->info.fixedAreaInfo.freeListTop = (void*)addr;
#if	__WORDSIZE == 64
						if(((uint64_t)addr+areaInfo->info.fixedAreaInfo.sizeOfBlock) == (uint64_t)fixedInfo) {
#else	/* __WORDSIZE */
						if(((uint32_t)addr+areaInfo->info.fixedAreaInfo.sizeOfBlock) == (uint32_t)fixedInfo) {
#endif	/* __WORDSIZE */
							((IpcFixedAreaFreeInfo_t*)addr)->numOfBlocks = fixedInfo->numOfBlocks+1;
							((IpcFixedAreaFreeInfo_t*)addr)->nextFreeArea = fixedInfo->nextFreeArea;
						}
					}
#if	__WORDSIZE == 64
					else if((uint64_t)preFixedInfo+(preFixedInfo->numOfBlocks * areaInfo->info.fixedAreaInfo.sizeOfBlock) == (uint64_t)addr) {
#else	/* __WORDSIZE */
					else if((uint32_t)preFixedInfo+(preFixedInfo->numOfBlocks * areaInfo->info.fixedAreaInfo.sizeOfBlock) == (uint32_t)addr) {
#endif	/* __WORDSIZE */
						(preFixedInfo->numOfBlocks)++;
#if	__WORDSIZE == 64
						if(((uint64_t)addr+areaInfo->info.fixedAreaInfo.sizeOfBlock) == (uint64_t)fixedInfo) {
#else	/* __WORDSIZE */
						if(((uint32_t)addr+areaInfo->info.fixedAreaInfo.sizeOfBlock) == (uint32_t)fixedInfo) {
#endif	/* __WORDSIZE */
							preFixedInfo->numOfBlocks += fixedInfo->numOfBlocks;
							preFixedInfo->nextFreeArea = fixedInfo->nextFreeArea;
						}
					}
					else {
						preFixedInfo->nextFreeArea = (void*)addr;
#if	__WORDSIZE == 64
						if(((uint64_t)addr+areaInfo->info.fixedAreaInfo.sizeOfBlock) == (uint64_t)fixedInfo) {
#else	/* __WORDSIZE */
						if(((uint32_t)addr+areaInfo->info.fixedAreaInfo.sizeOfBlock) == (uint32_t)fixedInfo) {
#endif	/* __WORDSIZE */
							((IpcFixedAreaFreeInfo_t*)addr)->numOfBlocks = fixedInfo->numOfBlocks+1;
							((IpcFixedAreaFreeInfo_t*)addr)->nextFreeArea = fixedInfo->nextFreeArea;
						}
					}
					(void)RPC_MutexUnlock(&(manageInfo->mutexId));
					return;
				}
				preFixedInfo = fixedInfo;
				fixedInfo = (IpcFixedAreaFreeInfo_t*)fixedInfo->nextFreeArea;
			}
			((IpcFixedAreaFreeInfo_t*)addr)->nextFreeArea = (void*)NULL;
			((IpcFixedAreaFreeInfo_t*)addr)->numOfBlocks = 1;
			if(preFixedInfo == (IpcFixedAreaFreeInfo_t*)NULL) {
				areaInfo->info.fixedAreaInfo.freeListTop = (void*)addr;
			}
#if	__WORDSIZE == 64
			else if((uint64_t)preFixedInfo+(preFixedInfo->numOfBlocks * areaInfo->info.fixedAreaInfo.sizeOfBlock) == (uint64_t)addr) {
#else	/* __WORDSIZE */
			else if((uint32_t)preFixedInfo+(preFixedInfo->numOfBlocks * areaInfo->info.fixedAreaInfo.sizeOfBlock) == (uint32_t)addr) {
#endif	/* __WORDSIZE */
				(preFixedInfo->numOfBlocks)++;
			}
			else {
				preFixedInfo->nextFreeArea = (void*)addr;
			}
			(void)RPC_MutexUnlock(&(manageInfo->mutexId));
			return;
		}
		areaInfo++;
	}
//	(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"NOW SEARCH FREE AREA:0x%x;",addr);
#if	__WORDSIZE == 64
	addr = (void*)((uint64_t)addr-sizeof(IpcFreeAreaUsedInfo_t));
#else	/* __WORDSIZE */
	addr = (void*)((uint32_t)addr-sizeof(IpcFreeAreaUsedInfo_t));
#endif	/* __WORDSIZE */
	if((addr >= areaInfo->info.freeAreaInfo.topAddr)&&(addr < areaInfo->info.freeAreaInfo.tailAddr)) {
		usedInfo = (IpcFreeAreaUsedInfo_t*)areaInfo->info.freeAreaInfo.usedListTop;
		preUsedInfo = (IpcFreeAreaUsedInfo_t*)NULL;
		while(usedInfo != (IpcFreeAreaUsedInfo_t*)NULL) {
#if	__WORDSIZE == 64
			if(((uint64_t)usedInfo+sizeof(IpcFreeAreaUsedInfo_t)) >= (uint64_t)addr) {
#else	/* __WORDSIZE */
			if(((uint32_t)usedInfo+sizeof(IpcFreeAreaUsedInfo_t)) >= (uint32_t)addr) {
#endif	/* __WORDSIZE */
//				(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"FIND AREA:0x%x; PRE:0x%x; SIZE:%d; AREA:0x%x; SIZE:%d; NEXT:0x%x;",addr,preUsedInfo,(preUsedInfo!=NULL)?(preUsedInfo->size):0,usedInfo,usedInfo->size,usedInfo->nextBlock);
				if(preUsedInfo == (IpcFreeAreaUsedInfo_t*)NULL) {
					areaInfo->info.freeAreaInfo.usedListTop = usedInfo->nextBlock;
				}
				else {
					preUsedInfo->nextBlock = usedInfo->nextBlock;
				}
				freeInfo = (IpcFreeAreaFreeInfo_t*)areaInfo->info.freeAreaInfo.freeListTop;
				preFreeInfo = (IpcFreeAreaFreeInfo_t*)NULL;
				while(freeInfo != (IpcFreeAreaFreeInfo_t*)NULL) {
#if	__WORDSIZE == 64
					if((uint64_t)usedInfo <= (uint64_t)freeInfo) {
#else	/* __WORDSIZE */
					if((uint32_t)usedInfo <= (uint32_t)freeInfo) {
#endif	/* __WORDSIZE */
						usedInfo->nextBlock = (void*)freeInfo;
						if(preFreeInfo == (IpcFreeAreaFreeInfo_t*)NULL) {
							areaInfo->info.freeAreaInfo.freeListTop = (void*)usedInfo;
						}
						else {
							preFreeInfo->nextBlock = (void*)(usedInfo);
						}
#if	__WORDSIZE == 64
						if(((uint64_t)usedInfo+usedInfo->size+sizeof(IpcFreeAreaFreeInfo_t)) == (uint64_t)freeInfo) {
#else	/* __WORDSIZE */
						if(((uint32_t)usedInfo+usedInfo->size+sizeof(IpcFreeAreaFreeInfo_t)) == (uint32_t)freeInfo) {
#endif	/* __WORDSIZE */
							usedInfo->nextBlock = freeInfo->nextBlock;
							usedInfo->size += (freeInfo->size+sizeof(IpcFreeAreaFreeInfo_t));
						}
#if	__WORDSIZE == 64
						if(((preFreeInfo != (IpcFreeAreaFreeInfo_t*)NULL)&&
								((uint64_t)preFreeInfo+preFreeInfo->size+sizeof(IpcFreeAreaFreeInfo_t)) == (uint64_t)usedInfo)) {
#else	/* __WORDSIZE */
						if(((preFreeInfo != (IpcFreeAreaFreeInfo_t*)NULL)&&
								((uint32_t)preFreeInfo+preFreeInfo->size+sizeof(IpcFreeAreaFreeInfo_t)) == (uint32_t)usedInfo)) {
#endif	/* __WORDSIZE */
							preFreeInfo->nextBlock = usedInfo->nextBlock;
							preFreeInfo->size += (usedInfo->size+sizeof(IpcFreeAreaFreeInfo_t));
						}
						(void)RPC_MutexUnlock(&(manageInfo->mutexId));
						return;
					}
					preFreeInfo = freeInfo;
					freeInfo = (IpcFreeAreaFreeInfo_t*)freeInfo->nextBlock;
				}
//				(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"NOT FOUND FREE LIST AREA:0x%x; SIZE:%d; PRE:0x%x; SIZE;%d;",usedInfo,usedInfo->size,preFreeInfo,(preFreeInfo!=NULL)?(preFreeInfo->size):0);
				usedInfo->nextBlock = (void*)NULL;
				if(preFreeInfo == (IpcFreeAreaFreeInfo_t*)NULL) {
					areaInfo->info.freeAreaInfo.freeListTop = (void*)usedInfo;
				}
#if	__WORDSIZE == 64
				else if(((uint64_t)preFreeInfo+preFreeInfo->size+sizeof(IpcFreeAreaFreeInfo_t)) == (uint64_t)(usedInfo)) {
#else	/* __WORDSIZE */
				else if(((uint32_t)preFreeInfo+preFreeInfo->size+sizeof(IpcFreeAreaFreeInfo_t)) == (uint32_t)(usedInfo)) {
#endif	/* __WORDSIZE */
					preFreeInfo->size += (usedInfo->size+sizeof(IpcFreeAreaFreeInfo_t));
				}
				else {
					preFreeInfo->nextBlock = (void*)usedInfo;
				}
				(void)RPC_MutexUnlock(&(manageInfo->mutexId));
				return;
			}
			preUsedInfo = usedInfo;
			usedInfo = (IpcFreeAreaUsedInfo_t*)usedInfo->nextBlock;
		}
		/* ERROR */
		(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_FATAL,"CAN NOT FIND FREE SHM MEM AREA:0x%x;",addr);
		(void)RPC_MutexUnlock(&(manageInfo->mutexId));
		return;
	}
	/* ERROR */
	(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_FATAL,"CAN NOT FIND FREE SHM MEM AREA:0x%x;",addr);
	(void)RPC_MutexUnlock(&(manageInfo->mutexId));
	return;
}

extern uint32_t IPC_AllocatedSizeShmMem(int fd, void *addr) {
	void *topAddr;uint32_t totalSize;IpcAreaInfo_t *areaInfo;IpcAreaManageInfo_t *manageInfo;
	int i;IpcFixedAreaFreeInfo_t *fixedInfo;IpcFreeAreaUsedInfo_t *usedInfo;
	uint32_t size = 0;IpcShmManageArea_t *ap;

	if(IPC_getShmAddrSize(fd, &topAddr, &totalSize) != RPC_SUCCESS) {
		return 0;
	}
	ap = (IpcShmManageArea_t*)topAddr;
	manageInfo = (IpcAreaManageInfo_t*)(ap->startOfIpcAreaManageInfo);
	if(RPC_MutexLock(&(manageInfo->mutexId)) != RPC_SUCCESS) {
		return 0;
	}
#if	__WORDSIZE == 64
	areaInfo = (IpcAreaInfo_t*)((uint64_t)manageInfo + sizeof(IpcAreaManageInfo_t));
#else	/* __WORDSIZE */
	areaInfo = (IpcAreaInfo_t*)((uint32_t)manageInfo + sizeof(IpcAreaManageInfo_t));
#endif	/* __WORDSIZE */
	for(i = 0;i < (manageInfo->numOfDev-1);i++) {
		if((addr >= areaInfo->info.fixedAreaInfo.topAddr)&&(addr < areaInfo->info.fixedAreaInfo.tailAddr)) {
			fixedInfo = (IpcFixedAreaFreeInfo_t*)areaInfo->info.fixedAreaInfo.freeListTop;
			while(fixedInfo != (IpcFixedAreaFreeInfo_t*)NULL) {
				if((void*)fixedInfo > addr) {
					size = areaInfo->info.fixedAreaInfo.sizeOfBlock;
					(void)RPC_MutexUnlock(&(manageInfo->mutexId));
					return size;
				}
				fixedInfo = (IpcFixedAreaFreeInfo_t*)fixedInfo->nextFreeArea;
			}
			(void)RPC_MutexUnlock(&(manageInfo->mutexId));
			return 0;
		}
		areaInfo++;
	}
	if((addr >= areaInfo->info.freeAreaInfo.topAddr)&&(addr < areaInfo->info.freeAreaInfo.tailAddr)) {
		usedInfo = (IpcFreeAreaUsedInfo_t*)areaInfo->info.freeAreaInfo.usedListTop;
		while(usedInfo != (IpcFreeAreaUsedInfo_t*)NULL) {
#if	__WORDSIZE == 64
			if(((uint64_t)usedInfo+sizeof(IpcFreeAreaUsedInfo_t)) >= (uint64_t)addr) {
#else	/* __WORDSIZE */
			if(((uint32_t)usedInfo+sizeof(IpcFreeAreaUsedInfo_t)) >= (uint32_t)addr) {
#endif	/* __WORDSIZE */
				size = usedInfo->size;
				(void)RPC_MutexUnlock(&(manageInfo->mutexId));
				return size;
			}
			usedInfo = (IpcFreeAreaUsedInfo_t*)usedInfo->nextBlock;
		}
		/* ERROR */
		(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_FATAL,"CAN NOT FIND ALLOCATED SHM MEM AREA:0x%x;",addr);
		(void)RPC_MutexUnlock(&(manageInfo->mutexId));
		return 0;
	}
	/* ERROR */
	(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_FATAL,"CAN NOT FIND ALLOCATED SHM MEM AREA:0x%x;",addr);
	(void)RPC_MutexUnlock(&(manageInfo->mutexId));
	return 0;
}

extern void *IPC_ReallocShmMem(int fd, void *addr, uint32_t newSize) {
	void *retAddr;uint32_t size;

	if((retAddr = IPC_AllocShmMem(fd,newSize)) != (void*)NULL) {
		if((size = IPC_AllocatedSizeShmMem(fd,addr)) == 0) {
			IPC_FreeShmMem(fd,retAddr);
			return (void*)NULL;
		}
		(void)memcpy(retAddr,addr,size);
		IPC_FreeShmMem(fd,addr);
		return retAddr;
	}
	return (void*)NULL;
}

#if	0
extern void *IPC_AllcShmMemWithTimeout(int fd, uint32_t size, uint32_t timeout) {

}


extern void *IPC_ReallocShmMemWithTimeout(int fd, void *addr, uint32_t newSize, uint32_t timeout) {

}
#endif	/* 0 */

/* ----- INTERNAL FUNCTIONS ----- */

static RpcResult_t IPC_getShmAddrSize(int32_t fd, void **addr, uint32_t *size) {
	int i;

	for(i = 0;i < IPC_SHARED_MEM_NUM;i++) {
		if(IpcShmManage[i].fd == fd) {
			*addr = IpcShmManage[i].addr;
			*size = IpcShmManage[i].length;
			return RPC_SUCCESS;
		}
	}
	*addr = (void*)NULL;
	*size = 0;
	return RPC_PARAM_ERROR;
}

#ifdef	DEBUG
static void IPC_printFixedAreaList(int fd) {
	void *topAddr;uint32_t totalSize;IpcAreaInfo_t *areaInfo;IpcAreaManageInfo_t *manageInfo;
	int i;IpcFixedAreaFreeInfo_t *fixedInfo;IpcShmManageArea_t *ap;

	if(IPC_getShmAddrSize(fd, &topAddr, &totalSize) != RPC_SUCCESS) {
		return;
	}
	ap = (IpcShmManageArea_t*)topAddr;
	manageInfo = (IpcAreaManageInfo_t*)(ap->startOfIpcAreaManageInfo);
	if(RPC_MutexLock(&(manageInfo->mutexId)) != RPC_SUCCESS) {
		return;
	}
	(void)RPC_LogPrintNomark(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"---- FixedFreeList manageInfo:0x%x; areaInfo:0x%x; areaSize:%d; numOfDev:%d; rateOfMagnify:%d; sizeOfMinDev:0x%x; ----\n",
			manageInfo,manageInfo->areaInfo,manageInfo->areaSize,manageInfo->numOfDev,manageInfo->rateOfMagnify,manageInfo->sizeOfMinDev);
#if	__WORDSIZE == 64
	areaInfo = (IpcAreaInfo_t*)((uint64_t)manageInfo + sizeof(IpcAreaManageInfo_t));
#else	/* __WORDSIZE */
	areaInfo = (IpcAreaInfo_t*)((uint32_t)manageInfo + sizeof(IpcAreaManageInfo_t));
#endif	/* __WORDSIZE */
	for(i = 0;i < (manageInfo->numOfDev-1);i++) {
		(void)RPC_LogPrintNomark(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"  -- areaInfo:0x%x; numOfBlocks:%d; sizeOfBlock:%d; topAddr:0x%x; tailAddr:0x%x; freeListTop:0x%x; --\n",
				areaInfo,areaInfo->info.fixedAreaInfo.numOfBlocks,areaInfo->info.fixedAreaInfo.sizeOfBlock,areaInfo->info.fixedAreaInfo.topAddr,
				areaInfo->info.fixedAreaInfo.tailAddr, areaInfo->info.fixedAreaInfo.freeListTop);
		fixedInfo = (IpcFixedAreaFreeInfo_t*)areaInfo->info.fixedAreaInfo.freeListTop;
		while(fixedInfo != (IpcFixedAreaFreeInfo_t*)NULL) {
			(void)RPC_LogPrintNomark(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"    topAddr:0x%x; numOfBlocks:%d; nextFreeArea:0x%x;\n",fixedInfo,fixedInfo->numOfBlocks, fixedInfo->nextFreeArea);
			fixedInfo = (IpcFixedAreaFreeInfo_t*)fixedInfo->nextFreeArea;
		}
//		(void)RPC_LogPrintNomark(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"  -- END --\n");
		areaInfo++;
	}
	(void)RPC_LogPrintNomark(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"---- END ----\n");
	(void)RPC_MutexUnlock(&(manageInfo->mutexId));
	return;
}

static void IPC_printFreeAreaList(int fd) {
	void *addr;uint32_t totalSize;IpcAreaInfo_t *areaInfo;IpcAreaManageInfo_t *manageInfo;
	int i;//void *retAddr;
	IpcFreeAreaFreeInfo_t *freeInfo;IpcFreeAreaUsedInfo_t *usedInfo;IpcShmManageArea_t *ap;

	if(IPC_getShmAddrSize(fd, &addr, &totalSize) != RPC_SUCCESS) {
		return;
	}
	ap = (IpcShmManageArea_t*)addr;
	manageInfo = (IpcAreaManageInfo_t*)(ap->startOfIpcAreaManageInfo);
	if(RPC_MutexLock(&(manageInfo->mutexId)) != RPC_SUCCESS) {
		return;
	}
//	(void)RPC_LogPrintNomark(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"---- FixedFreeList manageInfo:0x%x; areaInfo:0x%x; areaSize:%d; numOfDev:%d; rateOfMagnify:%d; sizeOfMinDev:0x%x; ----\n",
//			manageInfo,(uint32_t)manageInfo + sizeof(IpcAreaManageInfo_t),manageInfo->areaSize,manageInfo->numOfDev,manageInfo->rateOfMagnify,manageInfo->sizeOfMinDev);
#if	__WORDSIZE == 64
	areaInfo = (IpcAreaInfo_t*)((uint64_t)manageInfo + sizeof(IpcAreaManageInfo_t));
#else	/* __WORDSIZE */
	areaInfo = (IpcAreaInfo_t*)((uint32_t)manageInfo + sizeof(IpcAreaManageInfo_t));
#endif	/* __WORDSIZE */
	for(i = 0;i < (manageInfo->numOfDev-1);i++) {
		areaInfo++;
	}
	(void)RPC_LogPrintNomark(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"---- FreeArea areaInfo:0x%x; topAddr:0x%x; tailAddr:0x%x; usedListTop:0x%x; freeListTop:0x%x; ----\n",
			areaInfo, areaInfo->info.freeAreaInfo.topAddr,areaInfo->info.freeAreaInfo.tailAddr,
			areaInfo->info.freeAreaInfo.usedListTop, areaInfo->info.freeAreaInfo.freeListTop);
	freeInfo = (IpcFreeAreaFreeInfo_t*)areaInfo->info.freeAreaInfo.freeListTop;
	(void)RPC_LogPrintNomark(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"  -- FreeList --\n");
	while(freeInfo != (IpcFreeAreaFreeInfo_t*)NULL) {
		(void)RPC_LogPrintNomark(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"    topAddr:0x%x; size:%d; nextBlock:0x%x;\n",
			freeInfo,freeInfo->size,freeInfo->nextBlock);
		freeInfo = freeInfo->nextBlock;
	}
//	(void)RPC_LogPrintNomark(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"  -- END --\n");
	usedInfo = (IpcFreeAreaFreeInfo_t*)areaInfo->info.freeAreaInfo.usedListTop;
	(void)RPC_LogPrintNomark(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"  -- UsedList --\n");
	while(usedInfo != (IpcFreeAreaFreeInfo_t*)NULL) {
		(void)RPC_LogPrintNomark(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"    topAddr:0x%x; size:%d; nextBlock:0x%x;\n",
			usedInfo, usedInfo->size,usedInfo->nextBlock);
		usedInfo = usedInfo->nextBlock;
	}
//	(void)RPC_LogPrintNomark(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"  -- END --\n");
	(void)RPC_LogPrintNomark(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"---- END ----\n");
	(void)RPC_MutexUnlock(&(manageInfo->mutexId));
	return;
}
#endif	/* DEBUG */

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

#ifdef	DEBUG

static int searchFreeArea(void** Area);
static int searchAllocatedArea(void** Area);
static RpcBool_t AllocOrFree(void);
static uint32_t AllocNum(void);

RpcResult_t shmTest(void);

RpcResult_t shmTest(void) {
	int fd1, fd2, fd3;void *addr;uint32_t size;
//	char *name;
	RpcResult_t ret;
	struct timeval curTime;
//	struct timeval sleepTime;
	uint32_t errCode;
	uint32_t aSize;int i,j;void *allocatedArea[100];

#if	0
	if((ret = IPC_InitSharedMem(IPC_TURE)) != RPC_SUCCESS) {
		(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,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_SHM,RPC_LOG_LEVEL_FATAL,"ERROR IN IPC_AttachSharedMem ret:%s;",RPC_LogConvertResultCode(ret));
		(void)IPC_DestroySharedMem();
		return ret;
	}
#endif	/* 0 */
	if((ret = IPC_GetShmInfo(IPC_MARSHAL_SHARED_MEM_NAME,&fd1, &addr, &size)) != RPC_SUCCESS) {
		(void)IPC_DettachSharedMem();
		(void)IPC_DestroySharedMem();
		return ret;
	}
	(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"SHM INFO NAME:%s; fd:%d; addr:0x%x; size:%d;",IPC_MARSHAL_SHARED_MEM_NAME,fd1,addr,size);
	if((ret = IPC_GetShmInfo(IPC_DATABASE_SHARED_MEM_NAME,&fd2, &addr, &size)) != RPC_SUCCESS) {
		(void)IPC_DettachSharedMem();
		(void)IPC_DestroySharedMem();
		return ret;
	}
	(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"SHM INFO NAME:%s; fd:%d; addr:0x%x; size:%d;",IPC_DATABASE_SHARED_MEM_NAME,fd2,addr,size);
	if((ret = IPC_GetShmInfo(IPC_MSG_QUE_SHARED_MEM_NAME,&fd3, &addr, &size)) != RPC_SUCCESS) {
		(void)IPC_DettachSharedMem();
		(void)IPC_DestroySharedMem();
		return ret;
	}
	(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"SHM INFO NAME:%s; fd:%d; addr:0x%x; size:%d;",IPC_MSG_QUE_SHARED_MEM_NAME,fd3,addr,size);
#if	0
	if((ret = IPC_InitShmGapArea(fd3, 1024)) != RPC_SUCCESS) {
		(void)IPC_DettachSharedMem();
		(void)IPC_DestroySharedMem();
		return ret;

	}
	if((ret = IPC_InitShmAllocArea(fd3, 1024*100,1, 64, 2)) != RPC_SUCCESS) {
		(void)IPC_DettachSharedMem();
		(void)IPC_DestroySharedMem();
		return ret;
	}
	IPC_printFixedAreaList(fd3);
	IPC_printFreeAreaList(fd3);
#endif	/* 0 */
	if((ret == RPC_GetTimeOfDay(&curTime,NULL,&errCode)) != RPC_SUCCESS) {
		(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,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));
	for(i = 0;i < 100;i++) {
		allocatedArea[i] = (void*)NULL;
	}
	(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"NOW TEST START");
	for(i = 0;i < 100;i++) {
		if(AllocOrFree()) {
			aSize = AllocNum();
			if((j = searchFreeArea(allocatedArea)) != -1) {
				allocatedArea[j] = IPC_AllocShmMem(fd3,aSize);
				(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"NOW ALLOC NUM:%d; SIZE:%d; PTR:0x%x;",j, aSize,allocatedArea[j]);
			}
			else {
				break;
			}
		}
		else {
			if((j = searchAllocatedArea(allocatedArea)) != -1) {
				IPC_FreeShmMem(fd3,allocatedArea[j]);
				(void)RPC_LogPrint(RPC_LOG_MODULE_SHM,RPC_LOG_LEVEL_DEBUG1,"NOW FREE NUM:%d; AREA:0x%x;",j, allocatedArea[j]);
				allocatedArea[j] = (void*)NULL;
			}
			else {
				continue;
			}
		}
//		if(i%10 == 0) {
			IPC_printFixedAreaList(fd3);
			IPC_printFreeAreaList(fd3);
//		}
	}
	(void)IPC_DettachSharedMem();
	(void)IPC_DestroySharedMem();
	return RPC_SUCCESS;
}

static int searchFreeArea(void** Area) {
	int i;RpcBool_t ok = RPC_FALSE;

retry:
	for(i = 0;i < 100;i++) {
		if(Area[i] == (void*)NULL) {
			ok = RPC_TRUE;
			if(AllocOrFree()) {
				continue;
			}
			return i;
		}
	}
	if(ok)
		goto retry;
	return -1;
}

static int searchAllocatedArea(void** Area) {
	int i;RpcBool_t ok = RPC_FALSE;

retry:
	for(i = 0;i < 100;i++) {
		if(Area[i] != (void*)NULL) {
			ok = RPC_TRUE;
			if(!AllocOrFree()) {
				continue;
			}
			return i;
		}
	}
	if(ok)
		goto retry;
	return -1;
}

static RpcBool_t AllocOrFree(void) {
	uint32_t val;

	val = RPC_Rand();
	if(val > RAND_MAX/2)
		return RPC_TRUE;
	else
		return RPC_FALSE;
}

static uint32_t AllocNum(void) {
	uint32_t val;

	for(;;) {
		val = RPC_Rand();
		if((val != 0)&&(val <= 5 * 1024))
			break;
	}
	return val;
}

#endif	/* DEBUG */
