diff --git a/kmtests/CMakeLists.txt b/kmtests/CMakeLists.txt index a9487ea655d..93b5912c15d 100644 --- a/kmtests/CMakeLists.txt +++ b/kmtests/CMakeLists.txt @@ -22,6 +22,7 @@ list(APPEND KMTEST_DRV_SOURCE ntos_ex/ExInterlocked.c ntos_ex/ExPools.c ntos_ex/ExResource.c + ntos_ex/ExSequencedList.c ntos_ex/ExSingleList.c ntos_ex/ExTimer.c ntos_fsrtl/FsRtlExpression.c diff --git a/kmtests/kmtest_drv.rbuild b/kmtests/kmtest_drv.rbuild index f5464dc4e40..8993688dda9 100644 --- a/kmtests/kmtest_drv.rbuild +++ b/kmtests/kmtest_drv.rbuild @@ -21,6 +21,7 @@ ExInterlocked.c ExPools.c ExResource.c + ExSequencedList.c ExSingleList.c ExTimer.c diff --git a/kmtests/kmtest_drv/testlist.c b/kmtests/kmtest_drv/testlist.c index ed8c13e7fbe..3d92cc8028f 100644 --- a/kmtests/kmtest_drv/testlist.c +++ b/kmtests/kmtest_drv/testlist.c @@ -15,6 +15,7 @@ KMT_TESTFUNC Test_ExHardErrorInteractive; KMT_TESTFUNC Test_ExInterlocked; KMT_TESTFUNC Test_ExPools; KMT_TESTFUNC Test_ExResource; +KMT_TESTFUNC Test_ExSequencedList; KMT_TESTFUNC Test_ExSingleList; KMT_TESTFUNC Test_ExTimer; KMT_TESTFUNC Test_FsRtlExpression; @@ -43,6 +44,7 @@ const KMT_TEST TestList[] = { "ExInterlocked", Test_ExInterlocked }, { "ExPools", Test_ExPools }, { "ExResource", Test_ExResource }, + { "ExSequencedList", Test_ExSequencedList }, { "ExSingleList", Test_ExSingleList }, { "ExTimer", Test_ExTimer }, { "Example", Test_Example }, diff --git a/kmtests/ntos_ex/ExSequencedList.c b/kmtests/ntos_ex/ExSequencedList.c new file mode 100644 index 00000000000..1fad7614fdd --- /dev/null +++ b/kmtests/ntos_ex/ExSequencedList.c @@ -0,0 +1,79 @@ +/* + * PROJECT: ReactOS kernel-mode tests + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Kernel-Mode Test Suite sequenced singly-linked list test + * PROGRAMMER: Thomas Faber + */ + +struct _SINGLE_LIST_ENTRY; +union _SLIST_HEADER; +struct _SINGLE_LIST_ENTRY *__fastcall ExInterlockedPushEntrySList(union _SLIST_HEADER *, struct _SINGLE_LIST_ENTRY *, unsigned long *); +struct _SINGLE_LIST_ENTRY *__fastcall ExInterlockedPopEntrySList(union _SLIST_HEADER *, unsigned long *); + +#include + +/* TODO: SLIST_HEADER is a lot different for x64 */ + +#define CheckSListHeader(ListHead, ExpectedPointer, ExpectedDepth) do \ +{ \ + ok_eq_pointer((ListHead)->Next.Next, ExpectedPointer); \ + /*ok_eq_pointer(FirstEntrySList(ListHead), ExpectedPointer);*/ \ + ok_eq_uint((ListHead)->Depth, ExpectedDepth); \ + ok_eq_uint((ListHead)->Sequence, ExpectedSequence); \ + ok_eq_uint(ExQueryDepthSList(ListHead), ExpectedDepth); \ + ok_irql(HIGH_LEVEL); \ + ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:"); \ +} while (0) + +#define PXLIST_HEADER PSLIST_HEADER +#define PXLIST_ENTRY PSLIST_ENTRY +#define PushXList ExInterlockedPushEntrySList +#define PopXList ExInterlockedPopEntrySList +#define FlushXList ExInterlockedFlushSList +#define ok_free_xlist ok_eq_pointer +#define CheckXListHeader CheckSListHeader +#define TestXListFunctional TestSListFunctional +#include "ExXList.h" + +#undef ExInterlockedPushEntrySList +#undef ExInterlockedPopEntrySList +#define TestXListFunctional TestSListFunctionalExports +#include "ExXList.h" + +START_TEST(ExSequencedList) +{ + PSLIST_HEADER ListHead; + KSPIN_LOCK SpinLock; + USHORT ExpectedSequence = 0; + PKSPIN_LOCK pSpinLock = &SpinLock; + PCHAR Buffer; + PSLIST_ENTRY Entries; + SIZE_T EntriesSize = 5 * sizeof *Entries; + KIRQL Irql; + + KeInitializeSpinLock(&SpinLock); +#ifdef _M_IX86 + pSpinLock = NULL; +#endif + + /* make sure stuff is as un-aligned as possible ;) */ + Buffer = ExAllocatePoolWithTag(NonPagedPool, sizeof *ListHead + EntriesSize + 1, 'TLqS'); + ListHead = (PVOID)&Buffer[1]; + Entries = (PVOID)&ListHead[1]; + KeRaiseIrql(HIGH_LEVEL, &Irql); + + RtlFillMemory(Entries, EntriesSize, 0x55); + RtlFillMemory(ListHead, sizeof *ListHead, 0x55); + InitializeSListHead(ListHead); + CheckSListHeader(ListHead, NULL, 0); + TestSListFunctional(ListHead, Entries, pSpinLock); + + RtlFillMemory(Entries, EntriesSize, 0x55); + RtlFillMemory(ListHead, sizeof *ListHead, 0x55); + ExInitializeSListHead(ListHead); + CheckSListHeader(ListHead, NULL, 0); + TestSListFunctionalExports(ListHead, Entries, pSpinLock); + + KeLowerIrql(Irql); + ExFreePoolWithTag(Buffer, 'TLqS'); +} diff --git a/kmtests/ntos_ex/ExSingleList.c b/kmtests/ntos_ex/ExSingleList.c index ebce09a9d15..cebf2652a27 100644 --- a/kmtests/ntos_ex/ExSingleList.c +++ b/kmtests/ntos_ex/ExSingleList.c @@ -11,8 +11,6 @@ struct _SINGLE_LIST_ENTRY *__stdcall ExInterlockedPopEntryList(struct _SINGLE_LI #include -SINGLE_LIST_ENTRY Entries[5]; - #define ok_eq_free2(Value, Expected) do \ { \ if (KmtIsCheckedBuild) \ @@ -21,107 +19,94 @@ SINGLE_LIST_ENTRY Entries[5]; ok_eq_pointer(Value, Expected); \ } while (0) -START_TEST(ExSingleList) +PSINGLE_LIST_ENTRY FlushList(PSINGLE_LIST_ENTRY ListHead) +{ + PSINGLE_LIST_ENTRY Ret = ListHead->Next; + ListHead->Next = NULL; + return Ret; +} + +USHORT QueryDepthList(PSINGLE_LIST_ENTRY ListHead) +{ + USHORT Depth = 0; + while (ListHead->Next) + { + ++Depth; + ListHead = ListHead->Next; + } + return Depth; +} + +PSINGLE_LIST_ENTRY PushEntryListWrapper(PSINGLE_LIST_ENTRY ListHead, PSINGLE_LIST_ENTRY Entry, PKSPIN_LOCK Lock) { - KSPIN_LOCK SpinLock; - SINGLE_LIST_ENTRY ListHead; PSINGLE_LIST_ENTRY Ret; + UNREFERENCED_PARAMETER(Lock); + Ret = ListHead->Next; + PushEntryList(ListHead, Entry); + return Ret; +} - KeInitializeSpinLock(&SpinLock); +#define CheckListHeader(ListHead, ExpectedPointer, ExpectedDepth) do \ +{ \ + ok_eq_pointer((ListHead)->Next, ExpectedPointer); \ + ok_eq_uint(QueryDepthList(ListHead), ExpectedDepth); \ + ok_irql(HIGH_LEVEL); \ + ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:"); \ +} while (0) - memset(Entries, 0x55, sizeof Entries); - ListHead.Next = NULL; - Ret = ExInterlockedPushEntryList(&ListHead, &Entries[0], &SpinLock); - ok_eq_pointer(Ret, NULL); - ok_eq_pointer(ListHead.Next, &Entries[0]); - ok_eq_pointer(Entries[0].Next, NULL); - ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:"); - ok_irql(PASSIVE_LEVEL); - - Ret = ExInterlockedPopEntryList(&ListHead, &SpinLock); - ok_eq_pointer(Ret, &Entries[0]); - ok_eq_pointer(ListHead.Next, NULL); - ok_eq_free2(Entries[0].Next, NULL); - ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:"); - ok_irql(PASSIVE_LEVEL); - - Ret = ExInterlockedPopEntryList(&ListHead, &SpinLock); - ok_eq_pointer(Ret, NULL); - ok_eq_pointer(ListHead.Next, NULL); - ok_eq_free2(Entries[0].Next, NULL); - ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:"); - ok_irql(PASSIVE_LEVEL); - - Ret = ExInterlockedPushEntryList(&ListHead, &Entries[0], &SpinLock); - ok_eq_pointer(Ret, NULL); - ok_eq_pointer(ListHead.Next, &Entries[0]); - ok_eq_pointer(Entries[0].Next, NULL); - ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:"); - ok_irql(PASSIVE_LEVEL); - - Ret = ExInterlockedPushEntryList(&ListHead, &Entries[1], &SpinLock); - ok_eq_pointer(Ret, &Entries[0]); - ok_eq_pointer(ListHead.Next, &Entries[1]); - ok_eq_pointer(Entries[1].Next, &Entries[0]); - ok_eq_pointer(Entries[0].Next, NULL); - ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:"); - ok_irql(PASSIVE_LEVEL); - - Ret = ExInterlockedPopEntryList(&ListHead, &SpinLock); - ok_eq_pointer(Ret, &Entries[1]); - ok_eq_pointer(ListHead.Next, &Entries[0]); - ok_eq_free2(Entries[1].Next, &Entries[0]); - ok_eq_pointer(Entries[0].Next, NULL); - ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:"); - ok_irql(PASSIVE_LEVEL); +#define PXLIST_HEADER PSINGLE_LIST_ENTRY +#define PXLIST_ENTRY PSINGLE_LIST_ENTRY +#define PushXList ExInterlockedPushEntryList +#define PopXList ExInterlockedPopEntryList +#define FlushXList FlushList +#define ok_free_xlist ok_eq_free2 +#define CheckXListHeader CheckListHeader +#define TestXListFunctional TestListFunctional +#include "ExXList.h" #undef ExInterlockedPushEntryList #undef ExInterlockedPopEntryList - memset(Entries, 0x55, sizeof Entries); - ListHead.Next = NULL; - Ret = ExInterlockedPushEntryList(&ListHead, &Entries[0], &SpinLock); - ok_eq_pointer(Ret, NULL); - ok_eq_pointer(ListHead.Next, &Entries[0]); - ok_eq_pointer(Entries[0].Next, NULL); - ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:"); - ok_irql(PASSIVE_LEVEL); +#define TestXListFunctional TestListFunctionalExports +#include "ExXList.h" - Ret = ExInterlockedPopEntryList(&ListHead, &SpinLock); - ok_eq_pointer(Ret, &Entries[0]); - ok_eq_pointer(ListHead.Next, NULL); - ok_eq_free2(Entries[0].Next, NULL); - ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:"); - ok_irql(PASSIVE_LEVEL); +#undef PushXList +#define PushXList PushEntryListWrapper +#undef PopXList +#define PopXList(h, s) PopEntryList(h) +#undef ok_free_xlist +#define ok_free_xlist ok_eq_pointer +#define TestXListFunctional TestListFunctionalNoInterlocked +#include "ExXList.h" - Ret = ExInterlockedPopEntryList(&ListHead, &SpinLock); - ok_eq_pointer(Ret, NULL); - ok_eq_pointer(ListHead.Next, NULL); - ok_eq_free2(Entries[0].Next, NULL); - ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:"); - ok_irql(PASSIVE_LEVEL); +START_TEST(ExSingleList) +{ + KSPIN_LOCK SpinLock; + PSINGLE_LIST_ENTRY ListHead; + PSINGLE_LIST_ENTRY Entries; + SIZE_T EntriesSize = 5 * sizeof *Entries; + PCHAR Buffer; + KIRQL Irql; - Ret = ExInterlockedPushEntryList(&ListHead, &Entries[0], &SpinLock); - ok_eq_pointer(Ret, NULL); - ok_eq_pointer(ListHead.Next, &Entries[0]); - ok_eq_pointer(Entries[0].Next, NULL); - ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:"); - ok_irql(PASSIVE_LEVEL); + KeInitializeSpinLock(&SpinLock); - Ret = ExInterlockedPushEntryList(&ListHead, &Entries[1], &SpinLock); - ok_eq_pointer(Ret, &Entries[0]); - ok_eq_pointer(ListHead.Next, &Entries[1]); - ok_eq_pointer(Entries[1].Next, &Entries[0]); - ok_eq_pointer(Entries[0].Next, NULL); - ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:"); - ok_irql(PASSIVE_LEVEL); + /* make sure stuff is as un-aligned as possible ;) */ + Buffer = ExAllocatePoolWithTag(NonPagedPool, sizeof *ListHead + EntriesSize + 1, 'TLiS'); + ListHead = (PVOID)&Buffer[1]; + Entries = (PVOID)&ListHead[1]; + KeRaiseIrql(HIGH_LEVEL, &Irql); + + RtlFillMemory(Entries, sizeof Entries, 0x55); + ListHead->Next = NULL; + TestListFunctional(ListHead, Entries, &SpinLock); - Ret = ExInterlockedPopEntryList(&ListHead, &SpinLock); - ok_eq_pointer(Ret, &Entries[1]); - ok_eq_pointer(ListHead.Next, &Entries[0]); - ok_eq_free2(Entries[1].Next, &Entries[0]); - ok_eq_pointer(Entries[0].Next, NULL); - ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:"); - ok_irql(PASSIVE_LEVEL); - - KmtSetIrql(PASSIVE_LEVEL); + RtlFillMemory(Entries, sizeof Entries, 0x55); + ListHead->Next = NULL; + TestListFunctionalExports(ListHead, Entries, &SpinLock); + + RtlFillMemory(Entries, sizeof Entries, 0x55); + ListHead->Next = NULL; + TestListFunctionalNoInterlocked(ListHead, Entries, &SpinLock); + + KeLowerIrql(Irql); + ExFreePoolWithTag(Buffer, 'TLiS'); } diff --git a/kmtests/ntos_ex/ExXList.h b/kmtests/ntos_ex/ExXList.h new file mode 100644 index 00000000000..f5928c92990 --- /dev/null +++ b/kmtests/ntos_ex/ExXList.h @@ -0,0 +1,91 @@ +/* used by ExSingleList and ExSequencedList tests */ +static +VOID +TestXListFunctional( + IN PXLIST_HEADER ListHead, + IN PXLIST_ENTRY Entries, + IN PKSPIN_LOCK pSpinLock) +{ + USHORT ExpectedSequence = 0; + PXLIST_ENTRY Ret; + + Ret = FlushXList(ListHead); + ok_eq_pointer(Ret, NULL); + CheckXListHeader(ListHead, NULL, 0); + + Ret = PopXList(ListHead, pSpinLock); + ok_eq_pointer(Ret, NULL); + CheckXListHeader(ListHead, NULL, 0); + + Ret = PushXList(ListHead, &Entries[0], pSpinLock); + ++ExpectedSequence; + ok_eq_pointer(Ret, NULL); + ok_eq_pointer(Entries[0].Next, NULL); + CheckXListHeader(ListHead, &Entries[0], 1); + + Ret = PushXList(ListHead, &Entries[1], pSpinLock); + ++ExpectedSequence; + ok_eq_pointer(Ret, &Entries[0]); + ok_eq_pointer(Entries[0].Next, NULL); + ok_eq_pointer(Entries[1].Next, &Entries[0]); + CheckXListHeader(ListHead, &Entries[1], 2); + + Ret = PopXList(ListHead, pSpinLock); + ok_eq_pointer(Ret, &Entries[1]); + ok_eq_pointer(Entries[0].Next, NULL); + ok_free_xlist(Entries[1].Next, &Entries[0]); + CheckXListHeader(ListHead, &Entries[0], 1); + + Ret = PopXList(ListHead, pSpinLock); + ok_eq_pointer(Ret, &Entries[0]); + ok_free_xlist(Entries[0].Next, NULL); + ok_free_xlist(Entries[1].Next, &Entries[0]); + CheckXListHeader(ListHead, NULL, 0); + + Ret = PopXList(ListHead, pSpinLock); + ok_eq_pointer(Ret, NULL); + ok_free_xlist(Entries[0].Next, NULL); + ok_free_xlist(Entries[1].Next, &Entries[0]); + CheckXListHeader(ListHead, NULL, 0); + + /* add entries again */ + Ret = PushXList(ListHead, &Entries[0], pSpinLock); + ++ExpectedSequence; + ok_eq_pointer(Ret, NULL); + ok_eq_pointer(Entries[0].Next, NULL); + CheckXListHeader(ListHead, &Entries[0], 1); + + Ret = PushXList(ListHead, &Entries[1], pSpinLock); + ++ExpectedSequence; + ok_eq_pointer(Ret, &Entries[0]); + ok_eq_pointer(Entries[0].Next, NULL); + ok_eq_pointer(Entries[1].Next, &Entries[0]); + CheckXListHeader(ListHead, &Entries[1], 2); + + Ret = PopXList(ListHead, pSpinLock); + ok_eq_pointer(Ret, &Entries[1]); + ok_eq_pointer(Entries[0].Next, NULL); + ok_free_xlist(Entries[1].Next, &Entries[0]); + CheckXListHeader(ListHead, &Entries[0], 1); + + Ret = PushXList(ListHead, &Entries[1], pSpinLock); + ++ExpectedSequence; + ok_eq_pointer(Ret, &Entries[0]); + ok_eq_pointer(Entries[0].Next, NULL); + ok_eq_pointer(Entries[1].Next, &Entries[0]); + CheckXListHeader(ListHead, &Entries[1], 2); + + Ret = PushXList(ListHead, &Entries[2], pSpinLock); + ++ExpectedSequence; + ok_eq_pointer(Ret, &Entries[1]); + ok_eq_pointer(Entries[0].Next, NULL); + ok_eq_pointer(Entries[1].Next, &Entries[0]); + ok_eq_pointer(Entries[2].Next, &Entries[1]); + CheckXListHeader(ListHead, &Entries[2], 3); + + Ret = FlushXList(ListHead); + ok_eq_pointer(Ret, &Entries[2]); + CheckXListHeader(ListHead, NULL, 0); +} + +#undef TestXListFunctional