diff --git a/kmtests/CMakeLists.txt b/kmtests/CMakeLists.txt
index b32e0dab20b..00f2fe36864 100644
--- a/kmtests/CMakeLists.txt
+++ b/kmtests/CMakeLists.txt
@@ -15,10 +15,12 @@ list(APPEND KMTEST_DRV_SOURCE
example/Example.c
example/KernelType.c
+ ntos_ex/ExDoubleList.c
ntos_ex/ExHardError.c
ntos_ex/ExInterlocked.c
ntos_ex/ExPools.c
ntos_ex/ExResource.c
+ ntos_ex/ExSingleList.c
ntos_ex/ExTimer.c
ntos_fsrtl/FsRtlExpression.c
ntos_io/IoDeviceInterface.c
diff --git a/kmtests/kmtest_drv.rbuild b/kmtests/kmtest_drv.rbuild
index ad76a2d9f19..7cb01ca29ef 100644
--- a/kmtests/kmtest_drv.rbuild
+++ b/kmtests/kmtest_drv.rbuild
@@ -15,10 +15,12 @@
KernelType.c
+ ExDoubleList.c
ExHardError.c
ExInterlocked.c
ExPools.c
ExResource.c
+ ExSingleList.c
ExTimer.c
diff --git a/kmtests/kmtest_drv/testlist.c b/kmtests/kmtest_drv/testlist.c
index 3e90a7e29ba..65e6a610c21 100644
--- a/kmtests/kmtest_drv/testlist.c
+++ b/kmtests/kmtest_drv/testlist.c
@@ -9,11 +9,13 @@
#include
KMT_TESTFUNC Test_Example;
+KMT_TESTFUNC Test_ExDoubleList;
KMT_TESTFUNC Test_ExHardError;
KMT_TESTFUNC Test_ExHardErrorInteractive;
KMT_TESTFUNC Test_ExInterlocked;
KMT_TESTFUNC Test_ExPools;
KMT_TESTFUNC Test_ExResource;
+KMT_TESTFUNC Test_ExSingleList;
KMT_TESTFUNC Test_ExTimer;
KMT_TESTFUNC Test_FsRtlExpression;
KMT_TESTFUNC Test_IoDeviceInterface;
@@ -28,11 +30,13 @@ KMT_TESTFUNC Test_ObCreate;
const KMT_TEST TestList[] =
{
+ { "ExDoubleList", Test_ExDoubleList },
{ "ExHardError", Test_ExHardError },
{ "-ExHardErrorInteractive", Test_ExHardErrorInteractive },
{ "ExInterlocked", Test_ExInterlocked },
{ "ExPools", Test_ExPools },
{ "ExResource", Test_ExResource },
+ { "ExSingleList", Test_ExSingleList },
{ "ExTimer", Test_ExTimer },
{ "Example", Test_Example },
{ "FsRtlExpression", Test_FsRtlExpression },
diff --git a/kmtests/ntos_ex/ExDoubleList.c b/kmtests/ntos_ex/ExDoubleList.c
new file mode 100644
index 00000000000..f582257a4ac
--- /dev/null
+++ b/kmtests/ntos_ex/ExDoubleList.c
@@ -0,0 +1,210 @@
+/*
+ * PROJECT: ReactOS kernel-mode tests
+ * LICENSE: GPLv2+ - See COPYING in the top level directory
+ * PURPOSE: Kernel-Mode Test Suite Doubly-linked list test
+ * PROGRAMMER: Thomas Faber
+ */
+
+struct _LIST_ENTRY;
+struct _LIST_ENTRY *__stdcall ExInterlockedInsertHeadList(struct _LIST_ENTRY *, struct _LIST_ENTRY *, unsigned long *);
+struct _LIST_ENTRY *__stdcall ExInterlockedInsertTailList(struct _LIST_ENTRY *, struct _LIST_ENTRY *, unsigned long *);
+struct _LIST_ENTRY *__stdcall ExInterlockedRemoveHeadList(struct _LIST_ENTRY *, unsigned long *);
+
+#include
+#include
+
+LIST_ENTRY Entries[5];
+
+#define ok_eq_free(Value, Expected) do \
+{ \
+ if (KmtIsCheckedBuild) \
+ ok_eq_pointer(Value, (PVOID)0x0BADD0FF); \
+ else \
+ ok_eq_pointer(Value, Expected); \
+} while (0)
+
+#define ok_eq_free2(Value, Expected) do \
+{ \
+ if (KmtIsCheckedBuild) \
+ ok_eq_pointer(Value, (PVOID)0xBADDD0FF); \
+ else \
+ ok_eq_pointer(Value, Expected); \
+} while (0)
+
+START_TEST(ExDoubleList)
+{
+ KSPIN_LOCK SpinLock;
+ LIST_ENTRY ListHead;
+ PLIST_ENTRY Ret;
+
+ KeInitializeSpinLock(&SpinLock);
+
+ memset(&ListHead, 0x55, sizeof ListHead);
+ InitializeListHead(&ListHead);
+ ok_eq_pointer(ListHead.Flink, &ListHead);
+ ok_eq_pointer(ListHead.Blink, &ListHead);
+ ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+ ok_irql(PASSIVE_LEVEL);
+
+ Ret = ExInterlockedInsertHeadList(&ListHead, &Entries[0], &SpinLock);
+ ok_eq_pointer(Ret, NULL);
+ ok_eq_pointer(ListHead.Flink, &Entries[0]);
+ ok_eq_pointer(ListHead.Blink, &Entries[0]);
+ ok_eq_pointer(Entries[0].Flink, &ListHead);
+ ok_eq_pointer(Entries[0].Blink, &ListHead);
+ ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+ ok_irql(PASSIVE_LEVEL);
+
+ Ret = ExInterlockedRemoveHeadList(&ListHead, &SpinLock);
+ ok_eq_pointer(Ret, &Entries[0]);
+ ok_eq_pointer(ListHead.Flink, &ListHead);
+ ok_eq_pointer(ListHead.Blink, &ListHead);
+ ok_eq_free(Entries[0].Flink, &ListHead);
+ ok_eq_free(Entries[0].Blink, &ListHead);
+ ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+ ok_irql(PASSIVE_LEVEL);
+
+ Ret = ExInterlockedRemoveHeadList(&ListHead, &SpinLock);
+ ok_eq_pointer(Ret, NULL);
+ ok_eq_pointer(ListHead.Flink, &ListHead);
+ ok_eq_pointer(ListHead.Blink, &ListHead);
+ ok_eq_free(Entries[0].Flink, &ListHead);
+ ok_eq_free(Entries[0].Blink, &ListHead);
+ ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+ ok_irql(PASSIVE_LEVEL);
+
+ Ret = ExInterlockedInsertTailList(&ListHead, &Entries[0], &SpinLock);
+ ok_eq_pointer(Ret, NULL);
+ ok_eq_pointer(ListHead.Flink, &Entries[0]);
+ ok_eq_pointer(ListHead.Blink, &Entries[0]);
+ ok_eq_pointer(Entries[0].Flink, &ListHead);
+ ok_eq_pointer(Entries[0].Blink, &ListHead);
+ ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+ ok_irql(PASSIVE_LEVEL);
+
+ Ret = ExInterlockedRemoveHeadList(&ListHead, &SpinLock);
+ ok_eq_pointer(Ret, &Entries[0]);
+ ok_eq_pointer(ListHead.Flink, &ListHead);
+ ok_eq_pointer(ListHead.Blink, &ListHead);
+ ok_eq_free(Entries[0].Flink, &ListHead);
+ ok_eq_free(Entries[0].Blink, &ListHead);
+ ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+ ok_irql(PASSIVE_LEVEL);
+
+ Ret = ExInterlockedRemoveHeadList(&ListHead, &SpinLock);
+ ok_eq_pointer(Ret, NULL);
+ ok_eq_pointer(ListHead.Flink, &ListHead);
+ ok_eq_pointer(ListHead.Blink, &ListHead);
+ ok_eq_free(Entries[0].Flink, &ListHead);
+ ok_eq_free(Entries[0].Blink, &ListHead);
+ ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+ ok_irql(PASSIVE_LEVEL);
+
+ Ret = ExInterlockedInsertTailList(&ListHead, &Entries[0], &SpinLock);
+ ok_eq_pointer(Ret, NULL);
+ ok_eq_pointer(ListHead.Flink, &Entries[0]);
+ ok_eq_pointer(ListHead.Blink, &Entries[0]);
+ ok_eq_pointer(Entries[0].Flink, &ListHead);
+ ok_eq_pointer(Entries[0].Blink, &ListHead);
+ ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+ ok_irql(PASSIVE_LEVEL);
+
+ Ret = ExInterlockedInsertHeadList(&ListHead, &Entries[1], &SpinLock);
+ ok_eq_pointer(Ret, &Entries[0]);
+ ok_eq_pointer(ListHead.Flink, &Entries[1]);
+ ok_eq_pointer(ListHead.Blink, &Entries[0]);
+ ok_eq_pointer(Entries[0].Flink, &ListHead);
+ ok_eq_pointer(Entries[0].Blink, &Entries[1]);
+ ok_eq_pointer(Entries[1].Flink, &Entries[0]);
+ ok_eq_pointer(Entries[1].Blink, &ListHead);
+ ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+ ok_irql(PASSIVE_LEVEL);
+
+ memset(Entries, 0x55, sizeof Entries);
+#undef ExInterlockedInsertHeadList
+#undef ExInterlockedInsertTailList
+#undef ExInterlockedRemoveHeadList
+
+ memset(&ListHead, 0x55, sizeof ListHead);
+ InitializeListHead(&ListHead);
+ ok_eq_pointer(ListHead.Flink, &ListHead);
+ ok_eq_pointer(ListHead.Blink, &ListHead);
+ ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+ ok_irql(PASSIVE_LEVEL);
+
+ Ret = ExInterlockedInsertHeadList(&ListHead, &Entries[0], &SpinLock);
+ ok_eq_pointer(Ret, NULL);
+ ok_eq_pointer(ListHead.Flink, &Entries[0]);
+ ok_eq_pointer(ListHead.Blink, &Entries[0]);
+ ok_eq_pointer(Entries[0].Flink, &ListHead);
+ ok_eq_pointer(Entries[0].Blink, &ListHead);
+ ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+ ok_irql(PASSIVE_LEVEL);
+
+ Ret = ExInterlockedRemoveHeadList(&ListHead, &SpinLock);
+ ok_eq_pointer(Ret, &Entries[0]);
+ ok_eq_pointer(ListHead.Flink, &ListHead);
+ ok_eq_pointer(ListHead.Blink, &ListHead);
+ ok_eq_free2(Entries[0].Flink, &ListHead);
+ ok_eq_free2(Entries[0].Blink, &ListHead);
+ ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+ ok_irql(PASSIVE_LEVEL);
+
+ Ret = ExInterlockedRemoveHeadList(&ListHead, &SpinLock);
+ ok_eq_pointer(Ret, NULL);
+ ok_eq_pointer(ListHead.Flink, &ListHead);
+ ok_eq_pointer(ListHead.Blink, &ListHead);
+ ok_eq_free2(Entries[0].Flink, &ListHead);
+ ok_eq_free2(Entries[0].Blink, &ListHead);
+ ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+ ok_irql(PASSIVE_LEVEL);
+
+ Ret = ExInterlockedInsertTailList(&ListHead, &Entries[0], &SpinLock);
+ ok_eq_pointer(Ret, NULL);
+ ok_eq_pointer(ListHead.Flink, &Entries[0]);
+ ok_eq_pointer(ListHead.Blink, &Entries[0]);
+ ok_eq_pointer(Entries[0].Flink, &ListHead);
+ ok_eq_pointer(Entries[0].Blink, &ListHead);
+ ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+ ok_irql(PASSIVE_LEVEL);
+
+ Ret = ExInterlockedRemoveHeadList(&ListHead, &SpinLock);
+ ok_eq_pointer(Ret, &Entries[0]);
+ ok_eq_pointer(ListHead.Flink, &ListHead);
+ ok_eq_pointer(ListHead.Blink, &ListHead);
+ ok_eq_free2(Entries[0].Flink, &ListHead);
+ ok_eq_free2(Entries[0].Blink, &ListHead);
+ ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+ ok_irql(PASSIVE_LEVEL);
+
+ Ret = ExInterlockedRemoveHeadList(&ListHead, &SpinLock);
+ ok_eq_pointer(Ret, NULL);
+ ok_eq_pointer(ListHead.Flink, &ListHead);
+ ok_eq_pointer(ListHead.Blink, &ListHead);
+ ok_eq_free2(Entries[0].Flink, &ListHead);
+ ok_eq_free2(Entries[0].Blink, &ListHead);
+ ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+ ok_irql(PASSIVE_LEVEL);
+
+ Ret = ExInterlockedInsertTailList(&ListHead, &Entries[0], &SpinLock);
+ ok_eq_pointer(Ret, NULL);
+ ok_eq_pointer(ListHead.Flink, &Entries[0]);
+ ok_eq_pointer(ListHead.Blink, &Entries[0]);
+ ok_eq_pointer(Entries[0].Flink, &ListHead);
+ ok_eq_pointer(Entries[0].Blink, &ListHead);
+ ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+ ok_irql(PASSIVE_LEVEL);
+
+ Ret = ExInterlockedInsertHeadList(&ListHead, &Entries[1], &SpinLock);
+ ok_eq_pointer(Ret, &Entries[0]);
+ ok_eq_pointer(ListHead.Flink, &Entries[1]);
+ ok_eq_pointer(ListHead.Blink, &Entries[0]);
+ ok_eq_pointer(Entries[0].Flink, &ListHead);
+ ok_eq_pointer(Entries[0].Blink, &Entries[1]);
+ ok_eq_pointer(Entries[1].Flink, &Entries[0]);
+ ok_eq_pointer(Entries[1].Blink, &ListHead);
+ ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");
+ ok_irql(PASSIVE_LEVEL);
+
+ KmtSetIrql(PASSIVE_LEVEL);
+}
diff --git a/kmtests/ntos_ex/ExSingleList.c b/kmtests/ntos_ex/ExSingleList.c
new file mode 100644
index 00000000000..b4b4b3ef4ad
--- /dev/null
+++ b/kmtests/ntos_ex/ExSingleList.c
@@ -0,0 +1,128 @@
+/*
+ * PROJECT: ReactOS kernel-mode tests
+ * LICENSE: GPLv2+ - See COPYING in the top level directory
+ * PURPOSE: Kernel-Mode Test Suite Singly-linked list test
+ * PROGRAMMER: Thomas Faber
+ */
+
+struct _SINGLE_LIST_ENTRY;
+struct _SINGLE_LIST_ENTRY *__stdcall ExInterlockedPushEntryList(struct _SINGLE_LIST_ENTRY *, struct _SINGLE_LIST_ENTRY *, unsigned long *);
+struct _SINGLE_LIST_ENTRY *__stdcall ExInterlockedPopEntryList(struct _SINGLE_LIST_ENTRY *, unsigned long *);
+
+#include
+#include
+
+SINGLE_LIST_ENTRY Entries[5];
+
+#define ok_eq_free2(Value, Expected) do \
+{ \
+ if (KmtIsCheckedBuild) \
+ ok_eq_pointer(Value, (PVOID)0xBADDD0FF); \
+ else \
+ ok_eq_pointer(Value, Expected); \
+} while (0)
+
+START_TEST(ExSingleList)
+{
+ KSPIN_LOCK SpinLock;
+ SINGLE_LIST_ENTRY ListHead;
+ PSINGLE_LIST_ENTRY Ret;
+
+ KeInitializeSpinLock(&SpinLock);
+
+ 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);
+
+#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);
+
+ 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);
+
+ KmtSetIrql(PASSIVE_LEVEL);
+}