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

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

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

static void RPC_convertErrCode(int err, RpcResult_t *ret);
static void RPC_convertErrno(int num, uint32_t *errCode);

/*----- SYSTEM CALL WRAPPER APIs -----*/

/*--- Task APIs ---*/

extern RpcResult_t RPC_CreateTask(RpcTaskID_t *taskId, RpcTaskAttribute_t *taskAttr, RPC_TaskStartRoutine_t startRoutine, void *arg) {
	int err; RpcResult_t ret;

	if((err = pthread_create((pthread_t*)taskId, (pthread_attr_t*)taskAttr, startRoutine, arg)) != 0) {
		RPC_convertErrCode(err,&ret);
//		*taskId = 0;
		return ret;
	}
	return RPC_SUCCESS;
}

extern void RPC_ExitTask(void *retVal) {
	pthread_exit(retVal);
}

extern RpcResult_t RPC_JoinTask(RpcTaskID_t taskId, void **retVal) {
	RpcResult_t ret;int err;

	if((err = pthread_join((pthread_t)taskId,retVal)) != 0) {
//		(void)RPC_LogPrint(RPC_LOG_MODULE_SYSCALL,RPC_LOG_LEVEL_ERROR,"FAIL IN RPC_JoinTask ERR:0x%x;",err);
		RPC_convertErrCode(err,&ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_DetachTask(RpcTaskID_t taskId) {
	RpcResult_t ret;int err;

	if((err = pthread_detach((pthread_t)taskId)) != 0) {
		RPC_convertErrCode(err,&ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_CancelTask(RpcTaskID_t taskId) {
	RpcResult_t ret;int err;

	if((err = pthread_cancel((pthread_t)taskId)) != 0) {
		RPC_convertErrCode(err,&ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_SetCancelState(int state, int *oldState) {
	RpcResult_t ret;int err;

	if((err = pthread_setcancelstate(state,oldState)) != 0) {
		RPC_convertErrCode(err,&ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_SetCancelType(int type, int *oldType) {
	RpcResult_t ret;int err;

	if((err = pthread_setcanceltype(type, oldType)) != 0) {
		RPC_convertErrCode(err,&ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_TestCancel(void) {
	pthread_testcancel();
	return RPC_SUCCESS;
}

extern RpcTaskID_t RPC_TaskSelf(void) {
	return (RpcTaskID_t)pthread_self();
}

/*
extern RpcResult_t RPC_TaskPushCleanup(void (*routine)(void*), void *arg) {
	pthread_cleanup_push(routine, arg);
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_TaskPopCleanup(int execute) {
	pthread_cleanup_pop(execute);
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_TaskPushdClenaupDeferNP(void (*routine)(void*), void *arg) {
	pthread_cleanup_push_defer_np(routine, arg);
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_TaskPopCleanupRestoreNP(int execute) {
	pthread_cleanup_pop_defer_np(execute);
	return RPC_SUCCESS;
}
*/

/*--- Task Attribute APIs ---*/

extern RpcResult_t RPC_TaskAttrInit(RpcTaskAttribute_t *taskAttr) {
	RpcResult_t ret;int err;

	if((err = pthread_attr_init((pthread_attr_t*)taskAttr)) != 0) {
		RPC_convertErrCode(err,&ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_TaskAttrSetDetachState(RpcTaskAttribute_t *taskAttr, int detachState) {
	RpcResult_t ret;int err;

	if((err = pthread_attr_setdetachstate((pthread_attr_t*)taskAttr, detachState)) != 0) {
		RPC_convertErrCode(err,&ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_TaskAttrGetDetachState(RpcTaskAttribute_t *taskAttr, int *detachState) {
	RpcResult_t ret;int err;

	if((err = pthread_attr_getdetachstate((pthread_attr_t*)taskAttr, detachState)) != 0) {
		RPC_convertErrCode(err,&ret);
		*detachState = PTHREAD_CREATE_JOINABLE;
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_TaskAttrSetSchedPolicy(RpcTaskAttribute_t *taskAttr, int policy) {
	RpcResult_t ret;int err;

	if((err = pthread_attr_setschedpolicy((pthread_attr_t*)taskAttr,policy)) != 0) {
		RPC_convertErrCode(err,&ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_TaskAttrGetSchedPolicy(RpcTaskAttribute_t *taskAttr, int *policy) {
	RpcResult_t ret;int err;

	if((err = pthread_attr_getschedpolicy((pthread_attr_t*)taskAttr, policy)) != 0) {
		RPC_convertErrCode(err,&ret);
		*policy = SCHED_OTHER;
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_TaskAttrSetSchedParam(RpcTaskAttribute_t *taskAttr, RpcTaskSchedParam_t *schedParam) {
	RpcResult_t ret; int err;

	if((err = pthread_attr_setschedparam((pthread_attr_t*)taskAttr, (struct sched_param*)schedParam)) != 0) {
		RPC_convertErrCode(err,&ret);
		return ret;
	}
	return RPC_SUCCESS;
}
extern RpcResult_t RPC_TaskAttrGetSchedParam(RpcTaskAttribute_t *taskAttr, RpcTaskSchedParam_t *schedParam) {
	RpcResult_t ret;int err;

	if((err = pthread_attr_getschedparam((pthread_attr_t*)taskAttr, (struct sched_param*)schedParam)) != 0) {
		RPC_convertErrCode(err, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_TaskAttrSetInheritSched(RpcTaskAttribute_t *taskAttr, int inherit) {
	RpcResult_t ret;int err;

	if((err = pthread_attr_setinheritsched((pthread_attr_t*)taskAttr, inherit)) != 0) {
		RPC_convertErrCode(err, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_TaskAttrGetInheritSched(RpcTaskAttribute_t *taskAttr, int *inherit) {
	RpcResult_t ret;int err;

	if((err = pthread_attr_getinheritsched((pthread_attr_t*)taskAttr, inherit)) != 0) {
		RPC_convertErrCode(err, &ret);
		*inherit = PTHREAD_EXPLICIT_SCHED;
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_TaskAttrDestroy(RpcTaskAttribute_t *taskAttr) {
	RpcResult_t ret;int err;

	if((err = pthread_attr_destroy(taskAttr)) != 0) {
		RPC_convertErrCode(err, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_TaskAttrSetStackSize(RpcTaskAttribute_t *taskAttr, int stackSize) {
	RpcResult_t ret;int err;

	if((err = pthread_attr_setstacksize((pthread_attr_t*)taskAttr, stackSize)) != 0) {
		RPC_convertErrCode(err, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_TaskAttrGetStackSize(RpcTaskAttribute_t *taskAttr, int *stackSize) {
	RpcResult_t ret;int err;

	if((err = pthread_attr_getstacksize(taskAttr, (size_t*)stackSize)) != 0) {
		RPC_convertErrCode(err, &ret);
		*stackSize = PTHREAD_STACK_MIN;
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_TaskAttrSetStack(RpcTaskAttribute_t *taskAttr, void *stackAddr, int stackSize) {
	RpcResult_t ret;int err;

	if((err = pthread_attr_setstack((pthread_attr_t*)taskAttr, stackAddr, stackSize)) != 0) {
		RPC_convertErrCode(err, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_TaskAttrGetStack(RpcTaskAttribute_t *taskAttr, void **stackAddr, int *stackSize) {
	RpcResult_t ret;int err;

	if((err = pthread_attr_getstack((pthread_attr_t*)taskAttr, stackAddr, (size_t*)stackSize)) != 0) {
		RPC_convertErrCode(err, &ret);
		*stackAddr = (void*)NULL;
		*stackSize = PTHREAD_STACK_MIN;
		return ret;
	}
	return RPC_SUCCESS;
}

/*--- Task Schedule APIs ---*/

extern RpcResult_t RPC_TaskYield(void) {
#ifdef	__USE_GNU
	{
	RpcResult_t ret; int err;

	if((err = pthread_yield()) < 0) {
		RPC_convertErrCode(err,&ret);
		return ret;
	}
	return RPC_SUCCESS;
	}
#else	/* __USE_GNU */
	{
	uint32_t errCode;

	if(sched_yield() < 0) {
		RPC_convertErrno(errno, &errCode);
		return RPC_SYSCALL_ERROR;
	}
	return RPC_SUCCESS;
	}
#endif	/* __USE_GNU */
}

extern RpcResult_t RPC_TaskSleep(struct timeval *sleepTime,struct timeval *remainTime) {
	struct timespec req,rem;
//	uint32_t errCode;

	if(remainTime != (struct timeval*)NULL) {
		(void)memset((void*)remainTime,0,sizeof(struct timeval));
	}
	if(sleepTime == (struct timeval*)NULL) {
		return RPC_PARAM_ERROR;
	}
	req.tv_sec = sleepTime->tv_sec;
	req.tv_nsec = sleepTime->tv_usec * 1000;
	if(nanosleep(&req,&rem) != 0) {
//		RPC_convertErrno(errno,&errCode);
		if(remainTime != (struct timeval*)NULL) {
			remainTime->tv_sec = rem.tv_sec;
			remainTime->tv_usec = rem.tv_nsec * 1000;
		}
		return RPC_INTERUPTTED;
	}
	if(remainTime != (struct timeval*)NULL) {
#if	0
		remainTime->tv_sec = rem.tv_sec;
		remainTime->tv_usec = rem.tv_nsec * 1000;
#else	/* 0 */
		(void)memset((void*)remainTime,0,sizeof(struct timeval));
#endif	/* 0 */
	}
	return RPC_SUCCESS;
}

/*--- Mutex APIs ---*/

extern RpcResult_t RPC_InitMutex(RpcMutexID_t *mutexID, RpcMutexAttribute_t *mutexAttr) {
	RpcResult_t ret; int err;

	if((err = pthread_mutex_init((pthread_mutex_t*)mutexID, (pthread_mutexattr_t*)mutexAttr)) != 0) {
		RPC_convertErrCode(err, &ret);
//		*mutexID = 0;
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_MutexLock(RpcMutexID_t *mutexID) {
	RpcResult_t ret;int err;

	if((err = pthread_mutex_lock((pthread_mutex_t*)mutexID)) != 0) {
		RPC_convertErrCode(err, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_MutexUnlock(RpcMutexID_t *mutexID) {
	RpcResult_t ret;int err;

	if((err = pthread_mutex_unlock((pthread_mutex_t*)mutexID)) != 0) {
		RPC_convertErrCode(err, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_MutexLockTry(RpcMutexID_t *mutexID) {
	RpcResult_t ret;int err;

	if((err = pthread_mutex_trylock((pthread_mutex_t*)mutexID)) != 0) {
		RPC_convertErrCode(err, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_MutexDestroy(RpcMutexID_t *mutexID) {
	RpcResult_t ret;int err;

	if((err = pthread_mutex_destroy((pthread_mutex_t*)mutexID)) != 0) {
		RPC_convertErrCode(err, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_MutexTimedLock(RpcMutexID_t *mutexID,struct timespec *absTime) {
	RpcResult_t ret;int err;

	if((err = pthread_mutex_timedlock((pthread_mutex_t*)mutexID,absTime)) != 0) {
		RPC_convertErrCode(err, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

/*--- Mutex Attribute APIs ---*/

extern RpcResult_t RPC_MutexAttrInit(RpcMutexAttribute_t *mutexAttr) {
	RpcResult_t ret;int err;

	if((err = pthread_mutexattr_init((pthread_mutexattr_t*)mutexAttr)) != 0) {
		RPC_convertErrCode(err, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_MutexAttrSetType(RpcMutexAttribute_t *mutexAttr, int kind) {
	RpcResult_t ret;int err;

	if((err = pthread_mutexattr_settype(mutexAttr, kind)) != 0) {
		RPC_convertErrCode(err, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_MutexAttrGetType(RpcMutexAttribute_t *mutexAttr, int *kind) {
	RpcResult_t ret;int err;

	if((err = pthread_mutexattr_gettype(mutexAttr, kind)) != 0) {
		RPC_convertErrCode(err, &ret);
#ifdef	_LINUX_
		*kind = PTHREAD_MUTEX_ADAPTIVE_NP;
#else	/* _LINUX_ */
		*kind = PTHREAD_MUTEX_RECURSIVE;
#endif	/* _LINUX_ */
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_MutexAttrDestroy(RpcMutexAttribute_t *mutexAttr) {
	RpcResult_t ret;int err;

	if((err = pthread_mutexattr_destroy(mutexAttr)) != 0) {
		RPC_convertErrCode(err, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_MutexAttrGetPshared(RpcMutexAttribute_t *mutexAttr, int *pshared) {
	RpcResult_t ret;int err;

	if((err = pthread_mutexattr_getpshared((pthread_mutexattr_t*)mutexAttr, pshared)) != 0) {
		RPC_convertErrCode(err, &ret);
		*pshared = PTHREAD_PROCESS_PRIVATE;
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_MutexAttrSetPshared(RpcMutexAttribute_t *mutexAttr, int pshared) {
	RpcResult_t ret;int err;

	if((err = pthread_mutexattr_setpshared((pthread_mutexattr_t*)mutexAttr, pshared)) != 0) {
		RPC_convertErrCode(err, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

/*--- Condition Variable APIs ---*/

extern RpcResult_t RPC_InitCond(RpcCondID_t *condID, RpcCondAttribute_t *condAttr) {
	RpcResult_t ret;int err;

	if((err = pthread_cond_init((pthread_cond_t*)condID, (pthread_condattr_t*)condAttr)) != 0) {
		RPC_convertErrCode(err, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_CondSignal(RpcCondID_t *condID) {
	RpcResult_t ret;int err;

	if((err = pthread_cond_signal((pthread_cond_t*)condID)) != 0) {
		RPC_convertErrCode(err, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_CondBroadcast(RpcCondID_t *condID) {
	RpcResult_t ret;int err;

	if((err = pthread_cond_broadcast((pthread_cond_t*)condID)) != 0) {
		RPC_convertErrCode(err, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_CondWait(RpcCondID_t *condID, RpcMutexID_t *mutexID) {
	RpcResult_t ret;int err;

	if((err = pthread_cond_wait((pthread_cond_t*)condID, (pthread_mutex_t*)mutexID)) != 0) {
		RPC_convertErrCode(err, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_CondWaitTimeout(RpcCondID_t *condID, RpcMutexID_t *mutexID, struct timespec *abstime) {
	RpcResult_t ret;int err;

	if((err = pthread_cond_timedwait((pthread_cond_t*)condID, (pthread_mutex_t*)mutexID, abstime)) != 0) {
		RPC_convertErrCode(err, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_CondDestroy(RpcCondID_t *condID) {
	RpcResult_t ret;int err;

	if((err = pthread_cond_destroy(condID)) != 0) {
		RPC_convertErrCode(err, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

/*--- Condition Variable Attribute APIs ---*/

extern RpcResult_t RPC_CondAttrInit(RpcCondAttribute_t *condAttr) {
	RpcResult_t ret;int err;

	if((err = pthread_condattr_init((pthread_condattr_t*)condAttr)) != 0) {
		RPC_convertErrCode(err, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_CondAttrDestroy(RpcCondAttribute_t *condAttr) {
	RpcResult_t ret;int err;

	if((err = pthread_condattr_destroy(condAttr)) != 0) {
		RPC_convertErrCode(err, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_CondAttrGetPshared(RpcCondAttribute_t *condAttr, int *pshared) {
	RpcResult_t ret;int err;

	if((err = pthread_condattr_getpshared((pthread_condattr_t*)condAttr, pshared)) != 0) {
		RPC_convertErrCode(err, &ret);
		*pshared = PTHREAD_PROCESS_PRIVATE;
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_CondAttrSetPshared(RpcCondAttribute_t *condAttr, int pshared) {
	RpcResult_t ret;int err;

	if((err = pthread_condattr_setpshared((pthread_condattr_t*)condAttr, pshared)) != 0) {
		RPC_convertErrCode(err, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

/*--- Semaphore APIs ---*/

extern RpcResult_t RPC_SemInit(RpcSem_t *sem, int pshared, int value) {
	RpcResult_t ret;int err;int errNo;

	if((err = sem_init(sem,pshared,value)) != 0) {
		errNo = errno;
		RPC_convertErrCode(errNo, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_SemPost(RpcSem_t *sem) {
	RpcResult_t ret;int err;int errNo;

	if((err = sem_post(sem)) != 0) {
		errNo = errno;
		RPC_convertErrCode(errNo, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_SemWait(RpcSem_t *sem) {
	RpcResult_t ret;int err;int errNo;

	if((err = sem_wait(sem)) != 0) {
		errNo = errno;
		RPC_convertErrCode(errNo, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_SemWaitTry(RpcSem_t *sem) {
	RpcResult_t ret;int err;int errNo;

	if((err = sem_trywait(sem)) != 0) {
		errNo = errno;
		if(errNo == EAGAIN) {
			ret = RPC_BUSY_ERROR;
			return ret;
		}
		RPC_convertErrCode(errNo, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_SemTimedWait(RpcSem_t *sem,struct timespec *absTime) {
	RpcResult_t ret;int err;int errNo;

	if((err = sem_timedwait(sem,absTime)) != 0) {
		errNo = errno;
		RPC_convertErrCode(errNo, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_SemGetValue(RpcSem_t *sem,int *value) {
	RpcResult_t ret;int err;int errNo;

	if((err = sem_getvalue(sem,value)) != 0) {
		errNo = errno;
		RPC_convertErrCode(errNo, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_SemDestroy(RpcSem_t *sem) {
	RpcResult_t ret;int err;int errNo;

	if((err = sem_destroy(sem)) != 0) {
		errNo = errno;
		RPC_convertErrCode(errNo, &ret);
		return ret;
	}
	return RPC_SUCCESS;
}

/*--- Shared Memory APIs ---*/

extern RpcResult_t RPC_ShmOpen(char *name, int oflag, mode_t mode, int *fd, uint32_t *errCode) {
//	(void)RPC_LogPrint(RPC_LOG_MODULE_SYSCALL,RPC_LOG_LEVEL_DEBUG1,"NOW EXEC RPC_ShmOpen name:%s; oflag:0x%x; mode:O%o fd:0x%x",name, oflag, mode,fd);
	if((*fd = shm_open(name, oflag, mode)) < 0) {
		RPC_convertErrno(errno, errCode);
		return RPC_SYSCALL_ERROR;
	}
//	(void)RPC_LogPrint(RPC_LOG_MODULE_SYSCALL,RPC_LOG_LEVEL_DEBUG1,"SUCCESS RPC_ShmOpen fd:%d",*fd);
	*errCode = RPC_NO_ERROR;
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_ShmUnlink(char *name, uint32_t *errCode) {
	if(shm_unlink(name) != 0) {
		RPC_convertErrno(errno, errCode);
		return RPC_SYSCALL_ERROR;
	}
	*errCode = RPC_NO_ERROR;
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_ShmClose(int fd, uint32_t *errCode) {
	if(close(fd) != 0) {
		RPC_convertErrno(errno, errCode);
		return RPC_SYSCALL_ERROR;
	}
	*errCode = RPC_NO_ERROR;
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_ShmMap(void *addr, int length, int prot, int flag, int fd, off_t offset, void **allocAddr, uint32_t *errCode) {
	if((*allocAddr = mmap(addr, length, prot, flag, fd, offset)) == MAP_FAILED) {
		RPC_convertErrno(errno,errCode);
		return RPC_SYSCALL_ERROR;
	}
	*errCode = RPC_NO_ERROR;
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_ShmUnmap(void *addr,int length, uint32_t *errCode) {
	if(munmap(addr, length) != 0) {
		RPC_convertErrno(errno,errCode);
		return RPC_SYSCALL_ERROR;
	}
	*errCode = RPC_NO_ERROR;
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_ShmFtruncate(int fd, off_t length, uint32_t *errCode) {
	if(ftruncate(fd, length) != 0) {
		RPC_convertErrno(errno, errCode);
		return RPC_SYSCALL_ERROR;
	}
	*errCode = RPC_NO_ERROR;
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_ShmFstat(int fd, struct stat *buff, uint32_t *errCode) {
	if(fstat(fd, buff) != 0) {
		RPC_convertErrno(errno, errCode);
		return RPC_SYSCALL_ERROR;
	}
	*errCode = RPC_NO_ERROR;
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_ShmFchown(int fd, uid_t owner, gid_t group, uint32_t *errCode) {
	if(fchown(fd, owner, group) != 0) {
		RPC_convertErrno(errno, errCode);
		return RPC_SYSCALL_ERROR;
	}
	*errCode = RPC_NO_ERROR;
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_ShmFchmod(int fd, mode_t mode, uint32_t *errCode) {
	if(fchmod(fd, mode) != 0) {
		RPC_convertErrno(errno, errCode);
		return RPC_SYSCALL_ERROR;
	}
	*errCode = RPC_NO_ERROR;
	return RPC_SUCCESS;
}

/*--- Memory Allocation APIs ---*/

extern void *RPC_AllocMem(uint32_t size) {
	void *memP;

	if((memP = malloc(size)) == (void*)NULL) {
		return (void*)NULL;
	}
	return memP;
}

extern void *RPC_ReallocMem(void *memP, uint32_t newSize) {
	void *newMemP;

	if((newMemP = realloc(memP, newSize)) == (void*)NULL) {
		return (void*)NULL;
	}
	return newMemP;
}

extern void RPC_FreeMem(void *memP) {
	free(memP);
}

/*--- Time APIs ---*/

extern RpcResult_t RPC_GetTimeOfDay(struct timeval *timeVal, struct timezone *timeZone, uint32_t *errCode) {
	if(gettimeofday(timeVal,timeZone) != 0) {
		RPC_convertErrno(errno,errCode);
		return RPC_SYSCALL_ERROR;
	}
	*errCode = RPC_NO_ERROR;
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_SetTimeOfDay(struct timeval *timeVal, struct timezone *timeZone, uint32_t *errCode) {
	if(settimeofday(timeVal,timeZone) != 0) {
		RPC_convertErrno(errno,errCode);
		return RPC_SYSCALL_ERROR;
	}
	*errCode = RPC_NO_ERROR;
	return RPC_SUCCESS;
}

/*--- Process APIs ---*/

extern uint32_t RPC_GetPid(void) {
	return (uint32_t)getpid();
}

extern RpcResult_t RPC_Fork(int32_t *pid,uint32_t *errCode) {
	if((*pid = (int32_t)fork()) == 0) {
		*errCode = RPC_NO_ERROR;
		return RPC_SUCCESS;
	}
	else if(*pid  != -1) {
		*errCode = RPC_NO_ERROR;
		return RPC_SUCCESS;
	}
	else {
		RPC_convertErrno(errno,errCode);
		return RPC_SYSCALL_ERROR;
	}
}

extern RpcResult_t RPC_Exec(char *filePath,char *argv[],char *envp[],uint32_t *errCode) {
	if(execve(filePath,argv,envp) == -1) {
		RPC_convertErrno(errno,errCode);
		return RPC_SYSCALL_ERROR;
	}
	*errCode = RPC_NO_ERROR;
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_Wait(int32_t *pid,int *status,uint32_t *errCode) {
	if((*pid = (int32_t)wait(status)) == -1) {
		RPC_convertErrno(errno,errCode);
		*pid = -1;
		return RPC_SYSCALL_ERROR;
	}
	*errCode = RPC_NO_ERROR;
	return RPC_SUCCESS;
}

extern RpcResult_t RPC_WaitPid(int32_t *pid,int *status,int options,uint32_t *errCode) {
	if((*pid = (int32_t)waitpid(*pid,status,options)) == -1) {
		RPC_convertErrno(errno,errCode);
		*pid = -1;
		return RPC_SYSCALL_ERROR;
	}
	*errCode = RPC_NO_ERROR;
	return RPC_SUCCESS;
}

extern void RPC_Exit(int32_t status) {
	_exit(status);
}

extern RpcResult_t RPC_Kill(int32_t pid,int32_t sig,uint32_t *errCode) {
	if(kill(pid,sig) == -1) {
		RPC_convertErrno(errno,errCode);
		return RPC_SYSCALL_ERROR;
	}
	*errCode = RPC_NO_ERROR;
	return RPC_SUCCESS;
}

/*--- Other APIs ---*/

extern void RPC_Srand(uint32_t seed) {
	static RpcBool_t srandCallFlag = RPC_FALSE;

	if(!srandCallFlag) {
		srandCallFlag = RPC_TRUE;
		srandom(seed);
	}
}

extern uint32_t RPC_Rand(void) {
	return random();
}


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

static void RPC_convertErrCode(int err, RpcResult_t *ret) {
	if(ret == (RpcResult_t*)NULL) {
		return;
	}
	switch(err) {
	case EAGAIN:
		*ret = RPC_NO_MORE_RESOURCE; break;
	case ESRCH:
	case EINVAL:
	case EPERM:
	case ENOSYS:
	case E2BIG:
	case ENOEXEC:
	case ECHILD:
		*ret = RPC_PARAM_ERROR; break;
	case ENOTSUP:
	case EDEADLK:
	case ELIBBAD:
	case ETXTBSY:
		*ret = RPC_CAN_NOT_EXEC; break;
	case EBUSY:
		*ret = RPC_BUSY_ERROR; break;
	case ETIMEDOUT:
		*ret = RPC_TIMEOUT_ERROR; break;
	case EINTR:
		*ret = RPC_INTERUPTTED; break;
	default:
		*ret = RPC_FATAL_ERROR; break;
	}
	return;
}

static void RPC_convertErrno(int num, uint32_t *errCode) {
	if(errCode == (uint32_t*)NULL) {
		return;
	}
	switch(num) {
	case EACCES:
		*errCode = RPC_ERR_EACCES; break;
	case EEXIST:
		*errCode = RPC_ERR_EEXIST; break;
	case EINVAL:
		*errCode = RPC_ERR_EINVAL; break;
	case ENOENT:
		*errCode = RPC_ERR_ENOENT; break;
	case ENAMETOOLONG:
		*errCode = RPC_ERR_ENAMETOOLONG; break;
	case EFAULT:
		*errCode = RPC_ERR_EFAULT; break;
	case ELOOP:
		*errCode = RPC_ERR_ELOOP; break;
	case EISDIR:
		*errCode = RPC_ERR_EISDIR; break;
	case ENOTDIR:
		*errCode = RPC_ERR_ENOTDIR; break;
	case EPERM:
		*errCode = RPC_ERR_EPERM; break;
	case EROFS:
		*errCode = RPC_ERR_EROFS; break;
	case ETXTBSY:
		*errCode = RPC_ERR_ETXTBSY; break;
	case EBADF:
		*errCode = RPC_ERR_EBADF; break;
	case ENODEV:
		*errCode = RPC_ERR_ENODEV; break;
	case EOVERFLOW:
		*errCode = RPC_ERR_EOVERFLOW; break;
	case EMFILE:
		*errCode = RPC_ERR_EMFILE; break;
	case ENFILE:
		*errCode = RPC_ERR_ENFILE; break;
	case ENOMEM:
		*errCode = RPC_ERR_ENOMEM; break;
	case EINTR:
		*errCode = RPC_ERR_EINTR; break;
	case EIO:
		*errCode = RPC_ERR_EIO; break;
	case EAGAIN:
		*errCode = RPC_ERR_EAGAIN; break;
	case EFBIG:
		*errCode = RPC_ERR_EFBIG; break;
	case ENOSYS:
		*errCode = RPC_ERR_ENOSYS; break;
	case E2BIG:
		*errCode = RPC_ERR_E2BIG; break;
	case ELIBBAD:
		*errCode = RPC_ERR_ELIBBAD; break;
	case ENOEXEC:
		*errCode = RPC_ERR_ENOEXEC; break;
	case ECHILD:
		*errCode = RPC_ERR_ECHILD; break;
	case ETIMEDOUT:
		*errCode = RPC_ERR_ETIMEDOUT; break;
	default:
		*errCode = RPC_ERR_OTHER; break;
	}
	return;
}
