Files
mars-flaim/ftk/src/ftkmisc.cpp

3036 lines
64 KiB
C++

//------------------------------------------------------------------------------
// Desc: This file contains misc toolkit functions
//
// Tabs: 3
//
// Copyright (c) 2000-2006 Novell, Inc. All Rights Reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of version 2 of the GNU General Public
// License as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, contact Novell, Inc.
//
// To contact Novell about this file by physical or electronic mail,
// you may find current contact information at www.novell.com
//
// $Id: ftkmisc.cpp 3115 2006-01-19 13:24:39 -0700 (Thu, 19 Jan 2006) dsanders $
//------------------------------------------------------------------------------
#include "ftksys.h"
static FLMATOMIC gv_startupCount = 0;
static FLMUINT gv_uiRandomGenInitCount = 0;
static F_MUTEX gv_hRandomGenMutex = F_MUTEX_NULL;
static IF_RandomGenerator * gv_pRandomGenerator = NULL;
static IF_ThreadMgr * gv_pThreadMgr = NULL;
static IF_FileSystem * gv_pFileSystem = NULL;
static FLMUINT gv_uiMaxFileSize = FLM_MAXIMUM_FILE_SIZE;
static F_XML * gv_pXml = NULL;
FLMATOMIC gv_openFiles = 0;
F_MUTEX F_FileHdl::m_hAsyncListMutex = F_MUTEX_NULL;
F_FileAsyncClient * F_FileHdl::m_pFirstAvailAsync = NULL;
FLMUINT F_FileHdl::m_uiAvailAsyncCount = 0;
FSTATIC RCODE f_initRandomGenerator( void);
FSTATIC void f_freeRandomGenerator( void);
#ifdef FLM_AIX
#ifndef nsleep
extern "C"
{
extern int nsleep( struct timestruc_t *, struct timestruc_t *);
}
#endif
#endif
/****************************************************************************
Desc:
****************************************************************************/
static FLMBYTE gv_ucSENLengthArray[] =
{
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 - 15
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 16 - 31
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 32 - 47
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 48 - 63
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 - 79
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80 - 95
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 - 111
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 112 - 127
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 128 - 143
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 144 - 159
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 160 - 175
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 176 - 191
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 192 - 207
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 208 - 223
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 224 - 239
5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 8, 9 // 240 - 255
};
/****************************************************************************
Desc:
****************************************************************************/
static FLMBYTE ucSENPrefixArray[] =
{
0,
0,
0x80,
0xC0,
0xE0,
0xF0,
0xF8,
0xFC,
0xFE,
0xFF
};
/****************************************************************************
Desc:
****************************************************************************/
RCODE FLMAPI ftkStartup( void)
{
RCODE rc = NE_FLM_OK;
if( f_atomicInc( &gv_startupCount) > 1)
{
goto Exit;
}
// Sanity check -- make sure we are using the correct
// byte-swap macros for this platform
f_assert( FB2UD( (FLMBYTE *)"\x0A\x0B\x0C\x0D") == 0x0D0C0B0A);
f_assert( FB2UW( (FLMBYTE *)"\x0A\x0B") == 0x0B0A);
// Verify that the platform word size is correct
#ifdef FLM_64BIT
f_assert( sizeof( FLMUINT) == 8);
#else
f_assert( sizeof( FLMUINT) == 4);
#endif
#if defined( FLM_RING_ZERO_NLM)
if( RC_BAD( rc = f_netwareStartup()))
{
goto Exit;
}
#endif
f_memoryInit();
#if !defined( FLM_RING_ZERO_NLM)
f_assert( sizeof( f_va_list) == sizeof( va_list));
#endif
if( RC_BAD( rc = f_initCharMappingTables()))
{
goto Exit;
}
if( RC_BAD( rc = f_verifyDiskStructOffsets()))
{
goto Exit;
}
if( RC_BAD( rc = f_allocFileSystem( &gv_pFileSystem)))
{
goto Exit;
}
if( RC_BAD( rc = f_initFileAsyncClientList()))
{
goto Exit;
}
if( RC_BAD( rc = f_allocThreadMgr( &gv_pThreadMgr)))
{
goto Exit;
}
if( RC_BAD( rc = f_initRandomGenerator()))
{
goto Exit;
}
if( RC_BAD( rc = f_initCRCTable()))
{
goto Exit;
}
f_initFastCheckSum();
if( (gv_pXml = f_new F_XML) == NULL)
{
rc = RC_SET( NE_FLM_MEM);
goto Exit;
}
if( RC_BAD( rc = gv_pXml->setup()))
{
goto Exit;
}
#ifdef FLM_DEBUG
if( RC_BAD( rc = f_verifyMetaphoneRoutines()))
{
goto Exit;
}
#endif
#if defined( FLM_LINUX)
f_setupLinuxKernelVersion();
gv_uiMaxFileSize = f_getLinuxMaxFileSize();
#elif defined( FLM_AIX)
// Call setrlimit to increase the max allowed file size.
// We don't have a good way to deal with any errors returned by
// setrlimit(), so we just hope that there aren't any ...
struct rlimit rlim;
rlim.rlim_cur = RLIM_INFINITY;
rlim.rlim_max = RLIM_INFINITY;
setrlimit( RLIMIT_FSIZE, &rlim);
#endif
// Setup logger
if (RC_BAD( rc = f_loggerInit()))
{
goto Exit;
}
Exit:
if( RC_BAD( rc))
{
ftkShutdown();
}
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
void FLMAPI ftkShutdown( void)
{
if( !gv_startupCount || f_atomicDec( &gv_startupCount) > 0)
{
return;
}
f_assert( !gv_openFiles);
if( gv_pThreadMgr)
{
gv_pThreadMgr->Release();
gv_pThreadMgr = NULL;
}
f_freeFileAsyncClientList();
if( gv_pFileSystem)
{
gv_pFileSystem->Release();
gv_pFileSystem = NULL;
}
f_freeCRCTable();
if( gv_pXml)
{
gv_pXml->Release();
}
f_loggerShutdown();
f_freeRandomGenerator();
f_freeCharMappingTables();
f_memoryCleanup();
#if defined( FLM_RING_ZERO_NLM)
f_netwareShutdown();
#endif
}
/****************************************************************************
Desc: This routine causes the calling process to delay the given number
of milliseconds. Due to the nature of the call, the actual sleep
time is almost guaranteed to be different from requested sleep time.
****************************************************************************/
#ifdef FLM_UNIX
void FLMAPI f_sleep(
FLMUINT uiMilliseconds)
{
#ifdef FLM_AIX
struct timestruc_t timeout;
struct timestruc_t remain;
#else
struct timespec timeout;
#endif
timeout.tv_sec = (uiMilliseconds / 1000);
timeout.tv_nsec = (uiMilliseconds % 1000) * 1000000;
#ifdef FLM_AIX
nsleep(&timeout, &remain);
#else
nanosleep(&timeout, 0);
#endif
}
#endif
/****************************************************************************
Desc:
****************************************************************************/
#ifdef FLM_WIN
void FLMAPI f_sleep(
FLMUINT uiMilliseconds)
{
Sleep( (DWORD)uiMilliseconds);
}
#endif
/****************************************************************************
Desc:
****************************************************************************/
#ifdef FLM_LIBC_NLM
void FLMAPI f_sleep(
FLMUINT uiMilliseconds)
{
if( !uiMilliseconds )
{
pthread_yield();
}
else
{
delay( uiMilliseconds);
}
}
#endif
/****************************************************************************
Desc:
****************************************************************************/
#ifdef FLM_RING_ZERO_NLM
void FLMAPI f_sleep(
FLMUINT uiMilliseconds)
{
if( !uiMilliseconds)
{
kYieldThread();
}
else
{
kDelayThread( uiMilliseconds);
}
}
#endif
/****************************************************************************
Desc:
****************************************************************************/
FSTATIC RCODE f_initRandomGenerator( void)
{
FLMUINT uiTime;
RCODE rc = NE_FLM_OK;
if (++gv_uiRandomGenInitCount > 1)
{
goto Exit;
}
if( RC_BAD( rc = f_mutexCreate( &gv_hRandomGenMutex)))
{
goto Exit;
}
f_timeGetSeconds( &uiTime );
if( RC_BAD( rc = FlmAllocRandomGenerator( &gv_pRandomGenerator)))
{
goto Exit;
}
gv_pRandomGenerator->setSeed( (FLMUINT32)(uiTime ^ (FLMUINT)f_getpid()));
Exit:
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
FSTATIC void f_freeRandomGenerator( void)
{
if( (--gv_uiRandomGenInitCount) > 0)
{
return;
}
if( gv_pRandomGenerator)
{
gv_pRandomGenerator->Release();
gv_pRandomGenerator = NULL;
}
if( gv_hRandomGenMutex != F_MUTEX_NULL)
{
f_mutexDestroy( &gv_hRandomGenMutex);
}
}
/****************************************************************************
Desc: This routine will use the operating system calls to generate a
"globally unique" identifier. Typically, this is based on the
MAC address of an ethernet card installed in the machine. If the
machine does not have an ethernet card, or if the OS does not
support generating GUIDs, this routine will generate a pseudo-GUID
using a random number generator. A serial number is 16-bytes.
****************************************************************************/
RCODE FLMAPI f_createSerialNumber(
FLMBYTE * pszSerialNum)
{
RCODE rc = NE_FLM_OK;
#if defined( FLM_WIN)
UUID uuidVal;
RPC_STATUS err = UuidCreate( &uuidVal);
if (err == RPC_S_OK || err == RPC_S_UUID_LOCAL_ONLY)
{
UD2FBA( (FLMUINT32)uuidVal.Data1, &pszSerialNum[ 0]);
UW2FBA( (FLMUINT16)uuidVal.Data2, &pszSerialNum[ 4]);
UW2FBA( (FLMUINT16)uuidVal.Data3, &pszSerialNum[ 6]);
f_memcpy( &pszSerialNum[ 8], (FLMBYTE *)uuidVal.Data4, 8);
goto Exit;
}
#elif defined( FLM_UNIX) || defined( FLM_NLM)
// Generate a pseudo GUID value
UD2FBA( f_getRandomUINT32(), &pszSerialNum[ 0]);
UD2FBA( f_getRandomUINT32(), &pszSerialNum[ 4]);
UD2FBA( f_getRandomUINT32(), &pszSerialNum[ 8]);
UD2FBA( f_getRandomUINT32(), &pszSerialNum[ 12]);
#endif
#if defined( FLM_WIN)
Exit:
#endif
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
void FLMAPI f_getenv(
const char * pszKey,
FLMBYTE * pszBuffer,
FLMUINT uiBufferSize,
FLMUINT * puiValueLen)
{
FLMUINT uiValueLen = 0;
if( !uiBufferSize)
{
goto Exit;
}
pszBuffer[ 0] = 0;
#if defined( FLM_WIN) || defined( FLM_UNIX)
char * pszValue;
if( (pszValue = getenv( pszKey)) != NULL &&
(uiValueLen = f_strlen( pszValue)) < uiBufferSize)
{
f_strcpy( (char *)pszBuffer, pszValue);
}
#else
F_UNREFERENCED_PARM( pszKey);
#endif
Exit:
if( puiValueLen)
{
*puiValueLen = uiValueLen;
}
return;
}
/***************************************************************************
Desc: Sort an array of items
****************************************************************************/
void FLMAPI f_qsort(
void * pvBuffer,
FLMUINT uiLowerBounds,
FLMUINT uiUpperBounds,
F_SORT_COMPARE_FUNC fnCompare,
F_SORT_SWAP_FUNC fnSwap)
{
FLMUINT uiLBPos;
FLMUINT uiUBPos;
FLMUINT uiMIDPos;
FLMUINT uiCurrentPos;
FLMUINT uiLeftItems;
FLMUINT uiRightItems;
FLMINT iCompare;
Iterate_Larger_Half:
uiUBPos = uiUpperBounds;
uiLBPos = uiLowerBounds;
uiMIDPos = (uiUpperBounds + uiLowerBounds + 1) / 2;
uiCurrentPos = uiMIDPos;
for (;;)
{
while (uiLBPos == uiMIDPos ||
((iCompare =
fnCompare( pvBuffer, uiLBPos, uiCurrentPos)) < 0))
{
if( uiLBPos >= uiUpperBounds)
{
break;
}
uiLBPos++;
}
while( uiUBPos == uiMIDPos ||
(((iCompare =
fnCompare( pvBuffer, uiCurrentPos, uiUBPos)) < 0)))
{
if (!uiUBPos)
{
break;
}
uiUBPos--;
}
if( uiLBPos < uiUBPos)
{
// Exchange [uiLBPos] with [uiUBPos].
fnSwap( pvBuffer, uiLBPos, uiUBPos);
uiLBPos++;
uiUBPos--;
}
else
{
break;
}
}
// Check for swap( LB, MID ) - cases 3 and 4
if( uiLBPos < uiMIDPos )
{
// Exchange [uiLBPos] with [uiMIDPos]
fnSwap( pvBuffer, uiMIDPos, uiLBPos);
uiMIDPos = uiLBPos;
}
else if( uiMIDPos < uiUBPos )
{
// Exchange [uUBPos] with [uiMIDPos]
fnSwap( pvBuffer, uiMIDPos, uiUBPos);
uiMIDPos = uiUBPos;
}
// Check the left piece.
uiLeftItems = (uiLowerBounds + 1 < uiMIDPos)
? uiMIDPos - uiLowerBounds
: 0;
uiRightItems = (uiMIDPos + 1 < uiUpperBounds)
? uiUpperBounds - uiMIDPos
: 0;
if( uiLeftItems < uiRightItems)
{
// Recurse on the LEFT side and goto the top on the RIGHT side.
if( uiLeftItems)
{
f_qsort( pvBuffer, uiLowerBounds, uiMIDPos - 1, fnCompare, fnSwap);
}
uiLowerBounds = uiMIDPos + 1;
goto Iterate_Larger_Half;
}
else if( uiLeftItems)
{
// Recurse on the RIGHT side and goto the top for the LEFT side.
if (uiRightItems )
{
f_qsort( pvBuffer, uiMIDPos + 1, uiUpperBounds, fnCompare, fnSwap);
}
uiUpperBounds = uiMIDPos - 1;
goto Iterate_Larger_Half;
}
}
/***************************************************************************
Desc:
****************************************************************************/
FLMINT FLMAPI f_qsortUINTCompare(
void * pvBuffer,
FLMUINT uiPos1,
FLMUINT uiPos2)
{
FLMUINT uiLeft = *(((FLMUINT *)pvBuffer) + uiPos1);
FLMUINT uiRight = *(((FLMUINT *)pvBuffer) + uiPos2);
if( uiLeft < uiRight)
{
return( -1);
}
else if( uiLeft > uiRight)
{
return( 1);
}
return( 0);
}
/***************************************************************************
Desc:
****************************************************************************/
void FLMAPI f_qsortUINTSwap(
void * pvBuffer,
FLMUINT uiPos1,
FLMUINT uiPos2)
{
FLMUINT * puiArray = (FLMUINT *)pvBuffer;
FLMUINT uiTmp = puiArray[ uiPos1];
puiArray[ uiPos1] = puiArray[ uiPos2];
puiArray[ uiPos2] = uiTmp;
}
/****************************************************************************
Desc:
****************************************************************************/
void * FLMAPI f_memcpy(
void * pvDest,
const void * pvSrc,
FLMSIZET iSize)
{
if( iSize == 1)
{
*((FLMBYTE *)pvDest) = *((FLMBYTE *)pvSrc);
return( pvDest);
}
#ifdef FLM_RING_ZERO_NLM
CMoveFast( pvSrc, pvDest, iSize);
return( pvDest);
#else
return( memcpy( pvDest, pvSrc, iSize));
#endif
}
/****************************************************************************
Desc:
****************************************************************************/
void * FLMAPI f_memmove(
void * pvDest,
const void * pvSrc,
FLMSIZET uiLength)
{
#ifndef FLM_RING_ZERO_NLM
return( memmove( pvDest, pvSrc, uiLength));
#else
#define CMOVB_THRESHOLD 16
char *s = (char *)pvSrc;
char *d = (char *)pvDest;
unsigned uDiff;
if( (char *)(s + uiLength) < d || (char *)(d + uiLength) < s)
{
// The source and destination do not overlap.
CMoveFast( (void *)s, d, (LONG)uiLength);
}
else if( s < d)
{
// Source preceeds the destination, with overlap.
uDiff = (unsigned)(d - s);
d += uiLength;
s += uiLength;
if( uDiff >= CMOVB_THRESHOLD)
{
for( ;;)
{
if( uiLength < uDiff)
{
break;
}
// Copy the tail
s -= uDiff;
d -= uDiff;
uiLength -= uDiff;
CMoveFast( (void *)s, d, (LONG)uDiff);
}
}
// Copy remaining bytes.
while( uiLength--)
{
*--d = *--s;
}
}
else if( s > d)
{
// Source follows the destination, with overlap.
uDiff = (unsigned)(s - d);
if( uDiff >= CMOVB_THRESHOLD)
{
for( ;;)
{
if( uiLength < uDiff)
{
break;
}
// Copy the head
CMoveFast( (void *)s, d, (LONG)uDiff);
uiLength -= uDiff;
d += uDiff;
s += uDiff;
}
}
// Copy the remaining bytes
while( uiLength--)
{
*d++ = *s++;
}
}
// Else, the regions overlap completely (s == d). Do nothing.
return( pvDest);
#endif
}
/****************************************************************************
Desc:
****************************************************************************/
void * FLMAPI f_memset(
void * pvMem,
unsigned char ucByte,
FLMSIZET uiLength)
{
#ifndef FLM_RING_ZERO_NLM
return( memset( pvMem, ucByte, uiLength));
#else
char * cp = (char *)pvMem;
unsigned dwordLength;
unsigned long dwordVal;
dwordVal = ((unsigned long)ucByte << 24) |
((unsigned long)ucByte << 16) |
((unsigned long)ucByte << 8) |
(unsigned long)ucByte;
while( uiLength && ((long)cp & 3L))
{
*cp++ = (char)ucByte;
uiLength--;
}
dwordLength = uiLength >> 2;
if( dwordLength != 0)
{
CSetD( dwordVal, (void *)cp, dwordLength);
cp += (dwordLength << 2);
uiLength -= (dwordLength << 2);
}
while( uiLength)
{
*cp++ = (char)ucByte;
uiLength--;
}
return( pvMem);
#endif
}
/****************************************************************************
Desc:
****************************************************************************/
FLMINT FLMAPI f_memcmp(
const void * pvMem1,
const void * pvMem2,
FLMSIZET uiLength)
{
#ifndef FLM_NLM
return( memcmp( pvMem1, pvMem2, uiLength));
#else
unsigned char * s1;
unsigned char * s2;
for (s1 = (unsigned char *)pvMem1, s2 = (unsigned char *)pvMem2;
uiLength > 0; uiLength--, s1++, s2++)
{
if (*s1 == *s2)
{
continue;
}
else if( *s1 > *s2)
{
return( 1);
}
else
{
return( -1);
}
}
return( 0);
#endif
}
/****************************************************************************
Desc:
****************************************************************************/
char * FLMAPI f_strcpy(
char * pszDest,
const char * pszSrc)
{
#ifndef FLM_NLM
return( strcpy( pszDest, pszSrc));
#else
while ((*pszDest++ = *pszSrc++) != 0);
return( pszDest);
#endif
}
/****************************************************************************
Desc:
****************************************************************************/
char * FLMAPI f_strncpy(
char * pszDest,
const char * pszSrc,
FLMSIZET uiLength)
{
#ifndef FLM_NLM
return( strncpy( pszDest, pszSrc, uiLength));
#else
while( uiLength)
{
*pszDest++ = *pszSrc;
if( *pszSrc)
{
pszSrc++;
}
uiLength--;
}
*pszDest = 0;
return( pszDest);
#endif
}
/****************************************************************************
Desc:
****************************************************************************/
FLMUINT FLMAPI f_strlen(
const char * pszStr)
{
#ifndef FLM_NLM
return( strlen( pszStr));
#else
const char * pszStart = pszStr;
while( *pszStr)
{
pszStr++;
}
return( pszStr - pszStart);
#endif
}
/****************************************************************************
Desc:
****************************************************************************/
FLMINT FLMAPI f_strcmp(
const char * pszStr1,
const char * pszStr2)
{
#ifndef FLM_NLM
return( strcmp( pszStr1, pszStr2));
#else
while( *pszStr1 == *pszStr2 && *pszStr1)
{
pszStr1++;
pszStr2++;
}
return( (FLMINT)(*pszStr1 - *pszStr2));
#endif
}
/****************************************************************************
Desc:
****************************************************************************/
FLMINT FLMAPI f_stricmp(
const char * pszStr1,
const char * pszStr2)
{
#ifdef FLM_WIN
return( _stricmp( pszStr1, pszStr2));
#else
while( f_toupper( *pszStr1) == f_toupper( *pszStr2) && *pszStr1)
{
pszStr1++;
pszStr2++;
}
return( (FLMINT)( f_toupper( *pszStr1) - f_toupper( *pszStr2)));
#endif
}
/****************************************************************************
Desc:
****************************************************************************/
FLMINT FLMAPI f_strncmp(
const char * pszStr1,
const char * pszStr2,
FLMSIZET uiLength)
{
#ifndef FLM_NLM
return( strncmp( pszStr1, pszStr2, uiLength));
#else
while( *pszStr1 == *pszStr2 && *pszStr1 && uiLength)
{
pszStr1++;
pszStr2++;
uiLength--;
}
if( uiLength)
{
return( (*pszStr1 - *pszStr2));
}
return( 0);
#endif
}
/****************************************************************************
Desc:
****************************************************************************/
FLMINT FLMAPI f_strnicmp(
const char * pszStr1,
const char * pszStr2,
FLMSIZET uiLength)
{
#ifdef FLM_WIN
return( _strnicmp( pszStr1, pszStr2, uiLength));
#else
FLMINT iLen = (FLMINT)uiLength;
if( !pszStr1 || !pszStr2)
{
return( (pszStr1 == pszStr2)
? 0
: (pszStr1 ? 1 : -1));
}
while( iLen-- && *pszStr1 && *pszStr2 &&
(f_toupper( *pszStr1) == f_toupper( *pszStr2)))
{
pszStr1++;
pszStr2++;
}
return( (iLen == -1)
? 0
: (f_toupper( *pszStr1) - f_toupper( *pszStr2)));
#endif
}
/****************************************************************************
Desc:
****************************************************************************/
char * FLMAPI f_strcat(
char * pszDest,
const char * pszSrc)
{
#ifndef FLM_NLM
return( strcat( pszDest, pszSrc));
#else
const char * p = pszSrc;
char * q = pszDest;
while (*q++);
q--;
while( (*q++ = *p++) != 0);
return( pszDest);
#endif
}
/****************************************************************************
Desc:
****************************************************************************/
char * FLMAPI f_strncat(
char * pszDest,
const char * pszSrc,
FLMSIZET uiLength)
{
#ifndef FLM_NLM
return( strncat( pszDest, pszSrc, uiLength));
#else
const char * p = pszSrc;
char * q = pszDest;
while (*q++);
q--;
uiLength++;
while( --uiLength)
{
if( (*q++ = *p++) == 0)
{
q--;
break;
}
}
*q = 0;
return( pszDest);
#endif
}
/****************************************************************************
Desc:
****************************************************************************/
char * FLMAPI f_strchr(
const char * pszStr,
unsigned char ucByte)
{
#ifndef FLM_NLM
return( (char *)strchr( pszStr, ucByte));
#else
if( !pszStr)
{
return( NULL);
}
while (*pszStr && *pszStr != ucByte)
{
pszStr++;
}
return( (char *)((*pszStr == ucByte)
? pszStr
: NULL));
#endif
}
/****************************************************************************
Desc:
****************************************************************************/
char * FLMAPI f_strrchr(
const char * pszStr,
unsigned char ucByte)
{
#ifndef FLM_NLM
return( (char *)strrchr( pszStr, ucByte));
#else
const char * pszLast = NULL;
if( !pszStr)
{
return( NULL);
}
while (*pszStr)
{
if( *pszStr == ucByte)
{
pszLast = pszStr;
}
pszStr++;
}
if( ucByte == '\0')
{
pszLast = pszStr;
}
return( (char *)pszLast);
#endif
}
/****************************************************************************
Desc:
****************************************************************************/
char * FLMAPI f_strstr(
const char * pszStr1,
const char * pszStr2)
{
#ifndef FLM_NLM
return( (char *)strstr( pszStr1, pszStr2));
#else
FLMUINT i;
FLMUINT j;
FLMUINT k;
if ( !pszStr1 || !pszStr2)
{
return( NULL);
}
for( i = 0; pszStr1[i] != '\0'; i++)
{
for( j=i, k=0; pszStr2[k] != '\0' &&
pszStr1[j] == pszStr2[k]; j++, k++)
{
;
}
if ( k > 0 && pszStr2[k] == '\0')
{
return( (char *)&pszStr1[i]);
}
}
return( NULL);
#endif
}
/****************************************************************************
Desc: Turn a base 24 digit's ordinal value into a native
alphanumeric value.
Notes: This is a base 24 alphanumeric value where
{a, b, c, d, e, f, i, l, o, r, u, v } values are removed.
****************************************************************************/
FLMBYTE FLMAPI f_getBase24DigitChar(
FLMBYTE ucValue)
{
f_assert( ucValue <= 23);
if( ucValue <= 9)
{
ucValue += NATIVE_ZERO;
}
else
{
ucValue = f_toascii( ucValue) - 10 + f_toascii( 'g');
if( ucValue >= (FLMBYTE)'i')
{
ucValue++;
if( ucValue >= (FLMBYTE)'l')
{
ucValue++;
if( ucValue >= (FLMBYTE)'o')
{
ucValue++;
if( ucValue >= (FLMBYTE)'r')
{
ucValue++;
if( ucValue >= (FLMBYTE)'u')
{
ucValue++;
if( ucValue >= (FLMBYTE)'v')
{
ucValue++;
}
}
}
}
}
}
}
return( ucValue);
}
/****************************************************************************
Desc:
****************************************************************************/
char * FLMAPI f_strupr(
char * pszStr)
{
#ifdef FLM_WIN
return( _strupr( pszStr));
#else
while( *pszStr)
{
*pszStr = f_toupper( *pszStr);
pszStr++;
}
return( pszStr);
#endif
}
/**********************************************************************
Desc:
**********************************************************************/
FLMINT32 FLMAPI f_atomicInc(
FLMATOMIC * piTarget)
{
#if defined( FLM_LIBC_NLM)
{
return( (FLMINT32)atomic_retadd( (unsigned long *)piTarget, 1));
}
#elif defined( FLM_RING_ZERO_NLM)
{
return( nlm_AtomicIncrement( (volatile LONG *)piTarget));
}
#elif defined( FLM_WIN)
{
return( (FLMINT32)InterlockedIncrement( (volatile LONG *)piTarget));
}
#elif defined( FLM_AIX)
{
return( (FLMINT32)aix_atomic_add( piTarget, 1));
}
#elif defined( FLM_OSX)
{
return( (FLMINT32)OSAtomicIncrement32Barrier( (int32_t *)piTarget));
}
#elif defined( FLM_SPARC_PLUS)
{
return( sparc_atomic_add_32( piTarget, 1));
}
#elif (defined( __i386__) || defined( __x86_64__)) && defined( FLM_GNUC)
{
FLMINT32 i32Tmp;
__asm__ __volatile__ (
"lock;"
"xaddl %0, %1"
: "=r" (i32Tmp), "=m" (*piTarget)
: "0" (1), "m" (*piTarget));
return( i32Tmp + 1);
}
#elif defined( FLM_PPC) && defined( FLM_GNUC) && defined( FLM_LINUX)
{
return( ppc_atomic_add( piTarget, 1));
}
#elif defined( FLM_UNIX)
return( posix_atomic_add_32( piTarget, 1));
#else
#error Atomic operations are not supported
#endif
}
/**********************************************************************
Desc:
**********************************************************************/
FLMINT32 FLMAPI f_atomicDec(
FLMATOMIC * piTarget)
{
#if defined( FLM_LIBC_NLM)
{
return( (FLMINT32)atomic_retadd( (unsigned long *)piTarget, -1));
}
#elif defined( FLM_RING_ZERO_NLM)
{
return( nlm_AtomicDecrement( (volatile LONG *)piTarget));
}
#elif defined( FLM_WIN)
{
return( (FLMINT32)InterlockedDecrement( (volatile LONG *)piTarget));
}
#elif defined( FLM_AIX)
{
return( (FLMINT32)aix_atomic_add( piTarget, -1));
}
#elif defined( FLM_OSX)
{
return( (FLMINT32)OSAtomicDecrement32Barrier( (int32_t *)piTarget));
}
#elif defined( FLM_SPARC_PLUS)
{
return( sparc_atomic_add_32( piTarget, -1));
}
#elif (defined( __i386__) || defined( __x86_64__)) && defined( FLM_GNUC)
{
FLMINT32 i32Tmp;
__asm__ __volatile__ (
"lock;"
"xaddl %0, %1"
: "=r" (i32Tmp), "=m" (*piTarget)
: "0" (-1), "m" (*piTarget));
return( i32Tmp - 1);
}
#elif defined( FLM_PPC) && defined( FLM_GNUC) && defined( FLM_LINUX)
{
return( ppc_atomic_add( piTarget, -1));
}
#elif defined( FLM_UNIX)
return( posix_atomic_add_32( piTarget, -1));
#else
#error Atomic operations are not supported
#endif
}
/**********************************************************************
Desc:
**********************************************************************/
FLMINT32 FLMAPI f_atomicExchange(
FLMATOMIC * piTarget,
FLMINT32 i32NewVal)
{
#if defined( FLM_NLM)
{
return( (FLMINT32)atomic_xchg( (unsigned long *)piTarget, i32NewVal));
}
#elif defined( FLM_WIN)
{
return( (FLMINT32)InterlockedExchange( (volatile LONG *)piTarget,
i32NewVal));
}
#elif defined( FLM_AIX)
{
int iOldVal;
for( ;;)
{
iOldVal = (int)*piTarget;
if( compare_and_swap( (int *)piTarget, &iOldVal, i32NewVal))
{
break;
}
}
return( (FLMINT32)iOldVal);
}
#elif defined( FLM_OSX)
{
int32_t iOldVal;
for( ;;)
{
iOldVal = (int32_t)*piTarget;
if( OSAtomicCompareAndSwap32Barrier( iOldVal, i32NewVal,
(int32_t *)piTarget))
{
break;
}
}
return( (FLMINT32)iOldVal);
}
#elif defined( FLM_SPARC_PLUS)
{
return( sparc_atomic_xchg_32( piTarget, i32NewVal));
}
#elif (defined( __i386__) || defined( __x86_64__)) && defined( FLM_GNUC)
{
FLMINT32 i32OldVal;
__asm__ __volatile__ (
"1: lock;"
" cmpxchgl %2, %0;"
" jne 1b"
: "=m" (*piTarget), "=a" (i32OldVal)
: "r" (i32NewVal), "m" (*piTarget), "a" (*piTarget));
return( i32OldVal);
}
#elif defined( FLM_PPC) && defined( FLM_GNUC) && defined( FLM_LINUX)
{
return( ppc_atomic_xchg( piTarget, i32NewVal));
}
#elif defined( FLM_UNIX)
return( posix_atomic_xchg_32( piTarget, i32NewVal));
#else
#error Atomic operations are not supported
#endif
}
/**********************************************************************
Desc:
**********************************************************************/
FLMINT FLMAPI F_Object::getRefCount( void)
{
return( m_refCnt);
}
/**********************************************************************
Desc:
**********************************************************************/
FLMINT FLMAPI F_Object::AddRef( void)
{
return( ++m_refCnt);
}
/**********************************************************************
Desc:
**********************************************************************/
FLMINT FLMAPI F_Object::Release( void)
{
FLMINT iRefCnt = --m_refCnt;
if( !iRefCnt)
{
delete this;
}
return( iRefCnt);
}
/**********************************************************************
Desc:
**********************************************************************/
IF_FileSystem * FLMAPI f_getFileSysPtr( void)
{
return( gv_pFileSystem);
}
/**********************************************************************
Desc:
**********************************************************************/
FLMUINT FLMAPI f_getOpenFileCount( void)
{
return( gv_openFiles);
}
/**********************************************************************
Desc:
**********************************************************************/
IF_ThreadMgr * f_getThreadMgrPtr( void)
{
return( gv_pThreadMgr);
}
/**********************************************************************
Desc:
**********************************************************************/
FLMUINT FLMAPI f_getMaxFileSize( void)
{
return( gv_uiMaxFileSize);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI f_readSEN(
IF_IStream * pIStream,
FLMUINT * puiValue,
FLMUINT * puiLength)
{
RCODE rc;
FLMUINT64 ui64Tmp;
if( RC_BAD( rc = f_readSEN64( pIStream, &ui64Tmp, puiLength)))
{
goto Exit;
}
if( ui64Tmp > ~((FLMUINT)0))
{
rc = RC_SET_AND_ASSERT( NE_FLM_CONV_DEST_OVERFLOW);
goto Exit;
}
if( puiValue)
{
*puiValue = (FLMUINT)ui64Tmp;
}
Exit:
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI f_readSEN64(
IF_IStream * pIStream,
FLMUINT64 * pui64Value,
FLMUINT * puiLength)
{
RCODE rc = NE_FLM_OK;
FLMUINT uiLen;
FLMUINT uiSENLength;
FLMBYTE ucBuffer[ 16];
const FLMBYTE * pucBuffer;
uiLen = 1;
if( RC_BAD( rc = pIStream->read(
(char *)&ucBuffer[ 0], uiLen, &uiLen)))
{
goto Exit;
}
uiSENLength = gv_ucSENLengthArray[ ucBuffer[ 0]];
uiLen = uiSENLength - 1;
if( puiLength)
{
*puiLength = uiSENLength;
}
if( pui64Value)
{
pucBuffer = &ucBuffer[ 1];
}
else
{
pucBuffer = NULL;
}
if( uiLen)
{
if( RC_BAD( rc = pIStream->read(
(char *)pucBuffer, uiLen, &uiLen)))
{
goto Exit;
}
}
if( pui64Value)
{
pucBuffer = &ucBuffer[ 0];
if( RC_BAD( rc = f_decodeSEN64( &pucBuffer,
&ucBuffer[ sizeof( ucBuffer)], pui64Value)))
{
goto Exit;
}
}
Exit:
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
FLMUINT FLMAPI f_getSENLength(
FLMBYTE ucByte)
{
return( gv_ucSENLengthArray[ ucByte]);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE FLMAPI f_decodeSEN64(
const FLMBYTE ** ppucBuffer,
const FLMBYTE * pucEnd,
FLMUINT64 * pui64Value)
{
RCODE rc = NE_FLM_OK;
FLMUINT uiSENLength;
const FLMBYTE * pucBuffer = *ppucBuffer;
uiSENLength = gv_ucSENLengthArray[ *pucBuffer];
if( pucBuffer + uiSENLength > pucEnd)
{
if (pui64Value)
{
*pui64Value = 0;
}
rc = RC_SET( NE_FLM_BAD_SEN);
goto Exit;
}
if (pui64Value)
{
switch( uiSENLength)
{
case 1:
*pui64Value = *pucBuffer;
break;
case 2:
*pui64Value = (((FLMUINT64)(*pucBuffer & 0x3F)) << 8) + pucBuffer[ 1];
break;
case 3:
*pui64Value = (((FLMUINT64)(*pucBuffer & 0x1F)) << 16) +
(((FLMUINT64)pucBuffer[ 1]) << 8) + pucBuffer[ 2];
break;
case 4:
*pui64Value = (((FLMUINT64)(*pucBuffer & 0x0F)) << 24) +
(((FLMUINT64)pucBuffer[ 1]) << 16) +
(((FLMUINT64)pucBuffer[ 2]) << 8) + pucBuffer[ 3];
break;
case 5:
*pui64Value = (((FLMUINT64)(*pucBuffer & 0x07)) << 32) +
(((FLMUINT64)pucBuffer[ 1]) << 24) +
(((FLMUINT64)pucBuffer[ 2]) << 16) +
(((FLMUINT64)pucBuffer[ 3]) << 8) + pucBuffer[ 4];
break;
case 6:
*pui64Value = (((FLMUINT64)(*pucBuffer & 0x03)) << 40) +
(((FLMUINT64)pucBuffer[ 1]) << 32) +
(((FLMUINT64)pucBuffer[ 2]) << 24) +
(((FLMUINT64)pucBuffer[ 3]) << 16) +
(((FLMUINT64)pucBuffer[ 4]) << 8) + pucBuffer[ 5];
break;
case 7:
*pui64Value = (((FLMUINT64)(*pucBuffer & 0x01)) << 48) +
(((FLMUINT64)pucBuffer[ 1]) << 40) +
(((FLMUINT64)pucBuffer[ 2]) << 32) +
(((FLMUINT64)pucBuffer[ 3]) << 24) +
(((FLMUINT64)pucBuffer[ 4]) << 16) +
(((FLMUINT64)pucBuffer[ 5]) << 8) + pucBuffer[ 6];
break;
case 8:
*pui64Value = (((FLMUINT64)pucBuffer[ 1]) << 48) +
(((FLMUINT64)pucBuffer[ 2]) << 40) +
(((FLMUINT64)pucBuffer[ 3]) << 32) +
(((FLMUINT64)pucBuffer[ 4]) << 24) +
(((FLMUINT64)pucBuffer[ 5]) << 16) +
(((FLMUINT64)pucBuffer[ 6]) << 8) + pucBuffer[ 7];
break;
case 9:
*pui64Value = (((FLMUINT64)pucBuffer[ 1]) << 56) +
(((FLMUINT64)pucBuffer[ 2]) << 48) +
(((FLMUINT64)pucBuffer[ 3]) << 40) +
(((FLMUINT64)pucBuffer[ 4]) << 32) +
(((FLMUINT64)pucBuffer[ 5]) << 24) +
(((FLMUINT64)pucBuffer[ 6]) << 16) +
(((FLMUINT64)pucBuffer[ 7]) << 8) + pucBuffer[ 8];
break;
default:
*pui64Value = 0;
f_assert( 0);
break;
}
}
Exit:
*ppucBuffer = pucBuffer + uiSENLength;
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE FLMAPI f_decodeSEN(
const FLMBYTE ** ppucBuffer,
const FLMBYTE * pucEnd,
FLMUINT * puiValue)
{
RCODE rc = NE_FLM_OK;
FLMUINT64 ui64Value;
if( RC_BAD( rc = f_decodeSEN64( ppucBuffer, pucEnd, &ui64Value)))
{
return( rc);
}
if( ui64Value > FLM_MAX_UINT)
{
return( RC_SET_AND_ASSERT( NE_FLM_CONV_NUM_OVERFLOW));
}
if( puiValue)
{
*puiValue = (FLMUINT)ui64Value;
}
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
FINLINE FLMBYTE f_shiftRightRetByte(
FLMUINT64 ui64Num,
FLMBYTE ucBits)
{
return( ucBits < 64 ? (FLMBYTE)(ui64Num >> ucBits) : 0);
}
/****************************************************************************
Desc:
****************************************************************************/
FLMUINT FLMAPI f_getSENByteCount(
FLMUINT64 ui64Num)
{
FLMUINT uiCount = 0;
if( ui64Num < 0x80)
{
return( 1);
}
while( ui64Num)
{
uiCount++;
ui64Num >>= 7;
}
// If the high bit is set, the counter will be incremented 1 beyond
// the actual number of bytes need to represent the SEN. We will need
// to re-visit this if we ever go beyond 64-bits.
return( uiCount < FLM_MAX_SEN_LEN ? uiCount : FLM_MAX_SEN_LEN);
}
/****************************************************************************
Desc: Encodes a number as a SEN
****************************************************************************/
FLMUINT FLMAPI f_encodeSEN(
FLMUINT64 ui64Value,
FLMBYTE ** ppucBuffer,
FLMUINT uiSizeWanted)
{
FLMBYTE * pucBuffer = *ppucBuffer;
FLMUINT uiSenLen = f_getSENByteCount( ui64Value);
f_assert( uiSizeWanted <= FLM_MAX_SEN_LEN &&
(!uiSizeWanted || uiSizeWanted >= uiSenLen));
uiSenLen = uiSizeWanted > uiSenLen ? uiSizeWanted : uiSenLen;
if( uiSenLen == 1)
{
*pucBuffer++ = (FLMBYTE)ui64Value;
}
else
{
FLMUINT uiTmp = (uiSenLen - 1) << 3;
*pucBuffer++ = ucSENPrefixArray[ uiSenLen] +
f_shiftRightRetByte( ui64Value, (FLMBYTE)uiTmp);
while( uiTmp)
{
uiTmp -= 8;
*pucBuffer++ = f_shiftRightRetByte( ui64Value, (FLMBYTE)uiTmp);
}
}
*ppucBuffer = pucBuffer;
return( uiSenLen);
}
/****************************************************************************
Desc: Encodes a number as a SEN
****************************************************************************/
RCODE FLMAPI f_encodeSEN(
FLMUINT64 ui64Value,
FLMBYTE ** ppucBuffer,
FLMBYTE * pucEnd)
{
RCODE rc = NE_FLM_OK;
FLMBYTE * pucBuffer = *ppucBuffer;
FLMUINT uiSenLen = f_getSENByteCount( ui64Value);
if( *ppucBuffer + uiSenLen > pucEnd)
{
rc = RC_SET_AND_ASSERT( NE_FLM_CONV_DEST_OVERFLOW);
goto Exit;
}
if( uiSenLen == 1)
{
*pucBuffer++ = (FLMBYTE)ui64Value;
}
else
{
FLMUINT uiTmp = (uiSenLen - 1) << 3;
*pucBuffer++ = ucSENPrefixArray[ uiSenLen] +
f_shiftRightRetByte( ui64Value, (FLMBYTE)uiTmp);
while( uiTmp)
{
uiTmp -= 8;
*pucBuffer++ = f_shiftRightRetByte( ui64Value, (FLMBYTE)uiTmp);
}
}
*ppucBuffer = pucBuffer;
Exit:
return( rc);
}
/****************************************************************************
Desc: Encodes a number as a SEN
****************************************************************************/
FLMUINT FLMAPI f_encodeSENKnownLength(
FLMUINT64 ui64Value,
FLMUINT uiSenLen,
FLMBYTE ** ppucBuffer)
{
FLMBYTE * pucBuffer = *ppucBuffer;
if( uiSenLen == 1)
{
*pucBuffer++ = (FLMBYTE)ui64Value;
}
else
{
FLMUINT uiTmp = (uiSenLen - 1) << 3;
*pucBuffer++ = ucSENPrefixArray[ uiSenLen] +
f_shiftRightRetByte( ui64Value, (FLMBYTE)uiTmp);
while( uiTmp)
{
uiTmp -= 8;
*pucBuffer++ = f_shiftRightRetByte( ui64Value, (FLMBYTE)uiTmp);
}
}
*ppucBuffer = pucBuffer;
return( uiSenLen);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE FLMAPI FlmGetXMLObject(
IF_XML ** ppXmlObject)
{
*ppXmlObject = gv_pXml;
(*ppXmlObject)->AddRef();
return( NE_FLM_OK);
}
/****************************************************************************
Desc:
****************************************************************************/
IF_XML * f_getXmlObjPtr( void)
{
return( gv_pXml);
}
/****************************************************************************
Desc:
****************************************************************************/
FLMUINT32 FLMAPI f_getRandomUINT32(
FLMUINT32 ui32Low,
FLMUINT32 ui32High)
{
FLMUINT32 ui32Value;
f_mutexLock( gv_hRandomGenMutex);
ui32Value = gv_pRandomGenerator->getUINT32( ui32Low, ui32High);
f_mutexUnlock( gv_hRandomGenMutex);
return( ui32Value);
}
/****************************************************************************
Desc:
****************************************************************************/
FLMBYTE FLMAPI f_getRandomByte( void)
{
FLMBYTE ucValue;
f_mutexLock( gv_hRandomGenMutex);
ucValue = (FLMBYTE)(gv_pRandomGenerator->getUINT32( 0, 0xFF));
f_mutexUnlock( gv_hRandomGenMutex);
return( ucValue);
}
/****************************************************************************
Desc:
****************************************************************************/
void F_ListManager::insertFirst(
FLMUINT uiList,
F_ListItem * pNewFirstItem)
{
F_ListNode * pListNode;
f_assert( uiList < m_uiListNodeCnt);
pNewFirstItem->AddRef();
pListNode = &m_pListNodes[ uiList];
if( !pListNode->pNextItem)
{
pListNode->pPrevItem = pNewFirstItem;
pNewFirstItem->setNextListItem( uiList, NULL);
}
else
{
// Add this new item to the first of the list.
pListNode->pNextItem->setPrevListItem( uiList, pNewFirstItem);
pNewFirstItem->setNextListItem( uiList, pListNode->pNextItem);
}
pListNode->pNextItem = pNewFirstItem;
pNewFirstItem->setPrevListItem( uiList, NULL);
pNewFirstItem->m_bInList = TRUE;
pListNode->uiListCount++;
}
/****************************************************************************
Desc:
****************************************************************************/
void F_ListManager::insertLast(
FLMUINT uiList,
F_ListItem * pNewLastItem)
{
F_ListNode * pListNode;
f_assert( uiList < m_uiListNodeCnt);
pNewLastItem->AddRef();
pListNode = &m_pListNodes[ uiList];
if( !pListNode->pPrevItem)
{
pListNode->pNextItem = pNewLastItem;
pNewLastItem->setPrevListItem( uiList, NULL);
}
else
{
// Add this new item to the end of the list.
pListNode->pPrevItem->setNextListItem( uiList, pNewLastItem);
pNewLastItem->setPrevListItem( uiList, pListNode->pPrevItem);
}
pListNode->pPrevItem = pNewLastItem;
pNewLastItem->setNextListItem( uiList, NULL);
pNewLastItem->m_bInList = TRUE;
pListNode->uiListCount++;
}
/****************************************************************************
Desc:
****************************************************************************/
F_ListItem * F_ListManager::getItem(
FLMUINT uiList,
FLMUINT nth)
{
F_ListNode * pListNode;
F_ListItem * pListItem;
// Check bounds with assert.
f_assert( uiList < m_uiListNodeCnt );
pListNode = &m_pListNodes[ uiList ];
pListItem = pListNode ? pListNode->pNextItem : NULL;
while( nth--)
{
pListItem = pListItem->getNextListItem( uiList);
}
return( pListItem);
}
/****************************************************************************
Desc:
****************************************************************************/
void F_ListManager::removeItem(
FLMUINT uiList,
F_ListItem * pItem)
{
F_ListNode * pMgrListNode;
F_ListItem * pPrevItem;
F_ListItem * pNextItem;
f_assert( uiList < m_uiListNodeCnt);
pMgrListNode = &m_pListNodes[ uiList];
// Get this item's prev and next items
pPrevItem = pItem->getPrevListItem( uiList);
pNextItem = pItem->getNextListItem( uiList);
if( !pPrevItem && !pNextItem && pMgrListNode->pPrevItem != pItem &&
pMgrListNode->pNextItem != pItem)
{
// If the item is not within the list then skip to the end
goto Exit;
}
// Determine if this item is pointed to by the head or tail pointers
// that the list manager maintains
if( pMgrListNode->pPrevItem == pItem)
{
pMgrListNode->pPrevItem = pItem->getPrevListItem( uiList);
}
if( pMgrListNode->pNextItem == pItem)
{
pMgrListNode->pNextItem = pItem->getNextListItem( uiList);
}
// If there is a prev item - change it's next ptr to be items next ptr
if( pPrevItem)
{
pPrevItem->setNextListItem( uiList, pItem->getNextListItem( uiList));
}
// If there is a next item - change it's prev ptr to be items prev ptr
if( pNextItem)
{
pNextItem->setPrevListItem( uiList, pItem->getPrevListItem( uiList));
}
// Clear out this items prev and next links
pItem->setPrevListItem( uiList, NULL);
pItem->setNextListItem( uiList, NULL);
pItem->m_bInList = FALSE;
pItem->Release();
pMgrListNode->uiListCount--;
Exit:
return;
}
/****************************************************************************
Desc:
****************************************************************************/
void F_ListManager::clearList(
FLMUINT uiList)
{
FLMUINT uiListCnt;
F_ListNode * pListNode;
f_assert( (FLM_ALL_LISTS == uiList) || (uiList < m_uiListNodeCnt));
if( uiList == FLM_ALL_LISTS)
{
uiList = 0;
uiListCnt = m_uiListNodeCnt;
pListNode = m_pListNodes;
}
else
{
uiListCnt = 1;
pListNode = &m_pListNodes[ uiList ];
}
for( ; uiListCnt--; pListNode++, uiList++)
{
F_ListItem * pItem;
F_ListItem * pNextItem;
// Go through the list Releasing every list item.
for( pItem = pListNode->pNextItem; pItem; pItem = pNextItem)
{
pNextItem = pItem->getNextListItem( uiList);
removeItem( uiList, pItem);
}
// At this point the ListCount should be at 0.
f_assert( !pListNode->uiListCount);
// Clear the managers head and tail list pointers.
pListNode->pNextItem = pListNode->pPrevItem = NULL;
}
}
/****************************************************************************
Desc:
****************************************************************************/
FLMUINT F_ListManager::getItemCount(
FLMUINT uiList)
{
FLMUINT uiListNodeCnt;
FLMUINT uiCount = 0;
F_ListNode * pListNode;
f_assert( (FLM_ALL_LISTS == uiList) || (uiList < m_uiListNodeCnt));
if( uiList == FLM_ALL_LISTS)
{
uiListNodeCnt = m_uiListNodeCnt;
pListNode = m_pListNodes;
}
else
{
uiListNodeCnt = 1;
pListNode = &m_pListNodes[ uiList];
}
for( ; uiListNodeCnt--; pListNode++)
{
uiCount += pListNode->uiListCount;
}
return( uiCount);
}
/****************************************************************************
Desc:
****************************************************************************/
F_ListItem::~F_ListItem()
{
#ifdef FLM_DEBUG
FLMUINT uiLoop;
F_ListNode * pTmpNd;
f_assert( !m_bInList);
for( uiLoop = 0; uiLoop < m_uiListNodeCnt; uiLoop++)
{
pTmpNd = &m_pListNodes[ uiLoop];
f_assert( !pTmpNd->pPrevItem && !pTmpNd->pNextItem);
}
#endif
}
/****************************************************************************
Desc:
****************************************************************************/
void F_ListItem::setup(
F_ListManager * pListMgr,
F_ListNode * pListNodes,
FLMUINT uiListNodeCnt)
{
f_assert( pListMgr);
f_assert( pListNodes);
f_assert( uiListNodeCnt);
m_pListManager = pListMgr;
m_uiListNodeCnt = uiListNodeCnt;
m_pListNodes = pListNodes;
f_memset( pListNodes, 0, sizeof( F_ListNode) * uiListNodeCnt );
}
/****************************************************************************
Desc:
****************************************************************************/
void F_ListItem::removeFromList(
FLMUINT uiList)
{
f_assert( (uiList < m_uiListNodeCnt) || (uiList == FLM_ALL_LISTS));
if( uiList == FLM_ALL_LISTS)
{
FLMUINT uiListCnt = m_uiListNodeCnt;
F_ListNode * pListNode = m_pListNodes;
uiList = 0;
// Remove this item from all lists
for( ; uiListCnt--; uiList++, pListNode++)
{
m_pListManager->removeItem( uiList, this);
}
}
else
{
// Remove item from a specific list
m_pListManager->removeItem( uiList, this);
}
}
/****************************************************************************
Desc: This routine allocates and initializes a hash table.
****************************************************************************/
RCODE FLMAPI f_allocHashTable(
FLMUINT uiHashTblSize,
F_BUCKET ** ppHashTblRV)
{
RCODE rc = NE_FLM_OK;
F_BUCKET * pHashTbl = NULL;
IF_RandomGenerator * pRandGen = NULL;
FLMUINT uiCnt;
FLMUINT uiRandVal;
FLMUINT uiTempVal;
// Allocate memory for the hash table
if (RC_BAD( rc = f_calloc(
(FLMUINT)(sizeof( F_BUCKET)) * uiHashTblSize, &pHashTbl)))
{
goto Exit;
}
// Set up the random number generator
if( RC_BAD( rc = FlmAllocRandomGenerator( &pRandGen)))
{
goto Exit;
}
pRandGen->setSeed( 1);
for (uiCnt = 0; uiCnt < uiHashTblSize; uiCnt++)
{
pHashTbl [uiCnt].uiHashValue = (FLMBYTE)uiCnt;
pHashTbl [uiCnt].pFirstInBucket = NULL;
}
if( uiHashTblSize <= 256)
{
for( uiCnt = 0; uiCnt < uiHashTblSize - 1; uiCnt++)
{
uiRandVal = (FLMBYTE) pRandGen->getUINT32( (FLMUINT32)uiCnt,
(FLMUINT32)(uiHashTblSize - 1));
if( uiRandVal != uiCnt)
{
uiTempVal = (FLMBYTE)pHashTbl [uiCnt].uiHashValue;
pHashTbl [uiCnt].uiHashValue = pHashTbl [uiRandVal].uiHashValue;
pHashTbl [uiRandVal].uiHashValue = uiTempVal;
}
}
}
Exit:
if( pRandGen)
{
pRandGen->Release();
}
*ppHashTblRV = pHashTbl;
return( rc);
}
/****************************************************************************
Desc: This routine determines the hash bucket for a string.
****************************************************************************/
FLMUINT FLMAPI f_strHashBucket(
char * pszStr,
F_BUCKET * pHashTbl,
FLMUINT uiNumBuckets)
{
FLMUINT uiHashIndex;
if ((uiHashIndex = (FLMUINT)*pszStr) >= uiNumBuckets)
{
uiHashIndex -= uiNumBuckets;
}
while (*pszStr)
{
if ((uiHashIndex = (FLMUINT)((pHashTbl [uiHashIndex].uiHashValue) ^
(FLMUINT)(f_toupper( *pszStr)))) >= uiNumBuckets)
{
uiHashIndex -= uiNumBuckets;
}
pszStr++;
}
return( uiHashIndex);
}
/****************************************************************************
Desc: This routine determines the hash bucket for a binary array of
characters.
****************************************************************************/
FLMUINT FLMAPI f_binHashBucket(
void * pBuf,
FLMUINT uiBufLen,
F_BUCKET * pHashTbl,
FLMUINT uiNumBuckets)
{
FLMUINT uiHashIndex;
FLMBYTE * ptr = (FLMBYTE *)pBuf;
if ((uiHashIndex = (FLMUINT)*ptr) >= uiNumBuckets)
uiHashIndex -= uiNumBuckets;
while (uiBufLen)
{
if ((uiHashIndex =
(FLMUINT)((pHashTbl [uiHashIndex].uiHashValue) ^ (FLMUINT)(*ptr))) >=
uiNumBuckets)
uiHashIndex -= uiNumBuckets;
ptr++;
uiBufLen--;
}
return( uiHashIndex);
}
/****************************************************************************
Desc:
****************************************************************************/
F_HashTable::F_HashTable()
{
m_hMutex = F_MUTEX_NULL;
m_pMRUObject = NULL;
m_pLRUObject = NULL;
m_ppHashTable = NULL;
m_uiBuckets = 0;
m_uiObjects = 0;
m_uiMaxObjects = 0;
}
/****************************************************************************
Desc:
****************************************************************************/
F_HashTable::~F_HashTable()
{
F_HashObject * pCur;
F_HashObject * pNext;
pCur = m_pMRUObject;
while( pCur)
{
pNext = pCur->m_pNextInGlobal;
unlinkObject( pCur);
pCur->Release();
pCur = pNext;
}
f_assert( !m_uiObjects);
f_assert( !m_pMRUObject);
f_assert( !m_pLRUObject);
if( m_ppHashTable)
{
f_free( &m_ppHashTable);
}
if( m_hMutex != F_MUTEX_NULL)
{
f_mutexDestroy( &m_hMutex);
}
}
/****************************************************************************
Desc: Configures the hash table prior to first use
****************************************************************************/
RCODE FLMAPI F_HashTable::setupHashTable(
FLMBOOL bMultithreaded,
FLMUINT uiNumBuckets,
FLMUINT uiMaxObjects)
{
RCODE rc = NE_FLM_OK;
f_assert( uiNumBuckets);
// Create the hash table
if( RC_BAD( rc = f_alloc(
sizeof( F_HashObject *) * uiNumBuckets, &m_ppHashTable)))
{
goto Exit;
}
m_uiObjects = 0;
m_uiMaxObjects = uiMaxObjects;
m_uiBuckets = uiNumBuckets;
f_memset( m_ppHashTable, 0, sizeof( F_HashObject *) * uiNumBuckets);
if( bMultithreaded)
{
// Initialize the mutex
if( RC_BAD( rc = f_mutexCreate( &m_hMutex)))
{
goto Exit;
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Retrieves an object from the hash table with the specified key.
This routine assumes the table's mutex has already been locked.
A reference IS NOT added to the object for the caller.
****************************************************************************/
RCODE F_HashTable::findObject(
const void * pvKey,
FLMUINT uiKeyLen,
F_HashObject ** ppObject)
{
RCODE rc = NE_FLM_OK;
F_HashObject * pObject = NULL;
FLMUINT uiBucket;
FLMUINT32 ui32CRC = 0;
*ppObject = NULL;
// Calculate the hash bucket and mutex offset
uiBucket = getHashBucket( pvKey, uiKeyLen, &ui32CRC);
// Search the bucket for an object with a matching
// key.
pObject = m_ppHashTable[ uiBucket];
while( pObject)
{
if( pObject->getKeyCRC() == ui32CRC)
{
const void * pvTmpKey = pObject->getKey();
FLMUINT uiTmpKeyLen = pObject->getKeyLength();
if( uiTmpKeyLen == uiKeyLen &&
f_memcmp( pvTmpKey, pvKey, uiKeyLen) == 0)
{
break;
}
}
pObject = pObject->m_pNextInBucket;
}
if( !pObject)
{
rc = RC_SET( NE_FLM_NOT_FOUND);
goto Exit;
}
*ppObject = pObject;
Exit:
return( rc);
}
/****************************************************************************
Desc: Adds an object to the hash table
****************************************************************************/
RCODE FLMAPI F_HashTable::addObject(
F_HashObject * pObject,
FLMBOOL bAllowDuplicates)
{
RCODE rc = NE_FLM_OK;
FLMUINT uiBucket;
F_HashObject * pTmp;
const void * pvKey;
FLMUINT uiKeyLen;
FLMUINT32 ui32CRC;
FLMBOOL bMutexLocked = FALSE;
// Calculate and set the objects hash bucket
f_assert( pObject->getHashBucket() == F_INVALID_HASH_BUCKET);
pvKey = pObject->getKey();
uiKeyLen = pObject->getKeyLength();
f_assert( uiKeyLen);
uiBucket = getHashBucket( pvKey, uiKeyLen, &ui32CRC);
pObject->m_ui32KeyCRC = ui32CRC;
// Lock the mutex
if( m_hMutex != F_MUTEX_NULL)
{
f_mutexLock( m_hMutex);
bMutexLocked = TRUE;
}
// Make sure the object doesn't already exist
if( !bAllowDuplicates)
{
if( RC_BAD( rc = findObject( pvKey, uiKeyLen, &pTmp)))
{
if( rc != NE_FLM_NOT_FOUND)
{
goto Exit;
}
rc = NE_FLM_OK;
}
else
{
rc = RC_SET_AND_ASSERT( NE_FLM_EXISTS);
goto Exit;
}
}
// Add a reference to the object
pObject->AddRef();
// Link the object into the appropriate lists
linkObject( pObject, uiBucket);
// Make sure the maximum number of objects hasn't been exceeded
if( m_uiMaxObjects)
{
while( m_uiObjects > m_uiMaxObjects)
{
if( (pTmp = m_pLRUObject) == NULL)
{
break;
}
unlinkObject( pTmp);
}
}
Exit:
if( bMutexLocked)
{
f_mutexUnlock( m_hMutex);
}
return( rc);
}
/****************************************************************************
Desc: Returns the next object in the linked list of objects in the hash
table. If *ppObject == NULL, the first object will be returned.
****************************************************************************/
RCODE FLMAPI F_HashTable::getNextObjectInGlobal(
F_HashObject ** ppObject)
{
RCODE rc = NE_FLM_OK;
FLMBOOL bMutexLocked = FALSE;
F_HashObject * pOldObj;
// Lock the mutex
if( m_hMutex != F_MUTEX_NULL)
{
f_mutexLock( m_hMutex);
bMutexLocked = TRUE;
}
if( !(*ppObject))
{
*ppObject = m_pMRUObject;
}
else
{
pOldObj = *ppObject;
*ppObject = (*ppObject)->m_pNextInGlobal;
pOldObj->Release();
}
if( *ppObject == NULL)
{
rc = RC_SET( NE_FLM_EOF_HIT);
goto Exit;
}
(*ppObject)->AddRef();
Exit:
if( bMutexLocked)
{
f_mutexUnlock( m_hMutex);
}
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE FLMAPI F_HashTable::getNextObjectInBucket(
F_HashObject ** ppObject)
{
RCODE rc = NE_FLM_OK;
FLMBOOL bMutexLocked = FALSE;
F_HashObject * pOldObj;
if( m_hMutex != F_MUTEX_NULL)
{
f_mutexLock( m_hMutex);
bMutexLocked = TRUE;
}
if( !(*ppObject))
{
rc = RC_SET( NE_FLM_EOF_HIT);
goto Exit;
}
pOldObj = *ppObject;
*ppObject = (*ppObject)->m_pNextInBucket;
pOldObj->Release();
if( *ppObject == NULL)
{
rc = RC_SET( NE_FLM_EOF_HIT);
goto Exit;
}
(*ppObject)->AddRef();
Exit:
if( bMutexLocked)
{
f_mutexUnlock( m_hMutex);
}
return( rc);
}
/****************************************************************************
Desc: Retrieves an object from the hash table with the specified key
****************************************************************************/
RCODE FLMAPI F_HashTable::getObject(
const void * pvKey,
FLMUINT uiKeyLen,
F_HashObject ** ppObject,
FLMBOOL bRemove)
{
RCODE rc = NE_FLM_OK;
F_HashObject * pObject;
FLMBOOL bMutexLocked = FALSE;
// Lock the mutex
if( m_hMutex != F_MUTEX_NULL)
{
f_mutexLock( m_hMutex);
bMutexLocked = TRUE;
}
// Search for an object with a matching key.
if( RC_BAD( rc = findObject( pvKey, uiKeyLen, &pObject)))
{
goto Exit;
}
if( pObject && bRemove)
{
unlinkObject( pObject);
if( !ppObject)
{
pObject->Release();
pObject = NULL;
}
}
if( ppObject)
{
if( !bRemove)
{
pObject->AddRef();
}
*ppObject = pObject;
pObject = NULL;
}
Exit:
if( bMutexLocked)
{
f_mutexUnlock( m_hMutex);
}
return( rc);
}
/****************************************************************************
Desc: Removes an object from the hash table by key
****************************************************************************/
RCODE FLMAPI F_HashTable::removeObject(
void * pvKey,
FLMUINT uiKeyLen)
{
return( getObject( pvKey, uiKeyLen, NULL, TRUE));
}
/****************************************************************************
Desc: Removes an object from the hash table by object pointer
****************************************************************************/
RCODE FLMAPI F_HashTable::removeObject(
F_HashObject * pObject)
{
const void * pvKey = pObject->getKey();
FLMUINT uiKeyLen = pObject->getKeyLength();
return( getObject( pvKey, uiKeyLen, NULL, TRUE));
}
/****************************************************************************
Desc:
****************************************************************************/
void FLMAPI F_HashTable::removeAllObjects( void)
{
F_HashObject * pCur;
FLMBOOL bMutexLocked = FALSE;
for( ;;)
{
if( m_hMutex != F_MUTEX_NULL)
{
f_mutexLock( m_hMutex);
bMutexLocked = TRUE;
}
if( (pCur = m_pMRUObject) == NULL)
{
break;
}
unlinkObject( pCur);
if( bMutexLocked)
{
f_mutexUnlock( m_hMutex);
bMutexLocked = FALSE;
}
pCur->Release();
}
f_assert( !m_pMRUObject);
f_assert( !m_pLRUObject);
if( bMutexLocked)
{
f_mutexUnlock( m_hMutex);
}
}
/****************************************************************************
Desc:
****************************************************************************/
void FLMAPI F_HashTable::removeAgedObjects(
FLMUINT uiMaxAge)
{
F_HashObject * pCur;
FLMBOOL bMutexLocked = FALSE;
FLMUINT uiCurrentTime = FLM_GET_TIMER();
for( ;;)
{
if( m_hMutex != F_MUTEX_NULL)
{
f_mutexLock( m_hMutex);
bMutexLocked = TRUE;
}
if( (pCur = m_pLRUObject) == NULL)
{
break;
}
if( FLM_TIMER_UNITS_TO_SECS(
FLM_ELAPSED_TIME( uiCurrentTime, pCur->m_uiTimeAdded)) < uiMaxAge)
{
break;
}
unlinkObject( pCur);
if( bMutexLocked)
{
f_mutexUnlock( m_hMutex);
bMutexLocked = FALSE;
}
pCur->Release();
}
if( bMutexLocked)
{
f_mutexUnlock( m_hMutex);
}
}
/****************************************************************************
Desc:
****************************************************************************/
FLMUINT FLMAPI F_HashTable::getMaxObjects( void)
{
FLMUINT uiMaxObjects;
if( m_hMutex != F_MUTEX_NULL)
{
f_mutexLock( m_hMutex);
}
uiMaxObjects = m_uiMaxObjects;
if( m_hMutex != F_MUTEX_NULL)
{
f_mutexUnlock( m_hMutex);
}
return( m_uiMaxObjects);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE FLMAPI F_HashTable::setMaxObjects(
FLMUINT uiMaxObjects)
{
F_HashObject * pCur;
FLMBOOL bMutexLocked = FALSE;
if( m_hMutex != F_MUTEX_NULL)
{
f_mutexLock( m_hMutex);
bMutexLocked = TRUE;
}
m_uiMaxObjects = uiMaxObjects;
while( m_uiObjects > m_uiMaxObjects)
{
if( !bMutexLocked && m_hMutex != F_MUTEX_NULL)
{
f_mutexLock( m_hMutex);
bMutexLocked = TRUE;
}
if( (pCur = m_pLRUObject) == NULL)
{
break;
}
unlinkObject( pCur);
if( bMutexLocked)
{
f_mutexUnlock( m_hMutex);
bMutexLocked = FALSE;
}
pCur->Release();
}
if( bMutexLocked)
{
f_mutexUnlock( m_hMutex);
}
return( NE_FLM_OK);
}
/****************************************************************************
Desc: Calculates the hash bucket of a key and optionally returns the key's
CRC.
****************************************************************************/
FLMUINT F_HashTable::getHashBucket(
const void * pvKey,
FLMUINT uiLen,
FLMUINT32 * pui32KeyCRC)
{
FLMUINT32 ui32CRC = 0;
f_updateCRC( (FLMBYTE *)pvKey, uiLen, &ui32CRC);
if( pui32KeyCRC)
{
*pui32KeyCRC = ui32CRC;
}
return( ui32CRC % m_uiBuckets);
}
/****************************************************************************
Desc: Links an object to the global list and also to its bucket
Notes: This routine assumes that the bucket's mutex is already locked
if the hash table is multi-threaded.
****************************************************************************/
void F_HashTable::linkObject(
F_HashObject * pObject,
FLMUINT uiBucket)
{
f_assert( uiBucket < m_uiBuckets);
f_assert( pObject->getHashBucket() == F_INVALID_HASH_BUCKET);
// Set the object's bucket
pObject->setHashBucket( uiBucket);
// Link the object to its hash bucket
pObject->m_pNextInBucket = m_ppHashTable[ uiBucket];
if( m_ppHashTable[ uiBucket])
{
m_ppHashTable[ uiBucket]->m_pPrevInBucket = pObject;
}
m_ppHashTable[ uiBucket] = pObject;
// Link to the global list
if( (pObject->m_pNextInGlobal = m_pMRUObject) != NULL)
{
m_pMRUObject->m_pPrevInGlobal = pObject;
}
else
{
m_pLRUObject = pObject;
}
pObject->m_uiTimeAdded = FLM_GET_TIMER();
m_pMRUObject = pObject;
m_uiObjects++;
}
/****************************************************************************
Desc: Unlinks an object from its bucket and the global list.
Notes: This routine assumes that the bucket's mutex is already locked
if the hash table is multi-threaded.
****************************************************************************/
void F_HashTable::unlinkObject(
F_HashObject * pObject)
{
FLMUINT uiBucket = pObject->getHashBucket();
// Is the bucket valid?
f_assert( uiBucket < m_uiBuckets);
// Unlink from the hash bucket
if( pObject->m_pNextInBucket)
{
pObject->m_pNextInBucket->m_pPrevInBucket = pObject->m_pPrevInBucket;
}
if( pObject->m_pPrevInBucket)
{
pObject->m_pPrevInBucket->m_pNextInBucket = pObject->m_pNextInBucket;
}
else
{
m_ppHashTable[ uiBucket] = pObject->m_pNextInBucket;
}
pObject->m_pPrevInBucket = NULL;
pObject->m_pNextInBucket = NULL;
pObject->setHashBucket( F_INVALID_HASH_BUCKET);
// Unlink from the global list
if( pObject->m_pNextInGlobal)
{
pObject->m_pNextInGlobal->m_pPrevInGlobal = pObject->m_pPrevInGlobal;
}
else
{
m_pLRUObject = pObject->m_pPrevInGlobal;
}
if( pObject->m_pPrevInGlobal)
{
pObject->m_pPrevInGlobal->m_pNextInGlobal = pObject->m_pNextInGlobal;
}
else
{
m_pMRUObject = pObject->m_pNextInGlobal;
}
pObject->m_pPrevInGlobal = NULL;
pObject->m_pNextInGlobal = NULL;
pObject->m_uiTimeAdded = 0;
f_assert( m_uiObjects);
m_uiObjects--;
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE f_initFileAsyncClientList( void)
{
RCODE rc = NE_FLM_OK;
if( RC_BAD( rc = f_mutexCreate( &F_FileHdl::m_hAsyncListMutex)))
{
goto Exit;
}
F_FileHdl::m_pFirstAvailAsync = NULL;
F_FileHdl::m_uiAvailAsyncCount = 0;
Exit:
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
void f_freeFileAsyncClientList( void)
{
F_FileAsyncClient * pAsyncClient;
while( F_FileHdl::m_pFirstAvailAsync)
{
pAsyncClient = F_FileHdl::m_pFirstAvailAsync;
F_FileHdl::m_pFirstAvailAsync = F_FileHdl::m_pFirstAvailAsync->m_pNext;
pAsyncClient->m_pNext = NULL;
delete pAsyncClient;
}
if( F_FileHdl::m_hAsyncListMutex != F_MUTEX_NULL)
{
f_mutexDestroy( &F_FileHdl::m_hAsyncListMutex);
}
F_FileHdl::m_uiAvailAsyncCount = 0;
}