801 lines
15 KiB
C++
801 lines
15 KiB
C++
/*++
|
||
|
||
Copyright (c) 1994 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
serialst.cxx
|
||
|
||
Abstract:
|
||
|
||
Functions to deal with a serialized list. These are replaced by macros in
|
||
the retail version, except for functions no longer inlined due to critsec
|
||
wrapper
|
||
|
||
Contents:
|
||
[InitializeSerializedList]
|
||
[TerminateSerializedList]
|
||
[LockSerializedList]
|
||
[UnlockSerializedList]
|
||
[InsertAtHeadOfSerializedList]
|
||
[InsertAtTailOfSerializedList]
|
||
[RemoveFromSerializedList]
|
||
[IsSerializedListEmpty]
|
||
[HeadOfSerializedList]
|
||
[TailOfSerializedList]
|
||
[CheckEntryOnSerializedList]
|
||
[(CheckEntryOnList)]
|
||
SlDequeueHead
|
||
SlDequeueTail
|
||
IsOnSerializedList
|
||
|
||
Author:
|
||
|
||
Richard L Firth (rfirth) 16-Feb-1995
|
||
|
||
Environment:
|
||
|
||
Win-32 user level
|
||
|
||
Revision History:
|
||
|
||
16-Feb-1995 rfirth
|
||
Created
|
||
|
||
--*/
|
||
|
||
#include <wininetp.h>
|
||
|
||
#if INET_DEBUG
|
||
|
||
//
|
||
// manifests
|
||
//
|
||
|
||
#define SERIALIZED_LIST_SIGNATURE 'tslS'
|
||
|
||
//
|
||
// private prototypes
|
||
//
|
||
|
||
PRIVATE
|
||
DEBUG_FUNCTION
|
||
BOOL
|
||
CheckEntryOnList(
|
||
IN PLIST_ENTRY List,
|
||
IN PLIST_ENTRY Entry,
|
||
IN BOOL ExpectedResult
|
||
);
|
||
|
||
//
|
||
// data
|
||
//
|
||
|
||
BOOL fCheckEntryOnList = FALSE;
|
||
BOOL ReportCheckEntryOnListErrors = FALSE;
|
||
|
||
//
|
||
// functions
|
||
//
|
||
|
||
|
||
DEBUG_FUNCTION
|
||
BOOL
|
||
InitializeSerializedList(
|
||
IN LPSERIALIZED_LIST SerializedList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
initializes a serialized list
|
||
|
||
Arguments:
|
||
|
||
SerializedList - pointer to SERIALIZED_LIST
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
INET_ASSERT(SerializedList != NULL);
|
||
|
||
SerializedList->Signature = SERIALIZED_LIST_SIGNATURE;
|
||
SerializedList->LockCount = 0;
|
||
|
||
INITIALIZE_RESOURCE_INFO(&SerializedList->ResourceInfo);
|
||
|
||
InitializeListHead(&SerializedList->List);
|
||
SerializedList->ElementCount = 0;
|
||
return SerializedList->Lock.Init();
|
||
}
|
||
|
||
|
||
DEBUG_FUNCTION
|
||
VOID
|
||
TerminateSerializedList(
|
||
IN LPSERIALIZED_LIST SerializedList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Undoes InitializeSerializeList
|
||
|
||
Arguments:
|
||
|
||
SerializedList - pointer to serialized list to terminate
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
INET_ASSERT(SerializedList != NULL);
|
||
INET_ASSERT(SerializedList->Signature == SERIALIZED_LIST_SIGNATURE);
|
||
INET_ASSERT(SerializedList->ElementCount == 0);
|
||
|
||
if (SerializedList->ElementCount != 0) {
|
||
|
||
DEBUG_PRINT(SERIALST,
|
||
ERROR,
|
||
("list @ %#x has %d elements, first is %#x\n",
|
||
SerializedList,
|
||
SerializedList->ElementCount,
|
||
SerializedList->List.Flink
|
||
));
|
||
|
||
} else {
|
||
|
||
INET_ASSERT(IsListEmpty(&SerializedList->List));
|
||
|
||
}
|
||
SerializedList->Lock.FreeLock();
|
||
}
|
||
|
||
|
||
DEBUG_FUNCTION
|
||
BOOL
|
||
LockSerializedList(
|
||
IN LPSERIALIZED_LIST SerializedList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Acquires a serialized list locks
|
||
|
||
Arguments:
|
||
|
||
SerializedList - SERIALIZED_LIST to lock
|
||
|
||
Return Value:
|
||
|
||
Success if able to acquire a lock.
|
||
|
||
--*/
|
||
|
||
{
|
||
INET_ASSERT(SerializedList->Signature == SERIALIZED_LIST_SIGNATURE);
|
||
INET_ASSERT(SerializedList->LockCount >= 0);
|
||
|
||
if ((!SerializedList->Lock.IsInitialized() && !SerializedList->Lock.Init()) ||
|
||
!SerializedList->Lock.Lock())
|
||
{
|
||
return FALSE;
|
||
}
|
||
else
|
||
{
|
||
if (SerializedList->LockCount != 0)
|
||
{
|
||
INET_ASSERT(SerializedList->ResourceInfo.Tid == GetCurrentThreadId());
|
||
}
|
||
}
|
||
++SerializedList->LockCount;
|
||
SerializedList->ResourceInfo.Tid = GetCurrentThreadId();
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
DEBUG_FUNCTION
|
||
VOID
|
||
UnlockSerializedList(
|
||
IN LPSERIALIZED_LIST SerializedList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Releases a serialized list lock
|
||
|
||
Arguments:
|
||
|
||
SerializedList - SERIALIZED_LIST to unlock
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
INET_ASSERT(SerializedList->Signature == SERIALIZED_LIST_SIGNATURE);
|
||
INET_ASSERT(SerializedList->ResourceInfo.Tid == GetCurrentThreadId());
|
||
INET_ASSERT(SerializedList->LockCount > 0);
|
||
|
||
--SerializedList->LockCount;
|
||
SerializedList->Lock.Unlock();
|
||
}
|
||
|
||
|
||
DEBUG_FUNCTION
|
||
BOOL
|
||
InsertAtHeadOfSerializedList(
|
||
IN LPSERIALIZED_LIST SerializedList,
|
||
IN PLIST_ENTRY Entry
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Adds an item to the head of a serialized list
|
||
|
||
Arguments:
|
||
|
||
SerializedList - SERIALIZED_LIST to update
|
||
|
||
Entry - thing to update it with
|
||
|
||
Return Value:
|
||
|
||
FALSE - only if unable to acquire the lock
|
||
|
||
--*/
|
||
|
||
{
|
||
INET_ASSERT(Entry != &SerializedList->List);
|
||
|
||
if (LockSerializedList(SerializedList))
|
||
{
|
||
if (fCheckEntryOnList)
|
||
{
|
||
CheckEntryOnList(&SerializedList->List, Entry, FALSE);
|
||
}
|
||
InsertHeadList(&SerializedList->List, Entry);
|
||
++SerializedList->ElementCount;
|
||
|
||
INET_ASSERT(SerializedList->ElementCount > 0);
|
||
|
||
UnlockSerializedList(SerializedList);
|
||
return TRUE;
|
||
}
|
||
else
|
||
{
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
|
||
DEBUG_FUNCTION
|
||
BOOL
|
||
InsertAtTailOfSerializedList(
|
||
IN LPSERIALIZED_LIST SerializedList,
|
||
IN PLIST_ENTRY Entry
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Adds an item to the head of a serialized list
|
||
|
||
Arguments:
|
||
|
||
SerializedList - SERIALIZED_LIST to update
|
||
|
||
Entry - thing to update it with
|
||
|
||
Return Value:
|
||
|
||
FALSE - only if not enough memory was available to insert an item.
|
||
|
||
--*/
|
||
|
||
{
|
||
INET_ASSERT(Entry != &SerializedList->List);
|
||
|
||
if (LockSerializedList(SerializedList))
|
||
{
|
||
if (fCheckEntryOnList) {
|
||
CheckEntryOnList(&SerializedList->List, Entry, FALSE);
|
||
}
|
||
InsertTailList(&SerializedList->List, Entry);
|
||
++SerializedList->ElementCount;
|
||
|
||
INET_ASSERT(SerializedList->ElementCount > 0);
|
||
|
||
UnlockSerializedList(SerializedList);
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
DEBUG_FUNCTION
|
||
RemoveFromSerializedList(
|
||
IN LPSERIALIZED_LIST SerializedList,
|
||
IN PLIST_ENTRY Entry
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Removes the entry from a serialized list
|
||
|
||
Arguments:
|
||
|
||
SerializedList - SERIALIZED_LIST to remove entry from
|
||
|
||
Entry - pointer to entry to remove
|
||
|
||
Return Value:
|
||
|
||
FALSE if unable sycnhronize access to the list due to low-memory.
|
||
|
||
--*/
|
||
|
||
{
|
||
INET_ASSERT((Entry->Flink != NULL) && (Entry->Blink != NULL));
|
||
|
||
if (LockSerializedList(SerializedList))
|
||
{
|
||
if (fCheckEntryOnList)
|
||
{
|
||
CheckEntryOnList(&SerializedList->List, Entry, TRUE);
|
||
}
|
||
|
||
INET_ASSERT(SerializedList->ElementCount > 0);
|
||
|
||
RemoveEntryList(Entry);
|
||
--SerializedList->ElementCount;
|
||
Entry->Flink = NULL;
|
||
Entry->Blink = NULL;
|
||
UnlockSerializedList(SerializedList);
|
||
return TRUE;
|
||
}
|
||
else
|
||
{
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
|
||
DEBUG_FUNCTION
|
||
BOOL
|
||
IsSerializedListEmpty(
|
||
IN LPSERIALIZED_LIST SerializedList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Checks if a serialized list contains any elements
|
||
|
||
Arguments:
|
||
|
||
SerializedList - pointer to list to check
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
|
||
--*/
|
||
|
||
{
|
||
// For simplicity, don't worry about returning additional status.
|
||
// Due to this always being tied to additional manipulation,
|
||
// the lock has already been acquired in all current cases.
|
||
if (!LockSerializedList(SerializedList))
|
||
return TRUE;
|
||
|
||
INET_ASSERT(SerializedList->Signature == SERIALIZED_LIST_SIGNATURE);
|
||
|
||
BOOL empty;
|
||
|
||
if (IsListEmpty(&SerializedList->List)) {
|
||
|
||
INET_ASSERT(SerializedList->ElementCount == 0);
|
||
|
||
empty = TRUE;
|
||
} else {
|
||
|
||
INET_ASSERT(SerializedList->ElementCount != 0);
|
||
|
||
empty = FALSE;
|
||
}
|
||
|
||
UnlockSerializedList(SerializedList);
|
||
|
||
return empty;
|
||
}
|
||
|
||
|
||
DEBUG_FUNCTION
|
||
PLIST_ENTRY
|
||
HeadOfSerializedList(
|
||
IN LPSERIALIZED_LIST SerializedList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns the element at the tail of the list, without taking the lock
|
||
|
||
Arguments:
|
||
|
||
SerializedList - pointer to SERIALIZED_LIST
|
||
|
||
Return Value:
|
||
|
||
PLIST_ENTRY
|
||
pointer to element at tail of list
|
||
|
||
--*/
|
||
|
||
{
|
||
INET_ASSERT(SerializedList->Signature == SERIALIZED_LIST_SIGNATURE);
|
||
|
||
return SerializedList->List.Flink;
|
||
}
|
||
|
||
|
||
DEBUG_FUNCTION
|
||
PLIST_ENTRY
|
||
TailOfSerializedList(
|
||
IN LPSERIALIZED_LIST SerializedList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns the element at the tail of the list, without taking the lock
|
||
|
||
Arguments:
|
||
|
||
SerializedList - pointer to SERIALIZED_LIST
|
||
|
||
Return Value:
|
||
|
||
PLIST_ENTRY
|
||
pointer to element at tail of list
|
||
|
||
--*/
|
||
|
||
{
|
||
INET_ASSERT(SerializedList->Signature == SERIALIZED_LIST_SIGNATURE);
|
||
|
||
return SerializedList->List.Blink;
|
||
}
|
||
|
||
|
||
DEBUG_FUNCTION
|
||
BOOL
|
||
CheckEntryOnSerializedList(
|
||
IN LPSERIALIZED_LIST SerializedList,
|
||
IN PLIST_ENTRY Entry,
|
||
IN BOOL ExpectedResult
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Checks an entry exists (or doesn't exist) on a list
|
||
|
||
Arguments:
|
||
|
||
SerializedList - pointer to serialized list
|
||
|
||
Entry - pointer to entry
|
||
|
||
ExpectedResult - TRUE if expected on list, else FALSE
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
TRUE - expected result
|
||
|
||
FALSE - unexpected result
|
||
|
||
--*/
|
||
|
||
{
|
||
INET_ASSERT(SerializedList->Signature == SERIALIZED_LIST_SIGNATURE);
|
||
|
||
if (!LockSerializedList(SerializedList))
|
||
return FALSE;
|
||
|
||
BOOL result;
|
||
|
||
__try {
|
||
result = CheckEntryOnList(&SerializedList->List, Entry, ExpectedResult);
|
||
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
||
DEBUG_PRINT(SERIALST,
|
||
FATAL,
|
||
("List @ %#x (%d elements) is bad\n",
|
||
SerializedList,
|
||
SerializedList->ElementCount
|
||
));
|
||
|
||
result = FALSE;
|
||
}
|
||
ENDEXCEPT
|
||
UnlockSerializedList(SerializedList);
|
||
|
||
return result;
|
||
}
|
||
|
||
|
||
PRIVATE
|
||
DEBUG_FUNCTION
|
||
BOOL
|
||
CheckEntryOnList(
|
||
IN PLIST_ENTRY List,
|
||
IN PLIST_ENTRY Entry,
|
||
IN BOOL ExpectedResult
|
||
)
|
||
{
|
||
BOOLEAN found = FALSE;
|
||
PLIST_ENTRY p;
|
||
|
||
if (!IsListEmpty(List)) {
|
||
for (p = List->Flink; p != List; p = p->Flink) {
|
||
if (p == Entry) {
|
||
found = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
if (found != ExpectedResult) {
|
||
if (ReportCheckEntryOnListErrors) {
|
||
|
||
LPSTR description;
|
||
|
||
description = found
|
||
? "Entry %#x already on list %#x\n"
|
||
: "Entry %#x not found on list %#x\n"
|
||
;
|
||
|
||
DEBUG_PRINT(SERIALST,
|
||
ERROR,
|
||
(description,
|
||
Entry,
|
||
List
|
||
));
|
||
|
||
DEBUG_BREAK(SERIALST);
|
||
|
||
}
|
||
return FALSE;
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
#else // else !INET_DEBUG
|
||
|
||
BOOL
|
||
InitializeSerializedList(LPSERIALIZED_LIST pList)
|
||
{
|
||
InitializeListHead(&(pList)->List);
|
||
(pList)->ElementCount = 0;
|
||
return (pList->Lock).Init();
|
||
}
|
||
|
||
|
||
BOOL
|
||
InsertAtHeadOfSerializedList(LPSERIALIZED_LIST list, PLIST_ENTRY entry)
|
||
{
|
||
if (LockSerializedList(list))
|
||
{
|
||
InsertHeadList(&(list)->List, entry);
|
||
++(list)->ElementCount;
|
||
UnlockSerializedList(list);
|
||
return TRUE;
|
||
}
|
||
else
|
||
{
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
|
||
BOOL
|
||
InsertAtTailOfSerializedList(LPSERIALIZED_LIST list, PLIST_ENTRY entry)
|
||
{
|
||
if (LockSerializedList(list))
|
||
{
|
||
InsertTailList(&(list)->List, entry);
|
||
++(list)->ElementCount;
|
||
UnlockSerializedList(list);
|
||
return TRUE;
|
||
}
|
||
else
|
||
{
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
|
||
BOOL
|
||
RemoveFromSerializedList(LPSERIALIZED_LIST list, PLIST_ENTRY entry)
|
||
{
|
||
if (LockSerializedList(list))
|
||
{
|
||
RemoveEntryList(entry);
|
||
--(list)->ElementCount;
|
||
UnlockSerializedList(list);
|
||
return TRUE;
|
||
}
|
||
else
|
||
{
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
#endif // INET_DEBUG
|
||
|
||
//
|
||
// functions that are always functions
|
||
//
|
||
|
||
|
||
LPVOID
|
||
SlDequeueHead(
|
||
IN LPSERIALIZED_LIST SerializedList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Dequeues the element at the head of the queue and returns its address or
|
||
NULL if the queue is empty
|
||
|
||
Arguments:
|
||
|
||
SerializedList - pointer to SERIALIZED_LIST to dequeue from
|
||
|
||
Return Value:
|
||
|
||
LPVOID
|
||
|
||
--*/
|
||
|
||
{
|
||
LPVOID entry = NULL;
|
||
|
||
if (!IsSerializedListEmpty(SerializedList)) {
|
||
if (LockSerializedList(SerializedList)) {
|
||
if (!IsSerializedListEmpty(SerializedList)) {
|
||
entry = (LPVOID)HeadOfSerializedList(SerializedList);
|
||
if (!RemoveFromSerializedList(SerializedList, (PLIST_ENTRY)entry))
|
||
entry = NULL;
|
||
}
|
||
UnlockSerializedList(SerializedList);
|
||
}
|
||
}
|
||
|
||
return entry;
|
||
}
|
||
|
||
|
||
LPVOID
|
||
SlDequeueTail(
|
||
IN LPSERIALIZED_LIST SerializedList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Dequeues the element at the tail of the queue and returns its address or
|
||
NULL if the queue is empty
|
||
|
||
Arguments:
|
||
|
||
SerializedList - pointer to SERIALIZED_LIST to dequeue from
|
||
|
||
Return Value:
|
||
|
||
LPVOID
|
||
|
||
--*/
|
||
|
||
{
|
||
LPVOID entry = NULL;
|
||
|
||
if (!IsSerializedListEmpty(SerializedList)) {
|
||
if (LockSerializedList(SerializedList)) {
|
||
if (!IsSerializedListEmpty(SerializedList)) {
|
||
entry = (LPVOID)TailOfSerializedList(SerializedList);
|
||
if (!RemoveFromSerializedList(SerializedList, (PLIST_ENTRY)entry))
|
||
entry = NULL;
|
||
}
|
||
UnlockSerializedList(SerializedList);
|
||
}
|
||
} else {
|
||
entry = NULL;
|
||
}
|
||
return entry;
|
||
}
|
||
|
||
|
||
BOOL
|
||
IsOnSerializedList(
|
||
IN LPSERIALIZED_LIST SerializedList,
|
||
IN PLIST_ENTRY Entry
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Checks if an entry is on a serialized list. Useful to call before
|
||
RemoveFromSerializedList() if multiple threads can remove the element
|
||
|
||
Arguments:
|
||
|
||
SerializedList - pointer to SERIALIZED_LIST
|
||
|
||
Entry - pointer to element to check
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
TRUE - Entry is on SerializedList
|
||
|
||
FALSE - " " not on "
|
||
|
||
--*/
|
||
|
||
{
|
||
BOOL onList = FALSE;
|
||
LPVOID entry;
|
||
|
||
if (!IsSerializedListEmpty(SerializedList)) {
|
||
if (LockSerializedList(SerializedList)) {
|
||
if (!IsSerializedListEmpty(SerializedList)) {
|
||
for (PLIST_ENTRY entry = HeadOfSerializedList(SerializedList);
|
||
entry != (PLIST_ENTRY)SlSelf(SerializedList);
|
||
entry = entry->Flink) {
|
||
|
||
if (entry == Entry) {
|
||
onList = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
UnlockSerializedList(SerializedList);
|
||
}
|
||
}
|
||
return onList;
|
||
}
|
||
|