ntdll: Slist support.
Implemented ntdll's RtlInitializeSListHead, RtlQueryDepthSList, RtlInterlockedFlushSList, RtlFirstEntrySList, RtlInterlockedPushEntrySList, RtlInterlockedPopEntrySList, their kernel32 equivalents, and tests.
This commit is contained in:
parent
7e7ff40769
commit
07db8882c2
|
@ -706,15 +706,15 @@
|
|||
@ stdcall InitAtomTable(long)
|
||||
@ stdcall InitializeCriticalSection(ptr)
|
||||
@ stdcall InitializeCriticalSectionAndSpinCount(ptr long)
|
||||
# @ stub InitializeSListHead ( -> ntdll.RtlInitializeSListHead)
|
||||
@ stdcall InitializeSListHead(ptr) ntdll.RtlInitializeSListHead
|
||||
@ stdcall InterlockedCompareExchange (ptr long long)
|
||||
@ stdcall InterlockedDecrement(ptr)
|
||||
@ stdcall InterlockedExchange(ptr long)
|
||||
@ stdcall InterlockedExchangeAdd (ptr long )
|
||||
# @ stub InterlockedFlushSList ( -> ntdll.RtlInterlockedFlushSList)
|
||||
@ stdcall InterlockedFlushSList(ptr) ntdll.RtlInterlockedFlushSList
|
||||
@ stdcall InterlockedIncrement(ptr)
|
||||
# @ stub InterlockedPopEntrySList ( -> ntdll.RtlInterlockedPopEntrySList)
|
||||
# @ stub InterlockedPushEntrySList ( -> ntdll.RtlInterlockedPushEntrySList)
|
||||
@ stdcall InterlockedPopEntrySList(ptr) ntdll.RtlInterlockedPopEntrySList
|
||||
@ stdcall InterlockedPushEntrySList(ptr ptr) ntdll.RtlInterlockedPushEntrySList
|
||||
@ stub InvalidateConsoleDIBits
|
||||
@ stdcall InvalidateNLSCache()
|
||||
@ stdcall IsBadCodePtr(ptr)
|
||||
|
@ -843,7 +843,7 @@
|
|||
@ stdcall PurgeComm(long long)
|
||||
@ stdcall -i386 -register QT_Thunk()
|
||||
@ stdcall QueryActCtxW(long ptr ptr long ptr long ptr)
|
||||
# @ stub QueryDepthSList ( -> ntdll.RtlQueryDepthSList)
|
||||
@ stdcall QueryDepthSList(ptr) ntdll.RtlQueryDepthSList
|
||||
@ stdcall QueryDosDeviceA(str ptr long)
|
||||
@ stdcall QueryDosDeviceW(wstr ptr long)
|
||||
@ stub QueryInformationJobObject
|
||||
|
|
|
@ -152,8 +152,102 @@ static void test_mutex(void)
|
|||
CloseHandle(hCreated);
|
||||
}
|
||||
|
||||
static void test_slist(void)
|
||||
{
|
||||
struct item
|
||||
{
|
||||
SLIST_ENTRY entry;
|
||||
int value;
|
||||
} item1, item2, item3, *pitem;
|
||||
|
||||
SLIST_HEADER slist_header, test_header;
|
||||
PSLIST_ENTRY entry;
|
||||
USHORT size;
|
||||
|
||||
VOID (WINAPI *pInitializeSListHead)(PSLIST_HEADER);
|
||||
USHORT (WINAPI *pQueryDepthSList)(PSLIST_HEADER);
|
||||
PSLIST_ENTRY (WINAPI *pInterlockedFlushSList)(PSLIST_HEADER);
|
||||
PSLIST_ENTRY (WINAPI *pInterlockedPopEntrySList)(PSLIST_HEADER);
|
||||
PSLIST_ENTRY (WINAPI *pInterlockedPushEntrySList)(PSLIST_HEADER,PSLIST_ENTRY);
|
||||
HMODULE kernel32;
|
||||
|
||||
kernel32 = GetModuleHandle("KERNEL32.DLL");
|
||||
pInitializeSListHead = (void*) GetProcAddress(kernel32, "InitializeSListHead");
|
||||
pQueryDepthSList = (void*) GetProcAddress(kernel32, "QueryDepthSList");
|
||||
pInterlockedFlushSList = (void*) GetProcAddress(kernel32, "InterlockedFlushSList");
|
||||
pInterlockedPopEntrySList = (void*) GetProcAddress(kernel32, "InterlockedPopEntrySList");
|
||||
pInterlockedPushEntrySList = (void*) GetProcAddress(kernel32, "InterlockedPushEntrySList");
|
||||
if (pInitializeSListHead == NULL ||
|
||||
pQueryDepthSList == NULL ||
|
||||
pInterlockedFlushSList == NULL ||
|
||||
pInterlockedPopEntrySList == NULL ||
|
||||
pInterlockedPushEntrySList == NULL)
|
||||
{
|
||||
skip("some required slist entrypoints were not found, skipping tests\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&test_header, 0, sizeof(test_header));
|
||||
memset(&slist_header, 0xFF, sizeof(slist_header));
|
||||
pInitializeSListHead(&slist_header);
|
||||
ok(memcmp(&test_header, &slist_header, sizeof(SLIST_HEADER)) == 0,
|
||||
"InitializeSListHead didn't zero-fill list header");
|
||||
size = pQueryDepthSList(&slist_header);
|
||||
ok(size == 0, "initially created slist has size %d, expected 0\n", size);
|
||||
|
||||
item1.value = 1;
|
||||
ok(pInterlockedPushEntrySList(&slist_header, &item1.entry) == NULL,
|
||||
"previous entry in empty slist wasn't NULL\n");
|
||||
size = pQueryDepthSList(&slist_header);
|
||||
ok(size == 1, "slist with 1 item has size %d\n", size);
|
||||
|
||||
item2.value = 2;
|
||||
entry = pInterlockedPushEntrySList(&slist_header, &item2.entry);
|
||||
ok(entry != NULL, "previous entry in non-empty slist was NULL\n");
|
||||
if (entry != NULL)
|
||||
{
|
||||
pitem = (struct item*) entry;
|
||||
ok(pitem->value == 1, "previous entry in slist wasn't the one added\n");
|
||||
}
|
||||
size = pQueryDepthSList(&slist_header);
|
||||
ok(size == 2, "slist with 2 items has size %d\n", size);
|
||||
|
||||
item3.value = 3;
|
||||
entry = pInterlockedPushEntrySList(&slist_header, &item3.entry);
|
||||
ok(entry != NULL, "previous entry in non-empty slist was NULL\n");
|
||||
if (entry != NULL)
|
||||
{
|
||||
pitem = (struct item*) entry;
|
||||
ok(pitem->value == 2, "previous entry in slist wasn't the one added\n");
|
||||
}
|
||||
size = pQueryDepthSList(&slist_header);
|
||||
ok(size == 3, "slist with 3 items has size %d\n", size);
|
||||
|
||||
entry = pInterlockedPopEntrySList(&slist_header);
|
||||
ok(entry != NULL, "entry shouldn't be NULL\n");
|
||||
if (entry != NULL)
|
||||
{
|
||||
pitem = (struct item*) entry;
|
||||
ok(pitem->value == 3, "unexpected entry removed\n");
|
||||
}
|
||||
size = pQueryDepthSList(&slist_header);
|
||||
ok(size == 2, "slist with 2 items has size %d\n", size);
|
||||
|
||||
entry = pInterlockedFlushSList(&slist_header);
|
||||
size = pQueryDepthSList(&slist_header);
|
||||
ok(size == 0, "flushed slist should be empty, size is %d\n", size);
|
||||
if (size == 0)
|
||||
{
|
||||
ok(pInterlockedPopEntrySList(&slist_header) == NULL,
|
||||
"popping empty slist didn't return NULL\n");
|
||||
}
|
||||
ok(((struct item*)entry)->value == 2, "item 2 not in front of list\n");
|
||||
ok(((struct item*)entry->Next)->value == 1, "item 1 not at the back of list\n");
|
||||
}
|
||||
|
||||
START_TEST(sync)
|
||||
{
|
||||
test_signalandwait();
|
||||
test_mutex();
|
||||
test_slist();
|
||||
}
|
||||
|
|
|
@ -592,7 +592,7 @@
|
|||
@ stdcall RtlFindSetBits(ptr long long)
|
||||
@ stdcall RtlFindSetBitsAndClear(ptr long long)
|
||||
@ stdcall RtlFindSetRuns(ptr ptr long long)
|
||||
@ stub RtlFirstEntrySList
|
||||
@ stdcall RtlFirstEntrySList(ptr)
|
||||
@ stdcall RtlFirstFreeAce(ptr ptr)
|
||||
@ stub RtlFlushPropertySet
|
||||
# @ stub RtlFlushSecureMemoryCache
|
||||
|
@ -670,7 +670,7 @@
|
|||
@ stub RtlInitializeRXact
|
||||
# @ stub RtlInitializeRangeList
|
||||
@ stdcall RtlInitializeResource(ptr)
|
||||
# @ stub RtlInitializeSListHead
|
||||
@ stdcall RtlInitializeSListHead(ptr)
|
||||
@ stdcall RtlInitializeSid(ptr ptr long)
|
||||
# @ stub RtlInitializeStackTraceDataBase
|
||||
@ stub RtlInsertElementGenericTable
|
||||
|
@ -678,10 +678,10 @@
|
|||
@ stdcall RtlInt64ToUnicodeString(double long ptr)
|
||||
@ stdcall RtlIntegerToChar(long long long ptr)
|
||||
@ stdcall RtlIntegerToUnicodeString(long long ptr)
|
||||
# @ stub RtlInterlockedFlushSList
|
||||
# @ stub RtlInterlockedPopEntrySList
|
||||
# @ stub RtlInterlockedPushEntrySList
|
||||
# @ stub RtlInterlockedPushListSList
|
||||
@ stdcall RtlInterlockedFlushSList(ptr)
|
||||
@ stdcall RtlInterlockedPopEntrySList(ptr)
|
||||
@ stdcall RtlInterlockedPushEntrySList(ptr ptr)
|
||||
@ stdcall RtlInterlockedPushListSList(ptr ptr ptr long)
|
||||
# @ stub RtlInvertRangeList
|
||||
# @ stub RtlIpv4AddressToStringA
|
||||
# @ stub RtlIpv4AddressToStringExA
|
||||
|
@ -763,7 +763,7 @@
|
|||
@ stub RtlProtectHeap
|
||||
# @ stub RtlPushFrame
|
||||
@ stdcall RtlQueryAtomInAtomTable(ptr long ptr ptr ptr ptr)
|
||||
@ stub RtlQueryDepthSList
|
||||
@ stdcall RtlQueryDepthSList(ptr)
|
||||
@ stdcall RtlQueryEnvironmentVariable_U(ptr ptr ptr)
|
||||
@ stub RtlQueryHeapInformation
|
||||
@ stdcall RtlQueryInformationAcl(ptr ptr long long)
|
||||
|
|
130
dlls/ntdll/rtl.c
130
dlls/ntdll/rtl.c
|
@ -35,6 +35,7 @@
|
|||
#include "windef.h"
|
||||
#include "winternl.h"
|
||||
#include "wine/debug.h"
|
||||
#include "wine/exception.h"
|
||||
#include "ntdll_misc.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
|
||||
|
@ -922,3 +923,132 @@ PVOID WINAPI RtlDecodePointer( PVOID ptr )
|
|||
DWORD_PTR ptrval = (DWORD_PTR) ptr;
|
||||
return (PVOID)(ptrval ^ get_pointer_obfuscator());
|
||||
}
|
||||
|
||||
VOID WINAPI RtlInitializeSListHead(volatile PSLIST_HEADER ListHeader)
|
||||
{
|
||||
TRACE("(%p)\n", ListHeader);
|
||||
#if _WIN64
|
||||
assert(0);
|
||||
#else
|
||||
ListHeader->Alignment = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
USHORT WINAPI RtlQueryDepthSList(volatile PSLIST_HEADER ListHeader)
|
||||
{
|
||||
TRACE("(%p)\n", ListHeader);
|
||||
#if _WIN64
|
||||
assert(0);
|
||||
#else
|
||||
return ListHeader->Depth;
|
||||
#endif
|
||||
}
|
||||
|
||||
PSLIST_ENTRY WINAPI RtlFirstEntrySList(volatile PSLIST_HEADER ListHeader)
|
||||
{
|
||||
TRACE("(%p)\n", ListHeader);
|
||||
#if _WIN64
|
||||
assert(0);
|
||||
#else
|
||||
return ListHeader->Next.Next;
|
||||
#endif
|
||||
}
|
||||
|
||||
PSLIST_ENTRY WINAPI RtlInterlockedFlushSList(volatile PSLIST_HEADER ListHeader)
|
||||
{
|
||||
SLIST_HEADER oldHeader, newHeader;
|
||||
TRACE("(%p)\n", ListHeader);
|
||||
#if _WIN64
|
||||
assert(0);
|
||||
#else
|
||||
if (ListHeader->Depth == 0)
|
||||
return NULL;
|
||||
newHeader.Alignment = 0;
|
||||
do
|
||||
{
|
||||
oldHeader = *ListHeader;
|
||||
newHeader.Sequence = ListHeader->Sequence + 1;
|
||||
} while (interlocked_cmpxchg64((__int64*)&ListHeader->Alignment,
|
||||
newHeader.Alignment,
|
||||
oldHeader.Alignment) != oldHeader.Alignment);
|
||||
return oldHeader.Next.Next;
|
||||
#endif
|
||||
}
|
||||
|
||||
PSLIST_ENTRY WINAPI RtlInterlockedPushEntrySList(volatile PSLIST_HEADER ListHeader,
|
||||
PSLIST_ENTRY ListEntry)
|
||||
{
|
||||
SLIST_HEADER oldHeader, newHeader;
|
||||
TRACE("(%p, %p)\n", ListHeader, ListEntry);
|
||||
#if _WIN64
|
||||
assert(0);
|
||||
#else
|
||||
newHeader.Next.Next = ListEntry;
|
||||
do
|
||||
{
|
||||
oldHeader = *ListHeader;
|
||||
ListEntry->Next = ListHeader->Next.Next;
|
||||
newHeader.Depth = ListHeader->Depth + 1;
|
||||
newHeader.Sequence = ListHeader->Sequence + 1;
|
||||
} while (interlocked_cmpxchg64((__int64*)&ListHeader->Alignment,
|
||||
newHeader.Alignment,
|
||||
oldHeader.Alignment) != oldHeader.Alignment);
|
||||
return oldHeader.Next.Next;
|
||||
#endif
|
||||
}
|
||||
|
||||
PSLIST_ENTRY WINAPI RtlInterlockedPopEntrySList(volatile PSLIST_HEADER ListHeader)
|
||||
{
|
||||
SLIST_HEADER oldHeader, newHeader;
|
||||
PSLIST_ENTRY entry;
|
||||
TRACE("(%p)\n", ListHeader);
|
||||
#if _WIN64
|
||||
assert(0);
|
||||
#else
|
||||
do
|
||||
{
|
||||
oldHeader = *ListHeader;
|
||||
entry = ListHeader->Next.Next;
|
||||
if (entry == NULL)
|
||||
return NULL;
|
||||
/* entry could be deleted by another thread */
|
||||
__TRY
|
||||
{
|
||||
newHeader.Next.Next = entry->Next;
|
||||
newHeader.Depth = ListHeader->Depth - 1;
|
||||
newHeader.Sequence = ListHeader->Sequence + 1;
|
||||
}
|
||||
__EXCEPT_PAGE_FAULT
|
||||
{
|
||||
}
|
||||
__ENDTRY
|
||||
} while (interlocked_cmpxchg64((__int64*)&ListHeader->Alignment,
|
||||
newHeader.Alignment,
|
||||
oldHeader.Alignment) != oldHeader.Alignment);
|
||||
return entry;
|
||||
#endif
|
||||
}
|
||||
|
||||
PSLIST_ENTRY WINAPI RtlInterlockedPushListSList(volatile PSLIST_HEADER ListHeader,
|
||||
PSLIST_ENTRY FirstEntry,
|
||||
PSLIST_ENTRY LastEntry,
|
||||
ULONG Count)
|
||||
{
|
||||
SLIST_HEADER oldHeader, newHeader;
|
||||
TRACE("(%p, %p, %p, %d)\n", ListHeader, FirstEntry, LastEntry, Count);
|
||||
#if _WIN64
|
||||
assert(0);
|
||||
#else
|
||||
newHeader.Next.Next = FirstEntry;
|
||||
do
|
||||
{
|
||||
oldHeader = *ListHeader;
|
||||
newHeader.Depth = ListHeader->Depth + Count;
|
||||
newHeader.Sequence = ListHeader->Sequence + 1;
|
||||
LastEntry->Next = ListHeader->Next.Next;
|
||||
} while (interlocked_cmpxchg64((__int64*)&ListHeader->Alignment,
|
||||
newHeader.Alignment,
|
||||
oldHeader.Alignment) != oldHeader.Alignment);
|
||||
return oldHeader.Next.Next;
|
||||
#endif
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue