From 07db8882c24281ca0acd8435d0e0b31a448ba59d Mon Sep 17 00:00:00 2001 From: Damjan Jovanovic Date: Fri, 2 Feb 2007 16:41:15 +0200 Subject: [PATCH] ntdll: Slist support. Implemented ntdll's RtlInitializeSListHead, RtlQueryDepthSList, RtlInterlockedFlushSList, RtlFirstEntrySList, RtlInterlockedPushEntrySList, RtlInterlockedPopEntrySList, their kernel32 equivalents, and tests. --- dlls/kernel32/kernel32.spec | 10 +-- dlls/kernel32/tests/sync.c | 94 ++++++++++++++++++++++++++ dlls/ntdll/ntdll.spec | 14 ++-- dlls/ntdll/rtl.c | 130 ++++++++++++++++++++++++++++++++++++ 4 files changed, 236 insertions(+), 12 deletions(-) diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index aac13728eec..ac340ff004d 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -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 diff --git a/dlls/kernel32/tests/sync.c b/dlls/kernel32/tests/sync.c index de387f7dea5..19c90672c40 100644 --- a/dlls/kernel32/tests/sync.c +++ b/dlls/kernel32/tests/sync.c @@ -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(); } diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index b3e3540c5af..827d98df1f7 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -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) diff --git a/dlls/ntdll/rtl.c b/dlls/ntdll/rtl.c index 449e91a89e7..605ec899229 100644 --- a/dlls/ntdll/rtl.c +++ b/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 +}