/*******************************************************************************
 * Copyright (c) 2005, 2009 Intel Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Hoang M Nguyen, Intel - TPTP OS Calls Linux specific Implementation
 * $Id: TPTPOSCalls_linux.c,v 1.19 2009/01/27 19:20:01 jcayne Exp $
 *******************************************************************************/ 


#if defined _LINUX_X86 || defined _LINUX_390 // Linux-specific


#include <stdio.h>

#include "TPTPOSCalls.h"
#include <string.h>


#include <uuid/uuid.h>
#include <dlfcn.h>


const char OS_SPECIFIC_NAME_SEPARATOR = '/' ;

#define LIB_DIR "lib"
#define LIB_FILE_EXT  ".so"




/**
 *********************************************************
 *
 * @brief
 *    Return a global unique id string (GUID or UUID)
 *
 * @note
 *    This requires to compile with "libuuid.so" library
 *    or "-luuid" option.
 *
 *********************************************************/

char * getGlobalUniqueId()
{
   char * pTokenStr = NULL ;

   unsigned char token[16] ;

   char buffer[37] ;

   uuid_generate(token) ;

   uuid_unparse(token, buffer) ;

   pTokenStr = strdup(buffer) ;

   return ( pTokenStr ) ;
}

/**
 *********************************************************
 *                                                       
 * @brief                                                
 *    convenient way to compare string ignoring case
 *    and is still platform independent.
 *
 *********************************************************/
 
int compareIgnoreCase(const char *pStr1, const char *pStr2)
{
	return ( strcasecmp(pStr1, pStr2) ) ;
}



/**
 *********************************************************
 *                                                       
 * @brief                                                
 *    load the given module
 *
 *********************************************************/
 
void * loadTheModule(const char *pLibName)
{
	char buffer[1024] ;

	strcpy(buffer, LIB_DIR) ;
	strcat(buffer, pLibName) ;
	strcat(buffer, LIB_FILE_EXT) ;

	return ( dlopen( buffer, RTLD_LAZY ) );
}


/**
 *********************************************************
 *                                                       
 * @brief                                                
 *    Start a new running thread and execute the given function
 *       in that running thread.
 *
 * @return
 *    0 - Success
 *    Nonzero - Error
 *
 *********************************************************/

int  startNewThread(RUN_FUNC_TYPE  pFunc, void * pParmBlock, TID *pThreadId, HANDLE *pThreadHandle)
{
	int    rc = 0 ;

	rc = pthread_create(pThreadId, NULL, pFunc, pParmBlock);
	/* Clear pThreadHandle as it is only used for Windows version of this function. */
	*pThreadHandle = 0; /* Use 0 rather than NULL to stop compiler warning. */

	if (rc != 0)
		rc = 1 ;
	
	return ( rc ) ;
}


/**
 *********************************************************
 *                                                       
 * @brief                                                
 *    Indicate that thread resources can be reclaimed when the thread terminates.
 *
 * @return
 *    0 - Success
 *    Nonzero - Error
 *
 *********************************************************/

int  detachThread(TID threadId, HANDLE threadHandle)
{
	return pthread_detach (threadId);
}

/**
 *********************************************************
 *                                                       
 * @brief                                                
 *    Start a new running thread, execute the given function
 *       in that running thread, detach from the thread.
 *
 * @return
 *    0 - Success
 *    Nonzero - Error
 *
 *********************************************************/

int  tptpStartThread(RUN_FUNC_TYPE  pFunc, void * pParamBlock, TID *pThreadId, HANDLE *pThreadHandle)
{
	int    rc = startNewThread (pFunc, pParamBlock, pThreadId, pThreadHandle);
	
	if (!rc) detachThread (*pThreadId, *pThreadHandle);
	
	return ( rc ) ;
}


/**
 *********************************************************
 *                                                       
 * @brief                                                
 *    Return the process id of the current running process
 *
 *********************************************************/

PID  getCurrentlyRunningProcessId()
{
	return ( getpid() ) ;
}

/**
 *********************************************************
 *                                                       
 * @brief                                                
 *    Return the executable name of the current running process.
 *    Caller must free the allocated memory for the name string returned.
 *
 *********************************************************/

char *getExecutableName()
{
	char *exeName = NULL;
	char procFileName[128];
	char cmdLine[_MAX_PATH];
	FILE *hFile = NULL;
	int num = 0;

	/* Get the name of the executable for this process from the /proc
	* file structure.  The file /proc/<pid>/cmdline contains the cmdline
	* arguments as null terminated strings.  So reading the first element
	* of that file gives us the executable name (i.e., argv[0]).
	*/
	sprintf(procFileName, "/proc/%d/cmdline",getpid());
	hFile = fopen(procFileName,"r");
	if (hFile)
	{
		num = fread(cmdLine, _MAX_PATH, 1, hFile);
		if (!ferror(hFile))
		{
			/*Make sure a null is at the end of whatever we read*/
			cmdLine[_MAX_PATH-1] = '\0';
			exeName = (char *)tptp_malloc(strlen(cmdLine) +1);
			strcpy(exeName, cmdLine);
			return exeName;
		}
	}

	/* if error occurred trying to get the name, just return 'unknown' */
	exeName = (char *)tptp_malloc(strlen(UNKNOWN_EXE) +1);
	strcpy(exeName, UNKNOWN_EXE);
	return exeName;
}

/**
 *********************************************************
 *                                                       
 * @brief                                                
 *    Return the process id of the current running process
 *
 *********************************************************/

PID  getCurrentlyRunningThreadId()
{
	/* On Linux the Process ID is the thread ID */
	return ( getpid() ) ;
}

/**
 *********************************************************
 *                                                       
 * @brief                                                
 *    Print out the current system error message
 *
 *********************************************************/
void printCurrentSysError()
{
	printf("errno(%d) error_message(%s) \n", errno, strerror(errno)); 
}


/**
 *********************************************************
 *                                                       
 * @brief                                                
 *    Put the current thread in sleep mode
 *    for a given amount of time (in milliseconds)
 *
 *********************************************************/
void  tptpSleep(int milliseconds)
{
    long seconds   = milliseconds / 1000;
    long remainder_in_micro_seconds = (milliseconds % 1000) * 1000;

	if (seconds != 0)
		sleep(seconds);
	
	if (remainder_in_micro_seconds != 0)
		usleep(remainder_in_micro_seconds);
}


#endif   // end-of-Linux-specific



