[KMTEST]
[reactos.git] / rostests / kmtests / ntos_ke / KeMutex.c
1 /*
2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Kernel-Mode Test Suite Mutant/Mutex test
5 * PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
6 */
7
8 #include <kmt_test.h>
9
10 static
11 _IRQL_requires_min_(PASSIVE_LEVEL)
12 _IRQL_requires_max_(DISPATCH_LEVEL)
13 BOOLEAN
14 (NTAPI
15 *pKeAreAllApcsDisabled)(VOID);
16
17 #define ULONGS_PER_POINTER (sizeof(PVOID) / sizeof(ULONG))
18 #define MUTANT_SIZE (2 + 6 * ULONGS_PER_POINTER)
19
20 C_ASSERT(sizeof(DISPATCHER_HEADER) == 8 + 2 * sizeof(PVOID));
21 C_ASSERT(sizeof(KMUTANT) == sizeof(DISPATCHER_HEADER) + 3 * sizeof(PVOID) + sizeof(PVOID));
22 C_ASSERT(sizeof(KMUTANT) == MUTANT_SIZE * sizeof(ULONG));
23
24 #define CheckMutex(Mutex, State, New, ExpectedApcDisable) do { \
25 PKTHREAD Thread = KeGetCurrentThread(); \
26 ok_eq_uint((Mutex)->Header.Type, MutantObject); \
27 ok_eq_uint((Mutex)->Header.Abandoned, 0x55); \
28 ok_eq_uint((Mutex)->Header.Size, MUTANT_SIZE); \
29 ok_eq_uint((Mutex)->Header.DpcActive, 0x55); \
30 ok_eq_pointer((Mutex)->Header.WaitListHead.Flink, \
31 &(Mutex)->Header.WaitListHead); \
32 ok_eq_pointer((Mutex)->Header.WaitListHead.Blink, \
33 &(Mutex)->Header.WaitListHead); \
34 if ((State) <= 0) \
35 { \
36 ok_eq_long((Mutex)->Header.SignalState, State); \
37 ok_eq_pointer((Mutex)->MutantListEntry.Flink, &Thread->MutantListHead); \
38 ok_eq_pointer((Mutex)->MutantListEntry.Blink, &Thread->MutantListHead); \
39 ok_eq_pointer(Thread->MutantListHead.Flink, &(Mutex)->MutantListEntry); \
40 ok_eq_pointer(Thread->MutantListHead.Blink, &(Mutex)->MutantListEntry); \
41 ok_eq_pointer((Mutex)->OwnerThread, Thread); \
42 } \
43 else \
44 { \
45 ok_eq_long((Mutex)->Header.SignalState, State); \
46 if (New) \
47 { \
48 ok_eq_pointer((Mutex)->MutantListEntry.Flink, \
49 (PVOID)0x5555555555555555ULL); \
50 ok_eq_pointer((Mutex)->MutantListEntry.Blink, \
51 (PVOID)0x5555555555555555ULL); \
52 } \
53 ok_eq_pointer(Thread->MutantListHead.Flink, &Thread->MutantListHead); \
54 ok_eq_pointer(Thread->MutantListHead.Blink, &Thread->MutantListHead); \
55 ok_eq_pointer((Mutex)->OwnerThread, NULL); \
56 } \
57 ok_eq_uint((Mutex)->Abandoned, 0); \
58 ok_eq_uint((Mutex)->ApcDisable, ExpectedApcDisable); \
59 } while (0)
60
61 #define CheckApcs(KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, Irql) do \
62 { \
63 ok_eq_bool(KeAreApcsDisabled(), KernelApcsDisabled || SpecialApcsDisabled); \
64 ok_eq_int(Thread->KernelApcDisable, KernelApcsDisabled); \
65 if (pKeAreAllApcsDisabled) \
66 ok_eq_bool(pKeAreAllApcsDisabled(), AllApcsDisabled); \
67 ok_eq_int(Thread->SpecialApcDisable, SpecialApcsDisabled); \
68 ok_irql(Irql); \
69 } while (0)
70
71 static
72 VOID
73 TestMutant(VOID)
74 {
75 NTSTATUS Status;
76 KMUTANT Mutant;
77 LONG State;
78 LONG i;
79 PKTHREAD Thread = KeGetCurrentThread();
80
81 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
82 RtlFillMemory(&Mutant, sizeof(Mutant), 0x55);
83 KeInitializeMutant(&Mutant, FALSE);
84 CheckMutex(&Mutant, 1L, TRUE, 0);
85 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
86
87 RtlFillMemory(&Mutant, sizeof(Mutant), 0x55);
88 KeInitializeMutant(&Mutant, TRUE);
89 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
90 CheckMutex(&Mutant, 0L, TRUE, 0);
91 State = KeReleaseMutant(&Mutant, 1, FALSE, FALSE);
92 ok_eq_long(State, 0L);
93 CheckMutex(&Mutant, 1L, FALSE, 0);
94 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
95
96 /* Acquire and release */
97 Status = KeWaitForSingleObject(&Mutant,
98 Executive,
99 KernelMode,
100 FALSE,
101 NULL);
102 ok_eq_hex(Status, STATUS_SUCCESS);
103 CheckMutex(&Mutant, 0L, TRUE, 0);
104 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
105
106 State = KeReleaseMutant(&Mutant, 1, FALSE, FALSE);
107 ok_eq_long(State, 0L);
108 CheckMutex(&Mutant, 1L, FALSE, 0);
109 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
110
111 /* Acquire recursively */
112 for (i = 0; i < 8; i++)
113 {
114 KmtStartSeh()
115 Status = KeWaitForSingleObject(&Mutant,
116 Executive,
117 KernelMode,
118 FALSE,
119 NULL);
120 KmtEndSeh(STATUS_SUCCESS);
121 ok_eq_hex(Status, STATUS_SUCCESS);
122 CheckMutex(&Mutant, -i, FALSE, 0);
123 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
124 }
125
126 for (i = 0; i < 7; i++)
127 {
128 KmtStartSeh()
129 State = KeReleaseMutant(&Mutant, 1, FALSE, FALSE);
130 KmtEndSeh(STATUS_SUCCESS);
131 ok_eq_long(State, -7L + i);
132 CheckMutex(&Mutant, -6L + i, FALSE, 0);
133 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
134 }
135
136 State = KeReleaseMutant(&Mutant, 1, FALSE, FALSE);
137 ok_eq_long(State, 0L);
138 CheckMutex(&Mutant, 1L, FALSE, 0);
139 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
140
141 /* Pretend to acquire it recursively -MINLONG times */
142 KmtStartSeh()
143 Status = KeWaitForSingleObject(&Mutant,
144 Executive,
145 KernelMode,
146 FALSE,
147 NULL);
148 KmtEndSeh(STATUS_SUCCESS);
149 ok_eq_hex(Status, STATUS_SUCCESS);
150 CheckMutex(&Mutant, 0L, FALSE, 0);
151 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
152
153 Mutant.Header.SignalState = MINLONG + 1;
154 KmtStartSeh()
155 Status = KeWaitForSingleObject(&Mutant,
156 Executive,
157 KernelMode,
158 FALSE,
159 NULL);
160 KmtEndSeh(STATUS_SUCCESS);
161 ok_eq_hex(Status, STATUS_SUCCESS);
162 CheckMutex(&Mutant, (LONG)MINLONG, FALSE, 0);
163 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
164
165 KmtStartSeh()
166 KeWaitForSingleObject(&Mutant,
167 Executive,
168 KernelMode,
169 FALSE,
170 NULL);
171 KmtEndSeh(STATUS_MUTANT_LIMIT_EXCEEDED);
172 CheckMutex(&Mutant, (LONG)MINLONG, FALSE, 0);
173 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
174
175 State = KeReleaseMutant(&Mutant, 1, FALSE, FALSE);
176 ok_eq_long(State, (LONG)MINLONG);
177 CheckMutex(&Mutant, (LONG)MINLONG + 1L, FALSE, 0);
178 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
179
180 Mutant.Header.SignalState = -1;
181 State = KeReleaseMutant(&Mutant, 1, FALSE, FALSE);
182 ok_eq_long(State, -1L);
183 CheckMutex(&Mutant, 0L, FALSE, 0);
184 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
185
186 State = KeReleaseMutant(&Mutant, 1, FALSE, FALSE);
187 ok_eq_long(State, 0L);
188 CheckMutex(&Mutant, 1L, FALSE, 0);
189 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
190
191 /* Now release it once too often */
192 KmtStartSeh()
193 KeReleaseMutant(&Mutant, 1, FALSE, FALSE);
194 KmtEndSeh(STATUS_MUTANT_NOT_OWNED);
195 CheckMutex(&Mutant, 1L, FALSE, 0);
196 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
197 }
198
199 static
200 VOID
201 TestMutex(VOID)
202 {
203 NTSTATUS Status;
204 KMUTEX Mutex;
205 LONG State;
206 LONG i;
207 PKTHREAD Thread = KeGetCurrentThread();
208
209 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
210 RtlFillMemory(&Mutex, sizeof(Mutex), 0x55);
211 KeInitializeMutex(&Mutex, 0);
212 CheckMutex(&Mutex, 1L, TRUE, 1);
213 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
214
215 RtlFillMemory(&Mutex, sizeof(Mutex), 0x55);
216 KeInitializeMutex(&Mutex, 123);
217 CheckMutex(&Mutex, 1L, TRUE, 1);
218 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
219
220 /* Acquire and release */
221 Status = KeWaitForSingleObject(&Mutex,
222 Executive,
223 KernelMode,
224 FALSE,
225 NULL);
226 ok_eq_hex(Status, STATUS_SUCCESS);
227 CheckMutex(&Mutex, 0L, FALSE, 1);
228 CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
229
230 State = KeReleaseMutex(&Mutex, FALSE);
231 ok_eq_long(State, 0L);
232 CheckMutex(&Mutex, 1L, FALSE, 1);
233 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
234
235 /* Acquire recursively */
236 for (i = 0; i < 8; i++)
237 {
238 KmtStartSeh()
239 Status = KeWaitForSingleObject(&Mutex,
240 Executive,
241 KernelMode,
242 FALSE,
243 NULL);
244 KmtEndSeh(STATUS_SUCCESS);
245 ok_eq_hex(Status, STATUS_SUCCESS);
246 CheckMutex(&Mutex, -i, FALSE, 1);
247 CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
248 }
249
250 for (i = 0; i < 7; i++)
251 {
252 KmtStartSeh()
253 State = KeReleaseMutex(&Mutex, FALSE);
254 KmtEndSeh(STATUS_SUCCESS);
255 ok_eq_long(State, -7L + i);
256 CheckMutex(&Mutex, -6L + i, FALSE, 1);
257 CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
258 }
259
260 State = KeReleaseMutex(&Mutex, FALSE);
261 ok_eq_long(State, 0L);
262 CheckMutex(&Mutex, 1L, FALSE, 1);
263 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
264
265 /* Pretend to acquire it recursively -MINLONG times */
266 KmtStartSeh()
267 Status = KeWaitForSingleObject(&Mutex,
268 Executive,
269 KernelMode,
270 FALSE,
271 NULL);
272 KmtEndSeh(STATUS_SUCCESS);
273 ok_eq_hex(Status, STATUS_SUCCESS);
274 CheckMutex(&Mutex, 0L, FALSE, 1);
275 CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
276
277 Mutex.Header.SignalState = MINLONG + 1;
278 KmtStartSeh()
279 Status = KeWaitForSingleObject(&Mutex,
280 Executive,
281 KernelMode,
282 FALSE,
283 NULL);
284 KmtEndSeh(STATUS_SUCCESS);
285 ok_eq_hex(Status, STATUS_SUCCESS);
286 CheckMutex(&Mutex, (LONG)MINLONG, FALSE, 1);
287 CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
288
289 KmtStartSeh()
290 KeWaitForSingleObject(&Mutex,
291 Executive,
292 KernelMode,
293 FALSE,
294 NULL);
295 KmtEndSeh(STATUS_MUTANT_LIMIT_EXCEEDED);
296 CheckMutex(&Mutex, (LONG)MINLONG, FALSE, 1);
297 CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
298
299 State = KeReleaseMutex(&Mutex, FALSE);
300 ok_eq_long(State, (LONG)MINLONG);
301 CheckMutex(&Mutex, (LONG)MINLONG + 1L, FALSE, 1);
302 CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
303
304 Mutex.Header.SignalState = -1;
305 State = KeReleaseMutex(&Mutex, FALSE);
306 ok_eq_long(State, -1L);
307 CheckMutex(&Mutex, 0L, FALSE, 1);
308 CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
309
310 State = KeReleaseMutex(&Mutex, FALSE);
311 ok_eq_long(State, 0L);
312 CheckMutex(&Mutex, 1L, FALSE, 1);
313 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
314
315 /* Now release it once too often */
316 KmtStartSeh()
317 KeReleaseMutex(&Mutex, FALSE);
318 KmtEndSeh(STATUS_MUTANT_NOT_OWNED);
319 CheckMutex(&Mutex, 1L, FALSE, 1);
320 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
321 }
322
323 START_TEST(KeMutex)
324 {
325 pKeAreAllApcsDisabled = KmtGetSystemRoutineAddress(L"KeAreAllApcsDisabled");
326 if (skip(pKeAreAllApcsDisabled != NULL, "KeAreAllApcsDisabled unavailable\n"))
327 {
328 /* We can live without this function here */
329 }
330
331 TestMutant();
332 TestMutex();
333 }