You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
800 lines
15 KiB
800 lines
15 KiB
/*++
|
|
|
|
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;
|
|
}
|
|
|