1 /*
2  * PROJECT:         ReactOS kernel-mode tests
3  * LICENSE:         GPLv2+ - See COPYING in the top level directory
4  * PURPOSE:         Kernel-Mode Test Suite Singly-linked list test
5  * PROGRAMMER:      Thomas Faber <thomas.faber@reactos.org>
6  */
7 
8 struct _SINGLE_LIST_ENTRY;
9 #ifdef _X86_
10 struct _SINGLE_LIST_ENTRY *__stdcall ExInterlockedPushEntryList(struct _SINGLE_LIST_ENTRY *, struct _SINGLE_LIST_ENTRY *, unsigned long *);
11 struct _SINGLE_LIST_ENTRY *__stdcall ExInterlockedPopEntryList(struct _SINGLE_LIST_ENTRY *, unsigned long *);
12 #endif
13 
14 #include <kmt_test.h>
15 
16 #define ok_eq_free2(Value, Expected) do              \
17 {                                                   \
18     if (KmtIsCheckedBuild)                          \
19         ok_eq_pointer(Value, (PVOID)(ULONG_PTR)0xBADDD0FFBADDD0FFULL);    \
20     else                                            \
21         ok_eq_pointer(Value, Expected);             \
22 } while (0)
23 
24 PSINGLE_LIST_ENTRY FlushList(PSINGLE_LIST_ENTRY ListHead)
25 {
26     PSINGLE_LIST_ENTRY Ret = ListHead->Next;
27     ListHead->Next = NULL;
28     return Ret;
29 }
30 
31 USHORT QueryDepthList(PSINGLE_LIST_ENTRY ListHead)
32 {
33     USHORT Depth = 0;
34     while (ListHead->Next)
35     {
36         ++Depth;
37         ListHead = ListHead->Next;
38     }
39     return Depth;
40 }
41 
42 PSINGLE_LIST_ENTRY PushEntryListWrapper(PSINGLE_LIST_ENTRY ListHead, PSINGLE_LIST_ENTRY Entry, PKSPIN_LOCK Lock)
43 {
44     PSINGLE_LIST_ENTRY Ret;
45     UNREFERENCED_PARAMETER(Lock);
46     Ret = ListHead->Next;
47     PushEntryList(ListHead, Entry);
48     return Ret;
49 }
50 
51 #define CheckListHeader(ListHead, ExpectedPointer, ExpectedDepth) do    \
52 {                                                                       \
53     ok_eq_pointer((ListHead)->Next, ExpectedPointer);                   \
54     ok_eq_uint(QueryDepthList(ListHead), ExpectedDepth);                \
55     ok_irql(HIGH_LEVEL);                                                \
56     ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");     \
57 } while (0)
58 
59 #define PXLIST_HEADER       PSINGLE_LIST_ENTRY
60 #define PXLIST_ENTRY        PSINGLE_LIST_ENTRY
61 #define PushXList           ExInterlockedPushEntryList
62 #define PopXList            ExInterlockedPopEntryList
63 #define FlushXList          FlushList
64 #define ok_free_xlist       ok_eq_free2
65 #define CheckXListHeader    CheckListHeader
66 #define TestXListFunctional TestListFunctional
67 #include "ExXList.h"
68 
69 #undef ExInterlockedPushEntryList
70 #undef ExInterlockedPopEntryList
71 #define TestXListFunctional TestListFunctionalExports
72 #include "ExXList.h"
73 
74 #undef  PushXList
75 #define PushXList           PushEntryListWrapper
76 #undef  PopXList
77 #define PopXList(h, s)      PopEntryList(h)
78 #undef  ok_free_xlist
79 #define ok_free_xlist       ok_eq_pointer
80 #define TestXListFunctional TestListFunctionalNoInterlocked
81 #include "ExXList.h"
82 
83 START_TEST(ExSingleList)
84 {
85     KSPIN_LOCK SpinLock;
86     PSINGLE_LIST_ENTRY ListHead;
87     PSINGLE_LIST_ENTRY Entries;
88     SIZE_T EntriesSize = 5 * sizeof *Entries;
89     PCHAR Buffer;
90     KIRQL Irql;
91 
92     KeInitializeSpinLock(&SpinLock);
93 
94     /* make sure stuff is as un-aligned as possible ;) */
95     Buffer = ExAllocatePoolWithTag(NonPagedPool, sizeof *ListHead + EntriesSize + 1, 'TLiS');
96     ListHead = (PVOID)&Buffer[1];
97     Entries = (PVOID)&ListHead[1];
98     KeRaiseIrql(HIGH_LEVEL, &Irql);
99 
100     RtlFillMemory(Entries, sizeof(*Entries), 0x55);
101     ListHead->Next = NULL;
102     TestListFunctional(ListHead, Entries, &SpinLock);
103 
104     RtlFillMemory(Entries, sizeof(*Entries), 0x55);
105     ListHead->Next = NULL;
106     TestListFunctionalExports(ListHead, Entries, &SpinLock);
107 
108     RtlFillMemory(Entries, sizeof(*Entries), 0x55);
109     ListHead->Next = NULL;
110     TestListFunctionalNoInterlocked(ListHead, Entries, &SpinLock);
111 
112     KeLowerIrql(Irql);
113     ExFreePoolWithTag(Buffer, 'TLiS');
114 }
115