[KMTESTS/KE]
[reactos.git] / kmtests / ntos_ke / KeGuardedMutex.c
1 /*
2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Kernel-Mode Test Suite Guarded Mutex test
5 * PROGRAMMER: Thomas Faber <thfabba@gmx.de>
6 */
7
8 #include <kmt_test.h>
9
10 #define NDEBUG
11 #include <debug.h>
12
13 #define CheckMutex(Mutex, ExpectedCount, ExpectedOwner, ExpectedContention, \
14 ExpectedKernelApcDisable, ExpectedSpecialApcDisable, \
15 KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, \
16 ExpectedIrql) do \
17 { \
18 ok_eq_long((Mutex)->Count, ExpectedCount); \
19 ok_eq_pointer((Mutex)->Owner, ExpectedOwner); \
20 ok_eq_ulong((Mutex)->Contention, ExpectedContention); \
21 ok_eq_int((Mutex)->KernelApcDisable, ExpectedKernelApcDisable); \
22 if (KmtIsCheckedBuild) \
23 ok_eq_int((Mutex)->SpecialApcDisable, ExpectedSpecialApcDisable); \
24 else \
25 ok_eq_int((Mutex)->SpecialApcDisable, 0x5555); \
26 ok_eq_bool(KeAreApcsDisabled(), KernelApcsDisabled || SpecialApcsDisabled); \
27 ok_eq_int(Thread->KernelApcDisable, KernelApcsDisabled); \
28 ok_eq_bool(KeAreAllApcsDisabled(), AllApcsDisabled); \
29 ok_eq_int(Thread->SpecialApcDisable, SpecialApcsDisabled); \
30 ok_irql(ExpectedIrql); \
31 } while (0)
32
33 static
34 VOID
35 TestGuardedMutex(
36 PKGUARDED_MUTEX Mutex,
37 SHORT KernelApcsDisabled,
38 SHORT SpecialApcsDisabled,
39 SHORT AllApcsDisabled,
40 KIRQL OriginalIrql)
41 {
42 PKTHREAD Thread = KeGetCurrentThread();
43
44 ok_irql(OriginalIrql);
45 CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, 0x5555, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql);
46
47 /* these ASSERT */
48 if (!KmtIsCheckedBuild || OriginalIrql <= APC_LEVEL)
49 {
50 /* acquire/release normally */
51 KeAcquireGuardedMutex(Mutex);
52 CheckMutex(Mutex, 0L, Thread, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled - 1, TRUE, OriginalIrql);
53 ok_bool_false(KeTryToAcquireGuardedMutex(Mutex), "KeTryToAcquireGuardedMutex returned");
54 CheckMutex(Mutex, 0L, Thread, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled - 1, TRUE, OriginalIrql);
55 KeReleaseGuardedMutex(Mutex);
56 CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql);
57
58 /* try to acquire */
59 ok_bool_true(KeTryToAcquireGuardedMutex(Mutex), "KeTryToAcquireGuardedMutex returned");
60 CheckMutex(Mutex, 0L, Thread, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled - 1, TRUE, OriginalIrql);
61 KeReleaseGuardedMutex(Mutex);
62 CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql);
63 }
64 else
65 /* Make the following test happy */
66 Mutex->SpecialApcDisable = SpecialApcsDisabled - 1;
67
68 /* ASSERT */
69 if (!KmtIsCheckedBuild || OriginalIrql == APC_LEVEL || SpecialApcsDisabled < 0)
70 {
71 /* acquire/release unsafe */
72 KeAcquireGuardedMutexUnsafe(Mutex);
73 CheckMutex(Mutex, 0L, Thread, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql);
74 KeReleaseGuardedMutexUnsafe(Mutex);
75 CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql);
76 }
77
78 /* Bugchecks >= DISPATCH_LEVEL */
79 if (!KmtIsCheckedBuild)
80 {
81 /* mismatched acquire/release */
82 KeAcquireGuardedMutex(Mutex);
83 CheckMutex(Mutex, 0L, Thread, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled - 1, TRUE, OriginalIrql);
84 KeReleaseGuardedMutexUnsafe(Mutex);
85 CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled - 1, TRUE, OriginalIrql);
86 KeLeaveGuardedRegion();
87 CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql);
88
89 KeAcquireGuardedMutexUnsafe(Mutex);
90 CheckMutex(Mutex, 0L, Thread, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql);
91 KeReleaseGuardedMutex(Mutex);
92 CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled + 1, OriginalIrql >= APC_LEVEL || SpecialApcsDisabled != -1, OriginalIrql);
93 KeEnterGuardedRegion();
94 CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql);
95
96 /* release without acquire */
97 KeReleaseGuardedMutexUnsafe(Mutex);
98 CheckMutex(Mutex, 0L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql);
99 KeReleaseGuardedMutex(Mutex);
100 CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled, KernelApcsDisabled, SpecialApcsDisabled + 1, OriginalIrql >= APC_LEVEL || SpecialApcsDisabled != -1, OriginalIrql);
101 KeReleaseGuardedMutex(Mutex);
102 /* TODO: here we see that Mutex->Count isn't actually just a count. Test the bits correctly! */
103 CheckMutex(Mutex, 0L, NULL, 0LU, 0x5555, SpecialApcsDisabled, KernelApcsDisabled, SpecialApcsDisabled + 2, OriginalIrql >= APC_LEVEL || SpecialApcsDisabled != -2, OriginalIrql);
104 KeReleaseGuardedMutex(Mutex);
105 CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled, KernelApcsDisabled, SpecialApcsDisabled + 3, OriginalIrql >= APC_LEVEL || SpecialApcsDisabled != -3, OriginalIrql);
106 Thread->SpecialApcDisable -= 3;
107 }
108
109 /* make sure we survive this in case of error */
110 ok_eq_long(Mutex->Count, 1L);
111 Mutex->Count = 1;
112 ok_eq_int(Thread->KernelApcDisable, KernelApcsDisabled);
113 Thread->KernelApcDisable = KernelApcsDisabled;
114 ok_eq_int(Thread->SpecialApcDisable, SpecialApcsDisabled);
115 Thread->SpecialApcDisable = SpecialApcsDisabled;
116 ok_irql(OriginalIrql);
117 }
118
119 START_TEST(KeGuardedMutex)
120 {
121 KGUARDED_MUTEX Mutex;
122 KIRQL OldIrql;
123 PKTHREAD Thread = KeGetCurrentThread();
124 struct {
125 KIRQL Irql;
126 SHORT KernelApcsDisabled;
127 SHORT SpecialApcsDisabled;
128 BOOLEAN AllApcsDisabled;
129 } TestIterations[] =
130 {
131 { PASSIVE_LEVEL, 0, 0, FALSE },
132 { PASSIVE_LEVEL, -1, 0, FALSE },
133 { PASSIVE_LEVEL, -3, 0, FALSE },
134 { PASSIVE_LEVEL, 0, -1, TRUE },
135 { PASSIVE_LEVEL, -1, -1, TRUE },
136 { PASSIVE_LEVEL, -3, -2, TRUE },
137 // 6
138 { APC_LEVEL, 0, 0, TRUE },
139 { APC_LEVEL, -1, 0, TRUE },
140 { APC_LEVEL, -3, 0, TRUE },
141 { APC_LEVEL, 0, -1, TRUE },
142 { APC_LEVEL, -1, -1, TRUE },
143 { APC_LEVEL, -3, -2, TRUE },
144 // 12
145 { DISPATCH_LEVEL, 0, 0, TRUE },
146 { DISPATCH_LEVEL, -1, 0, TRUE },
147 { DISPATCH_LEVEL, -3, 0, TRUE },
148 { DISPATCH_LEVEL, 0, -1, TRUE },
149 { DISPATCH_LEVEL, -1, -1, TRUE },
150 { DISPATCH_LEVEL, -3, -2, TRUE },
151 // 18
152 { HIGH_LEVEL, 0, 0, TRUE },
153 { HIGH_LEVEL, -1, 0, TRUE },
154 { HIGH_LEVEL, -3, 0, TRUE },
155 { HIGH_LEVEL, 0, -1, TRUE },
156 { HIGH_LEVEL, -1, -1, TRUE },
157 { HIGH_LEVEL, -3, -2, TRUE },
158 };
159 int i;
160
161 for (i = 0; i < sizeof TestIterations / sizeof TestIterations[0]; ++i)
162 {
163 trace("Run %d\n", i);
164 KeRaiseIrql(TestIterations[i].Irql, &OldIrql);
165 Thread->KernelApcDisable = TestIterations[i].KernelApcsDisabled;
166 Thread->SpecialApcDisable = TestIterations[i].SpecialApcsDisabled;
167
168 RtlFillMemory(&Mutex, sizeof Mutex, 0x55);
169 KeInitializeGuardedMutex(&Mutex);
170 CheckMutex(&Mutex, 1L, NULL, 0LU, 0x5555, 0x5555, TestIterations[i].KernelApcsDisabled, TestIterations[i].SpecialApcsDisabled, TestIterations[i].AllApcsDisabled, TestIterations[i].Irql);
171 TestGuardedMutex(&Mutex, TestIterations[i].KernelApcsDisabled, TestIterations[i].SpecialApcsDisabled, TestIterations[i].AllApcsDisabled, TestIterations[i].Irql);
172
173 Thread->SpecialApcDisable = 0;
174 Thread->KernelApcDisable = 0;
175 KeLowerIrql(OldIrql);
176 }
177 }