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 InitAtomTable(long)
|
||||||
@ stdcall InitializeCriticalSection(ptr)
|
@ stdcall InitializeCriticalSection(ptr)
|
||||||
@ stdcall InitializeCriticalSectionAndSpinCount(ptr long)
|
@ stdcall InitializeCriticalSectionAndSpinCount(ptr long)
|
||||||
# @ stub InitializeSListHead ( -> ntdll.RtlInitializeSListHead)
|
@ stdcall InitializeSListHead(ptr) ntdll.RtlInitializeSListHead
|
||||||
@ stdcall InterlockedCompareExchange (ptr long long)
|
@ stdcall InterlockedCompareExchange (ptr long long)
|
||||||
@ stdcall InterlockedDecrement(ptr)
|
@ stdcall InterlockedDecrement(ptr)
|
||||||
@ stdcall InterlockedExchange(ptr long)
|
@ stdcall InterlockedExchange(ptr long)
|
||||||
@ stdcall InterlockedExchangeAdd (ptr long )
|
@ stdcall InterlockedExchangeAdd (ptr long )
|
||||||
# @ stub InterlockedFlushSList ( -> ntdll.RtlInterlockedFlushSList)
|
@ stdcall InterlockedFlushSList(ptr) ntdll.RtlInterlockedFlushSList
|
||||||
@ stdcall InterlockedIncrement(ptr)
|
@ stdcall InterlockedIncrement(ptr)
|
||||||
# @ stub InterlockedPopEntrySList ( -> ntdll.RtlInterlockedPopEntrySList)
|
@ stdcall InterlockedPopEntrySList(ptr) ntdll.RtlInterlockedPopEntrySList
|
||||||
# @ stub InterlockedPushEntrySList ( -> ntdll.RtlInterlockedPushEntrySList)
|
@ stdcall InterlockedPushEntrySList(ptr ptr) ntdll.RtlInterlockedPushEntrySList
|
||||||
@ stub InvalidateConsoleDIBits
|
@ stub InvalidateConsoleDIBits
|
||||||
@ stdcall InvalidateNLSCache()
|
@ stdcall InvalidateNLSCache()
|
||||||
@ stdcall IsBadCodePtr(ptr)
|
@ stdcall IsBadCodePtr(ptr)
|
||||||
|
@ -843,7 +843,7 @@
|
||||||
@ stdcall PurgeComm(long long)
|
@ stdcall PurgeComm(long long)
|
||||||
@ stdcall -i386 -register QT_Thunk()
|
@ stdcall -i386 -register QT_Thunk()
|
||||||
@ stdcall QueryActCtxW(long ptr ptr long ptr long ptr)
|
@ stdcall QueryActCtxW(long ptr ptr long ptr long ptr)
|
||||||
# @ stub QueryDepthSList ( -> ntdll.RtlQueryDepthSList)
|
@ stdcall QueryDepthSList(ptr) ntdll.RtlQueryDepthSList
|
||||||
@ stdcall QueryDosDeviceA(str ptr long)
|
@ stdcall QueryDosDeviceA(str ptr long)
|
||||||
@ stdcall QueryDosDeviceW(wstr ptr long)
|
@ stdcall QueryDosDeviceW(wstr ptr long)
|
||||||
@ stub QueryInformationJobObject
|
@ stub QueryInformationJobObject
|
||||||
|
|
|
@ -152,8 +152,102 @@ static void test_mutex(void)
|
||||||
CloseHandle(hCreated);
|
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)
|
START_TEST(sync)
|
||||||
{
|
{
|
||||||
test_signalandwait();
|
test_signalandwait();
|
||||||
test_mutex();
|
test_mutex();
|
||||||
|
test_slist();
|
||||||
}
|
}
|
||||||
|
|
|
@ -592,7 +592,7 @@
|
||||||
@ stdcall RtlFindSetBits(ptr long long)
|
@ stdcall RtlFindSetBits(ptr long long)
|
||||||
@ stdcall RtlFindSetBitsAndClear(ptr long long)
|
@ stdcall RtlFindSetBitsAndClear(ptr long long)
|
||||||
@ stdcall RtlFindSetRuns(ptr ptr long long)
|
@ stdcall RtlFindSetRuns(ptr ptr long long)
|
||||||
@ stub RtlFirstEntrySList
|
@ stdcall RtlFirstEntrySList(ptr)
|
||||||
@ stdcall RtlFirstFreeAce(ptr ptr)
|
@ stdcall RtlFirstFreeAce(ptr ptr)
|
||||||
@ stub RtlFlushPropertySet
|
@ stub RtlFlushPropertySet
|
||||||
# @ stub RtlFlushSecureMemoryCache
|
# @ stub RtlFlushSecureMemoryCache
|
||||||
|
@ -670,7 +670,7 @@
|
||||||
@ stub RtlInitializeRXact
|
@ stub RtlInitializeRXact
|
||||||
# @ stub RtlInitializeRangeList
|
# @ stub RtlInitializeRangeList
|
||||||
@ stdcall RtlInitializeResource(ptr)
|
@ stdcall RtlInitializeResource(ptr)
|
||||||
# @ stub RtlInitializeSListHead
|
@ stdcall RtlInitializeSListHead(ptr)
|
||||||
@ stdcall RtlInitializeSid(ptr ptr long)
|
@ stdcall RtlInitializeSid(ptr ptr long)
|
||||||
# @ stub RtlInitializeStackTraceDataBase
|
# @ stub RtlInitializeStackTraceDataBase
|
||||||
@ stub RtlInsertElementGenericTable
|
@ stub RtlInsertElementGenericTable
|
||||||
|
@ -678,10 +678,10 @@
|
||||||
@ stdcall RtlInt64ToUnicodeString(double long ptr)
|
@ stdcall RtlInt64ToUnicodeString(double long ptr)
|
||||||
@ stdcall RtlIntegerToChar(long long long ptr)
|
@ stdcall RtlIntegerToChar(long long long ptr)
|
||||||
@ stdcall RtlIntegerToUnicodeString(long long ptr)
|
@ stdcall RtlIntegerToUnicodeString(long long ptr)
|
||||||
# @ stub RtlInterlockedFlushSList
|
@ stdcall RtlInterlockedFlushSList(ptr)
|
||||||
# @ stub RtlInterlockedPopEntrySList
|
@ stdcall RtlInterlockedPopEntrySList(ptr)
|
||||||
# @ stub RtlInterlockedPushEntrySList
|
@ stdcall RtlInterlockedPushEntrySList(ptr ptr)
|
||||||
# @ stub RtlInterlockedPushListSList
|
@ stdcall RtlInterlockedPushListSList(ptr ptr ptr long)
|
||||||
# @ stub RtlInvertRangeList
|
# @ stub RtlInvertRangeList
|
||||||
# @ stub RtlIpv4AddressToStringA
|
# @ stub RtlIpv4AddressToStringA
|
||||||
# @ stub RtlIpv4AddressToStringExA
|
# @ stub RtlIpv4AddressToStringExA
|
||||||
|
@ -763,7 +763,7 @@
|
||||||
@ stub RtlProtectHeap
|
@ stub RtlProtectHeap
|
||||||
# @ stub RtlPushFrame
|
# @ stub RtlPushFrame
|
||||||
@ stdcall RtlQueryAtomInAtomTable(ptr long ptr ptr ptr ptr)
|
@ stdcall RtlQueryAtomInAtomTable(ptr long ptr ptr ptr ptr)
|
||||||
@ stub RtlQueryDepthSList
|
@ stdcall RtlQueryDepthSList(ptr)
|
||||||
@ stdcall RtlQueryEnvironmentVariable_U(ptr ptr ptr)
|
@ stdcall RtlQueryEnvironmentVariable_U(ptr ptr ptr)
|
||||||
@ stub RtlQueryHeapInformation
|
@ stub RtlQueryHeapInformation
|
||||||
@ stdcall RtlQueryInformationAcl(ptr ptr long long)
|
@ stdcall RtlQueryInformationAcl(ptr ptr long long)
|
||||||
|
|
130
dlls/ntdll/rtl.c
130
dlls/ntdll/rtl.c
|
@ -35,6 +35,7 @@
|
||||||
#include "windef.h"
|
#include "windef.h"
|
||||||
#include "winternl.h"
|
#include "winternl.h"
|
||||||
#include "wine/debug.h"
|
#include "wine/debug.h"
|
||||||
|
#include "wine/exception.h"
|
||||||
#include "ntdll_misc.h"
|
#include "ntdll_misc.h"
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
|
WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
|
||||||
|
@ -922,3 +923,132 @@ PVOID WINAPI RtlDecodePointer( PVOID ptr )
|
||||||
DWORD_PTR ptrval = (DWORD_PTR) ptr;
|
DWORD_PTR ptrval = (DWORD_PTR) ptr;
|
||||||
return (PVOID)(ptrval ^ get_pointer_obfuscator());
|
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