904 lines
19 KiB
C++
904 lines
19 KiB
C++
/****************************************************************************
|
||
*
|
||
*
|
||
* INTEL Corporation Prorietary Information
|
||
*
|
||
* This listing is supplied under the terms of a license agreement
|
||
* with INTEL Corporation and may not be copied nor disclosed except
|
||
* in accordance with the terms of that agreement.
|
||
*
|
||
* Copyright (c) 1996 Intel Corporation.
|
||
*
|
||
*
|
||
* Abstract:
|
||
*
|
||
* Notes:
|
||
*
|
||
***************************************************************************/
|
||
|
||
#ifndef __TSTABLE_H
|
||
#define __TSTABLE_H
|
||
|
||
typedef struct _LOCK_ENTRY
|
||
{
|
||
HANDLE hLock;
|
||
int iLockCount;
|
||
BOOL bCleanup,
|
||
bDeleted;
|
||
WORD wNextFree,
|
||
wUniqueID;
|
||
|
||
} LOCK_ENTRY, *PLOCK_ENTRY;
|
||
|
||
|
||
// definition of an invalid ID
|
||
#define TSTABLE_INVALID_ID (DWORD) 0xFFFFFFFF
|
||
|
||
// return codes that the callback function used in conjunction with EnumerateEntries can return
|
||
const DWORD CALLBACK_CONTINUE = 1;
|
||
const DWORD CALLBACK_ABORT = 2;
|
||
const DWORD CALLBACK_DELETE_ENTRY = 3;
|
||
const DWORD CALLBACK_DELETE_ENTRY_AND_OBJECT = 4;
|
||
|
||
|
||
|
||
// used in call to Lock
|
||
#define TSTABLE_INVALID_UNIQUE_ID (WORD) 0xFFFF
|
||
#define TSTABLE_INVALID_INDEX (WORD) 0xFFFF
|
||
|
||
// This is a compare function that we aren't using right now. It
|
||
// will be useful in the future if there is a reason to search
|
||
// the table
|
||
|
||
typedef INT (*ENTRY_COMPARE) (LPVOID ptr1, LPVOID ptr2);
|
||
|
||
|
||
template <class EntryData> class TSTable
|
||
{
|
||
typedef DWORD (*TABLE_CALLBACK) (EntryData* ptr, LPVOID context);
|
||
|
||
public:
|
||
TSTable (WORD _size);
|
||
~TSTable ();
|
||
BOOL Resize (WORD wNewSize);
|
||
BOOL CreateAndLock (EntryData* pEntryData,
|
||
LPDWORD lpdwID);
|
||
BOOL Validate (DWORD_PTR dwID);
|
||
EntryData *Lock (DWORD_PTR dwID,
|
||
DWORD timeout = INFINITE);
|
||
BOOL Unlock (DWORD_PTR dwID);
|
||
BOOL Delete (DWORD_PTR dwID,
|
||
BOOL bCleanup = FALSE);
|
||
EntryData *EnumerateEntries(TABLE_CALLBACK callBackFunc,
|
||
void* context,
|
||
BOOL bUnlockTable = FALSE);
|
||
|
||
BOOL IsInitialized () {return bInitialized;}
|
||
WORD GetSize () {return wNumUsed;}
|
||
|
||
private:
|
||
// data
|
||
|
||
EntryData** pDataTable;
|
||
PLOCK_ENTRY pLockTable;
|
||
CRITICAL_SECTION csTableLock;
|
||
WORD wSize,
|
||
wNumUsed,
|
||
wFirstFree,
|
||
wLastFree,
|
||
wUniqueID;
|
||
BOOL bInitialized;
|
||
|
||
// private methods
|
||
|
||
BOOL LockEntry (WORD wIndex,
|
||
DWORD timeout = INFINITE);
|
||
BOOL UnLockEntry(WORD wIndex);
|
||
void LockTable () { EnterCriticalSection(&csTableLock); };
|
||
void UnLockTable() { LeaveCriticalSection(&csTableLock); };
|
||
WORD GenerateUniqueID();
|
||
DWORD MakeID(WORD wIndex, WORD wUniqueID)
|
||
{
|
||
DWORD theID = wUniqueID;
|
||
theID = (theID << 16) & 0xFFFF0000;
|
||
theID |= wIndex;
|
||
return(theID);
|
||
};
|
||
void BreakID(DWORD_PTR theID, WORD* pwIndex, WORD* pwUID)
|
||
{
|
||
*pwIndex = (WORD) (theID & 0x0000FFFF);
|
||
*pwUID = (WORD) ((theID >> 16) & 0x0000FFFF);
|
||
};
|
||
|
||
};
|
||
|
||
/*
|
||
** TSTable::TSTable
|
||
*
|
||
* FILENAME: c:\msdev\projects\firewalls\inc\tstable.h
|
||
*
|
||
* PARAMETERS:
|
||
*
|
||
* DESCRIPTION:
|
||
*
|
||
* RETURNS:
|
||
*
|
||
*/
|
||
|
||
template <class EntryData>
|
||
TSTable<EntryData>::TSTable(WORD _size) :
|
||
wSize(_size),
|
||
wNumUsed((WORD) 0),
|
||
wFirstFree((WORD) 0),
|
||
wLastFree((WORD) (_size - 1)),
|
||
wUniqueID((WORD) 0),
|
||
bInitialized(TRUE),
|
||
pDataTable(NULL),
|
||
pLockTable(NULL)
|
||
{
|
||
WORD wIndex;
|
||
|
||
// Create the table lock
|
||
|
||
InitializeCriticalSection(&csTableLock);
|
||
|
||
// Lock the table
|
||
|
||
LockTable();
|
||
|
||
// Create the data table
|
||
|
||
pDataTable = new EntryData*[wSize];
|
||
|
||
if(pDataTable == NULL)
|
||
{
|
||
bInitialized = FALSE;
|
||
return;
|
||
}
|
||
|
||
// Init the pointers
|
||
|
||
for (wIndex = 0; wIndex < wSize; wIndex++)
|
||
{
|
||
pDataTable[wIndex] = NULL;
|
||
}
|
||
|
||
// Create the lock table
|
||
|
||
pLockTable = new LOCK_ENTRY[wSize];
|
||
|
||
if (pLockTable == NULL)
|
||
{
|
||
bInitialized = FALSE;
|
||
return;
|
||
}
|
||
|
||
// Initialize the lock table entries...each entry begins with
|
||
// a NULL mutex handle, a zero lock count and it's next free is
|
||
// the next successive entry.
|
||
|
||
for (wIndex = 0; wIndex < wSize; wIndex++ )
|
||
{
|
||
pLockTable[wIndex].hLock = NULL;
|
||
pLockTable[wIndex].iLockCount = 0;
|
||
pLockTable[wIndex].wNextFree = (WORD) (wIndex + 1);
|
||
}
|
||
|
||
// note: the wNextFree in the last table entry points to an invalid index, however,
|
||
// this is OK since if the table ever fills, it is automatically resized making what
|
||
// was an invalid index, the index into the first entry of newly added part of the
|
||
// enlargened table. Trust me...
|
||
|
||
// Unlock the table
|
||
|
||
UnLockTable();
|
||
}
|
||
|
||
/*
|
||
** TSTable::~TSTable
|
||
*
|
||
* FILENAME: c:\msdev\projects\firewalls\inc\table.h
|
||
*
|
||
* PARAMETERS:
|
||
*
|
||
* DESCRIPTION:
|
||
*
|
||
* RETURNS:
|
||
*
|
||
*/
|
||
|
||
template <class EntryData>
|
||
TSTable<EntryData>::~TSTable()
|
||
{
|
||
DWORD wIndex;
|
||
|
||
// Lock the table
|
||
|
||
LockTable();
|
||
|
||
// Delete the data table
|
||
|
||
if (pDataTable != NULL)
|
||
{
|
||
delete pDataTable;
|
||
}
|
||
|
||
// Delete the lock table
|
||
|
||
if (pLockTable != NULL)
|
||
{
|
||
// Destroy the mutexes
|
||
|
||
for (wIndex = 0; wIndex < wSize; wIndex++)
|
||
{
|
||
if (pLockTable[wIndex].hLock != NULL)
|
||
{
|
||
CloseHandle(pLockTable[wIndex].hLock);
|
||
}
|
||
}
|
||
|
||
delete pLockTable;
|
||
}
|
||
|
||
// Unlock the table
|
||
|
||
UnLockTable();
|
||
|
||
// Destroy the table lock
|
||
|
||
DeleteCriticalSection(&csTableLock);
|
||
|
||
bInitialized = FALSE;
|
||
}
|
||
|
||
/*
|
||
** TSTable::CreateAndLock
|
||
*
|
||
* FILENAME: c:\msdev\projects\firewalls\inc\table.h
|
||
*
|
||
* PARAMETERS:
|
||
*
|
||
* DESCRIPTION:
|
||
*
|
||
* RETURNS:
|
||
*
|
||
*/
|
||
|
||
template <class EntryData>
|
||
BOOL TSTable<EntryData>::CreateAndLock(EntryData* pEntryData,
|
||
LPDWORD lpdwID)
|
||
{
|
||
BOOL bRetCode = FALSE;
|
||
WORD wIndex;
|
||
|
||
// If the pointer passed in is bad, then don't even try to do anything for them
|
||
|
||
if (pEntryData == NULL || lpdwID == NULL)
|
||
{
|
||
goto EXIT;
|
||
}
|
||
|
||
// Lock the table
|
||
|
||
LockTable();
|
||
|
||
// If the table is full, then resize it.
|
||
|
||
if (wNumUsed >= wSize - 1)
|
||
{
|
||
goto EXIT;
|
||
}
|
||
|
||
// Get the first free entry
|
||
|
||
wIndex = wFirstFree;
|
||
|
||
// Create the mutex for the object
|
||
|
||
if ((pLockTable[wIndex].hLock = CreateMutexA(NULL, FALSE, NULL)) == NULL)
|
||
{
|
||
goto EXIT;
|
||
}
|
||
|
||
// Lock the entry (no need checking the return code as the entire
|
||
// table is locked) - since this is a new entry, that means that nobody
|
||
// could have locked the entry already.
|
||
|
||
LockEntry(wIndex, 0);
|
||
|
||
// Copy pointer to the data table
|
||
|
||
pDataTable[wIndex] = pEntryData;
|
||
|
||
// Init the corresponding lock table entry
|
||
|
||
pLockTable[wIndex].bDeleted = FALSE;
|
||
pLockTable[wIndex].iLockCount = 1;
|
||
pLockTable[wIndex].wUniqueID = GenerateUniqueID();
|
||
|
||
// Set the id for the caller
|
||
|
||
*lpdwID = MakeID(wIndex, pLockTable[wIndex].wUniqueID);
|
||
|
||
// Bump up the count of number used
|
||
|
||
wNumUsed++;
|
||
|
||
// Fix the next free index
|
||
|
||
wFirstFree = pLockTable[wIndex].wNextFree;
|
||
|
||
// Signal success
|
||
|
||
bRetCode = TRUE;
|
||
|
||
EXIT:
|
||
|
||
// Unlock the table
|
||
|
||
UnLockTable();
|
||
return bRetCode;
|
||
}
|
||
|
||
/*
|
||
** TSTable::Lock
|
||
*
|
||
* FILENAME: c:\msdev\projects\firewalls\inc\table.h
|
||
*
|
||
* PARAMETERS:
|
||
*
|
||
* DESCRIPTION:
|
||
*
|
||
* RETURNS:
|
||
*
|
||
*/
|
||
|
||
template <class EntryData>
|
||
EntryData* TSTable<EntryData>::Lock(DWORD_PTR dwID,
|
||
DWORD timeout)
|
||
{
|
||
EntryData* pEntryData = NULL;
|
||
|
||
WORD wIndex,
|
||
wUID;
|
||
|
||
BreakID(dwID, &wIndex, &wUID);
|
||
|
||
// Lock the table
|
||
|
||
LockTable();
|
||
|
||
// Verify the index is within bounds
|
||
|
||
if (wIndex >= wSize)
|
||
{
|
||
goto EXIT;
|
||
}
|
||
|
||
// Verify that the entry is actually valid (ie the lock in non-NULL,
|
||
// the object status is valid, and the unique ID matches).
|
||
|
||
if (pLockTable[wIndex].hLock == NULL ||
|
||
pLockTable[wIndex].bDeleted == TRUE ||
|
||
pLockTable[wIndex].wUniqueID != wUID)
|
||
{
|
||
goto EXIT;
|
||
}
|
||
|
||
// If the timeout is INFINITE, then try to lock the entry using a more
|
||
// "thread friendly" method. If a timeout is specified, then don't do
|
||
// the spin lock since it could be implemented at a higher level.
|
||
|
||
if(timeout == INFINITE)
|
||
{
|
||
// simulate infinity with a pseudo "spin lock"
|
||
// This is more "thread friendly" in that it unlocks the table allowing some
|
||
// other thread that is trying to unlock the same entry to be able to lock the
|
||
// table.
|
||
|
||
while(LockEntry(wIndex, 0) == FALSE)
|
||
{
|
||
UnLockTable();
|
||
|
||
// give up the rest of this thread quantum, allowing others to run and potentially
|
||
// unlock the entry
|
||
|
||
Sleep(0);
|
||
LockTable();
|
||
|
||
// If the entry has been replaced, deleted or marked for deletion then
|
||
// bag it (give up)
|
||
|
||
if((pLockTable[wIndex].wUniqueID != wUID) ||
|
||
(pLockTable[wIndex].hLock == NULL) ||
|
||
(pLockTable[wIndex].bDeleted == TRUE))
|
||
{
|
||
goto EXIT;
|
||
}
|
||
}
|
||
|
||
// we got the lock
|
||
|
||
pEntryData = pDataTable[wIndex];
|
||
}
|
||
|
||
// Otherwise, do a normal lock
|
||
|
||
else
|
||
{
|
||
if (LockEntry(wIndex, timeout) == TRUE)
|
||
{
|
||
pEntryData = pDataTable[wIndex];
|
||
}
|
||
}
|
||
|
||
EXIT:
|
||
|
||
// Unlock the table
|
||
|
||
UnLockTable();
|
||
|
||
return pEntryData;
|
||
}
|
||
|
||
/*
|
||
** TSTable::Unlock
|
||
*
|
||
* FILENAME: c:\msdev\projects\firewalls\inc\table.h
|
||
*
|
||
* PARAMETERS:
|
||
*
|
||
* DESCRIPTION:
|
||
*
|
||
* RETURNS:
|
||
*
|
||
*/
|
||
|
||
template <class EntryData>
|
||
BOOL TSTable<EntryData>::Unlock(DWORD_PTR dwID)
|
||
{
|
||
BOOL bRetCode = TRUE;
|
||
|
||
WORD wIndex,
|
||
wUID;
|
||
|
||
BreakID(dwID, &wIndex, &wUID);
|
||
|
||
// Lock the table
|
||
|
||
LockTable();
|
||
|
||
// Verify the id is within bounds
|
||
|
||
if (wIndex >= wSize)
|
||
{
|
||
bRetCode = FALSE;
|
||
goto EXIT;
|
||
}
|
||
|
||
// verify that the UID matches
|
||
if (pLockTable[wIndex].wUniqueID != wUID)
|
||
{
|
||
bRetCode = FALSE;
|
||
goto EXIT;
|
||
}
|
||
|
||
// Verify that the lock is actually valid and that the entry has not been
|
||
// deleted
|
||
|
||
if (pLockTable[wIndex].hLock == NULL)
|
||
{
|
||
goto EXIT;
|
||
}
|
||
|
||
// Make sure that that thread has the lock on the entry
|
||
|
||
if ((bRetCode = LockEntry(wIndex, 0)) == TRUE)
|
||
{
|
||
// if this table entry is marked for delete and the lock count is less than 2
|
||
// (since the thread could have called delete after unlocking the entry...although
|
||
// this is a no-no) then clean up the table entry
|
||
|
||
if (pLockTable[wIndex].bDeleted == TRUE &&
|
||
pLockTable[wIndex].iLockCount <= 2)
|
||
{
|
||
// If the caller specifed cleanup on delete, then get rid of memory
|
||
|
||
if (pLockTable[wIndex].bCleanup == TRUE)
|
||
{
|
||
delete pDataTable[wIndex];
|
||
}
|
||
|
||
// Set the pointer to NULL
|
||
|
||
pDataTable[wIndex] = NULL;
|
||
|
||
// Decrement the count of used entries
|
||
|
||
wNumUsed--;
|
||
|
||
// Fix the entry so that it's next free index is what is currently
|
||
// the next free pointed to by the current last free entry.
|
||
// Then update the last free entry's next pointer, and finally,
|
||
// update the last free index to this entry
|
||
pLockTable[wIndex].wNextFree = pLockTable[wLastFree].wNextFree;
|
||
pLockTable[wLastFree].wNextFree = wIndex;
|
||
wLastFree = wIndex;
|
||
}
|
||
|
||
// Do two unlocks on the entry ... one for the original lock and another for
|
||
// the lock we obtained during the test
|
||
|
||
UnLockEntry(wIndex);
|
||
UnLockEntry(wIndex);
|
||
|
||
// Since the entire table is locked, then we can get away with this. If
|
||
// the code is ever changed so that the entire table is not locked during
|
||
// these operations, then this will cause a race condition.
|
||
|
||
// If we got rid of the data, then close the handle to the mutex and
|
||
// set the handle to NULL
|
||
|
||
if (pDataTable[wIndex] == NULL)
|
||
{
|
||
CloseHandle(pLockTable[wIndex].hLock);
|
||
pLockTable[wIndex].hLock = NULL;
|
||
}
|
||
}
|
||
|
||
EXIT:
|
||
|
||
// Unlock the table
|
||
|
||
UnLockTable();
|
||
|
||
return bRetCode;
|
||
}
|
||
|
||
/*
|
||
** TSTable::Delete
|
||
*
|
||
* FILENAME: c:\msdev\projects\firewalls\inc\table.h
|
||
*
|
||
* PARAMETERS:
|
||
*
|
||
* DESCRIPTION:
|
||
*
|
||
* RETURNS:
|
||
*
|
||
*/
|
||
|
||
template <class EntryData>
|
||
BOOL TSTable<EntryData>::Delete(DWORD_PTR dwID,
|
||
BOOL bCleanup)
|
||
{
|
||
BOOL bRetCode = TRUE;
|
||
|
||
WORD wIndex,
|
||
wUID;
|
||
|
||
BreakID(dwID, &wIndex, &wUID);
|
||
|
||
// Lock the table
|
||
|
||
LockTable();
|
||
|
||
// Verify that the ID is within bounds
|
||
|
||
if (wIndex >= wSize)
|
||
{
|
||
bRetCode = FALSE;
|
||
goto EXIT;
|
||
}
|
||
|
||
// verify that the UID matches
|
||
if (pLockTable[wIndex].wUniqueID != wUID)
|
||
{
|
||
bRetCode = FALSE;
|
||
goto EXIT;
|
||
}
|
||
|
||
// Verify that the entry is valid
|
||
|
||
if (pDataTable[wIndex] == NULL)
|
||
{
|
||
bRetCode = FALSE;
|
||
goto EXIT;
|
||
}
|
||
|
||
// Try to lock the entry (ie check to see if we had the entry locked)
|
||
|
||
if (LockEntry(wIndex, 0) == TRUE)
|
||
{
|
||
// mark it for deletion, set the cleanp flag and then unlock it
|
||
|
||
pLockTable[wIndex].bDeleted = TRUE;
|
||
pLockTable[wIndex].bCleanup = bCleanup;
|
||
|
||
UnLockEntry(wIndex);
|
||
|
||
// Note: this function does not call ::Unlock() on behalf of the user.
|
||
// Thus, the entry is only marked as deleted at this point and can no
|
||
// longer be locked by any threads (including the one that marked it for delete).
|
||
// The thread that marked the entry as deleted must call ::Unlock() to actually
|
||
// free up the entry.
|
||
}
|
||
|
||
EXIT:
|
||
|
||
// Unlock the table
|
||
|
||
UnLockTable();
|
||
|
||
return bRetCode;
|
||
}
|
||
|
||
/*
|
||
** TSTable::Lock
|
||
*
|
||
* FILENAME: c:\msdev\projects\firewalls\inc\table.h
|
||
*
|
||
* PARAMETERS:
|
||
*
|
||
* DESCRIPTION: Validates that an object still exists. Can be called
|
||
* regardless if caller has entry locked or not.
|
||
*
|
||
* RETURNS:
|
||
*
|
||
*/
|
||
|
||
template <class EntryData>
|
||
BOOL TSTable<EntryData>::Validate(DWORD_PTR dwID)
|
||
{
|
||
BOOL bRetCode = TRUE;
|
||
WORD wIndex,
|
||
wUID;
|
||
|
||
BreakID(dwID, &wIndex, &wUID);
|
||
|
||
// Lock the table
|
||
|
||
LockTable();
|
||
|
||
// Verify the index is within bounds
|
||
|
||
if (wIndex >= wSize)
|
||
{
|
||
bRetCode = FALSE;
|
||
goto EXIT;
|
||
}
|
||
|
||
// Verify that the entry is actually valid (ie the lock in non-NULL,
|
||
// the object status is valid, the unique ID matches, and the data ptr is not null).
|
||
|
||
if (pLockTable[wIndex].hLock == NULL ||
|
||
pLockTable[wIndex].bDeleted == TRUE ||
|
||
pLockTable[wIndex].wUniqueID != wUID ||
|
||
pDataTable[wIndex] == NULL)
|
||
{
|
||
bRetCode = FALSE;
|
||
goto EXIT;
|
||
}
|
||
|
||
EXIT:
|
||
|
||
// Unlock the table
|
||
|
||
UnLockTable();
|
||
|
||
return bRetCode;
|
||
}
|
||
|
||
/*
|
||
** TSTable::EnumerateEntries
|
||
*
|
||
* FILENAME: c:\msdev\projects\firewalls\inc\table.h
|
||
*
|
||
* PARAMETERS:
|
||
*
|
||
* DESCRIPTION:
|
||
*
|
||
* RETURNS:
|
||
*
|
||
*/
|
||
|
||
template <class EntryData>
|
||
EntryData* TSTable<EntryData>::EnumerateEntries(TABLE_CALLBACK callbackFunc,
|
||
LPVOID context,
|
||
BOOL bUnlockTable)
|
||
{
|
||
DWORD dwAction;
|
||
WORD wIndex = wSize;
|
||
EntryData* pEntryData = NULL;
|
||
DWORD dwEntryID;
|
||
|
||
// Make sure they passed a good function
|
||
|
||
if (callbackFunc == NULL)
|
||
{
|
||
goto EXIT;
|
||
}
|
||
|
||
// Lock the table
|
||
|
||
LockTable();
|
||
|
||
// Run through the data table and pass the data to the callback function
|
||
|
||
for (wIndex = 0; wIndex < wSize; wIndex++)
|
||
{
|
||
// Verify that there is actually data in the entry and that the entry has not
|
||
// been marked for deletion.
|
||
|
||
if (pDataTable[wIndex] == NULL ||
|
||
pLockTable[wIndex].bDeleted == TRUE)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
|
||
// Try to lock the entry...if we cannot, then we don't have the lock and
|
||
// we will only report entries that we have locked (or are unlocked)
|
||
|
||
if (LockEntry(wIndex, 0) == FALSE)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
// build and remember the "full" entry ID so we can use it to unlock the entry
|
||
dwEntryID = MakeID(wIndex, pLockTable[wIndex].wUniqueID);
|
||
|
||
// Save the pointer to the object.
|
||
|
||
pEntryData = pDataTable[wIndex];
|
||
|
||
// note: only unlock the table during the callback if we are explicitly asked to (the
|
||
// default is not to unlock the table).
|
||
if(bUnlockTable == TRUE)
|
||
UnLockTable();
|
||
|
||
// Call their function
|
||
dwAction = callbackFunc(pDataTable[wIndex], context);
|
||
|
||
if(bUnlockTable == TRUE)
|
||
LockTable();
|
||
|
||
// If the action says to delete the entry, then do so...if we are also to delete
|
||
// the object, pass in a TRUE.
|
||
|
||
if (dwAction == CALLBACK_DELETE_ENTRY ||
|
||
dwAction == CALLBACK_DELETE_ENTRY_AND_OBJECT)
|
||
{
|
||
Delete(dwEntryID, (dwAction == CALLBACK_DELETE_ENTRY ? FALSE : TRUE));
|
||
}
|
||
|
||
// If the action says abort, then break the loop...notice that means that
|
||
// the entry is still locked
|
||
|
||
else if (dwAction == CALLBACK_ABORT)
|
||
{
|
||
goto EXIT;
|
||
}
|
||
|
||
// Unlock the entry...notice we don't use UnLockEntry. The reason is that
|
||
// if the entry has been marked as deleted, then we need to have
|
||
// it destroyed and UnLockEntry doesn't do that.
|
||
|
||
Unlock(dwEntryID);
|
||
}
|
||
|
||
EXIT:
|
||
|
||
// Unlock the table
|
||
|
||
UnLockTable();
|
||
|
||
// Return NULL if we processed the entire table...if we were told to abort,
|
||
// return a pointer to the entry we stopped on.
|
||
|
||
return (wIndex == wSize ? NULL : pEntryData);
|
||
}
|
||
|
||
// helper functions - these assume table is locked and index is good
|
||
|
||
/*
|
||
** TSTable::LockEntry
|
||
*
|
||
* FILENAME: c:\msdev\projects\firewalls\inc\table.h
|
||
*
|
||
* PARAMETERS:
|
||
*
|
||
* DESCRIPTION:
|
||
*
|
||
* RETURNS:
|
||
*
|
||
*/
|
||
|
||
template <class EntryData>
|
||
BOOL TSTable<EntryData>::LockEntry(WORD wIndex,
|
||
DWORD timeout)
|
||
{
|
||
BOOL bRetCode = TRUE;
|
||
DWORD dwRetCode;
|
||
|
||
|
||
// Try to lock the entry. If it succeeds, we'll bump up the lock count. If
|
||
// the wait ended because another thread abandoned the mutex, then set the count
|
||
// to one.
|
||
|
||
dwRetCode = WaitForSingleObject(pLockTable[wIndex].hLock, timeout);
|
||
|
||
if (dwRetCode == WAIT_OBJECT_0)
|
||
{
|
||
pLockTable[wIndex].iLockCount++;
|
||
}
|
||
else if (dwRetCode == WAIT_ABANDONED)
|
||
{
|
||
pLockTable[wIndex].iLockCount = 1;
|
||
}
|
||
else
|
||
{
|
||
bRetCode = FALSE;
|
||
}
|
||
|
||
return bRetCode;
|
||
}
|
||
|
||
/*
|
||
** TSTable::UnLockEntry
|
||
*
|
||
* FILENAME: c:\msdev\projects\firewalls\inc\table.h
|
||
*
|
||
* PARAMETERS:
|
||
*
|
||
* DESCRIPTION:
|
||
*
|
||
* RETURNS:
|
||
*
|
||
*/
|
||
|
||
template <class EntryData>
|
||
BOOL TSTable<EntryData>::UnLockEntry(WORD wIndex)
|
||
{
|
||
BOOL bRetCode;
|
||
|
||
// Release the mutex...if that succeeds, reduce the count
|
||
|
||
if((bRetCode = ReleaseMutex(pLockTable[wIndex].hLock)) == TRUE)
|
||
{
|
||
pLockTable[wIndex].iLockCount--;
|
||
}
|
||
|
||
return bRetCode;
|
||
}
|
||
|
||
|
||
/*
|
||
** TSTable::GenerateUniqueID
|
||
*
|
||
* FILENAME: c:\msdev\projects\firewalls\inc\table.h
|
||
*
|
||
* PARAMETERS:
|
||
*
|
||
* DESCRIPTION: table should be locked before calling this function.
|
||
*
|
||
* RETURNS:
|
||
*
|
||
*/
|
||
|
||
template <class EntryData>
|
||
WORD TSTable<EntryData>::GenerateUniqueID()
|
||
{
|
||
// table must be locked
|
||
if(++wUniqueID == TSTABLE_INVALID_UNIQUE_ID)
|
||
wUniqueID++;
|
||
return(wUniqueID);
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
#endif
|
||
|