[SERVICES]
[reactos.git] / rostests / kmtests / ntos_ex / ExResource.c
1 /*
2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Kernel-Mode Test Suite Executive Resource test
5 * PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
6 */
7
8 #include <kmt_test.h>
9
10 //#define NDEBUG
11 #include <debug.h>
12
13 static
14 _IRQL_requires_max_(APC_LEVEL)
15 _Acquires_lock_(_Global_critical_region_)
16 PVOID
17 (NTAPI
18 *pExEnterCriticalRegionAndAcquireResourceShared)(
19 _Inout_ _Requires_lock_not_held_(*_Curr_) _Acquires_shared_lock_(*_Curr_)
20 PERESOURCE Resource);
21
22 static
23 _IRQL_requires_max_(APC_LEVEL)
24 _Acquires_lock_(_Global_critical_region_)
25 PVOID
26 (NTAPI
27 *pExEnterCriticalRegionAndAcquireResourceExclusive)(
28 _Inout_ _Requires_lock_not_held_(*_Curr_) _Acquires_exclusive_lock_(*_Curr_)
29 PERESOURCE Resource);
30
31 static
32 _IRQL_requires_max_(APC_LEVEL)
33 _Acquires_lock_(_Global_critical_region_)
34 PVOID
35 (NTAPI
36 *pExEnterCriticalRegionAndAcquireSharedWaitForExclusive)(
37 _Inout_ _Requires_lock_not_held_(*_Curr_) _Acquires_lock_(*_Curr_)
38 PERESOURCE Resource);
39
40 static
41 _IRQL_requires_max_(DISPATCH_LEVEL)
42 _Releases_lock_(_Global_critical_region_)
43 VOID
44 (FASTCALL
45 *pExReleaseResourceAndLeaveCriticalRegion)(
46 _Inout_ _Requires_lock_held_(*_Curr_) _Releases_lock_(*_Curr_)
47 PERESOURCE Resource);
48
49 static
50 _IRQL_requires_min_(PASSIVE_LEVEL)
51 _IRQL_requires_max_(DISPATCH_LEVEL)
52 BOOLEAN
53 (NTAPI
54 *pKeAreAllApcsDisabled)(VOID);
55
56 /* TODO: This is getting pretty long, make it somehow easier to read if possible */
57
58 /* TODO: this is the Windows Server 2003 version! ROS should use this!
59 * This declaration can be removed once ROS headers are corrected */
60 typedef struct _ERESOURCE_2K3 {
61 LIST_ENTRY SystemResourcesList;
62 POWNER_ENTRY OwnerTable;
63 SHORT ActiveCount;
64 USHORT Flag;
65 volatile PKSEMAPHORE SharedWaiters;
66 volatile PKEVENT ExclusiveWaiters;
67 OWNER_ENTRY OwnerThreads[2];
68 ULONG ContentionCount;
69 USHORT NumberOfSharedWaiters;
70 USHORT NumberOfExclusiveWaiters;
71 _ANONYMOUS_UNION union {
72 PVOID Address;
73 ULONG_PTR CreatorBackTraceIndex;
74 } DUMMYUNIONNAME;
75 KSPIN_LOCK SpinLock;
76 } ERESOURCE_2K3, *PERESOURCE_2K3;
77
78 #define CheckResourceFields(Res, Reinit) do \
79 { \
80 ok_eq_pointer((Res)->SystemResourcesList.Flink->Blink, &(Res)->SystemResourcesList); \
81 ok_eq_pointer((Res)->SystemResourcesList.Blink->Flink, &(Res)->SystemResourcesList); \
82 if (!Reinit) ok_eq_pointer((Res)->OwnerTable, NULL); \
83 ok_eq_int((Res)->ActiveCount, 0); \
84 ok_eq_uint((Res)->Flag, 0); \
85 if (!Reinit) ok_eq_pointer((Res)->SharedWaiters, NULL); \
86 if (!Reinit) ok_eq_pointer((Res)->ExclusiveWaiters, NULL); \
87 ok_eq_ulongptr((Res)->OwnerThreads[0].OwnerThread, 0); \
88 ok_eq_ulong((Res)->OwnerThreads[0].TableSize, 0LU); \
89 ok_eq_ulongptr((Res)->OwnerThreads[1].OwnerThread, 0); \
90 ok_eq_ulong((Res)->OwnerThreads[1].TableSize, 0LU); \
91 ok_eq_ulong((Res)->ContentionCount, 0LU); \
92 ok_eq_uint((Res)->NumberOfSharedWaiters, 0); \
93 ok_eq_uint((Res)->NumberOfExclusiveWaiters, 0); \
94 ok_eq_pointer((Res)->Address, NULL); \
95 ok_eq_ulongptr((Res)->SpinLock, 0); \
96 } while (0)
97
98 #define CheckResourceStatus(Res, Exclusive, Shared, ExclusiveWaiters, SharedWaiters) do \
99 { \
100 if (Exclusive) \
101 ok_bool_true(ExIsResourceAcquiredExclusiveLite(Res), "ExIsResourceAcquiredExclusiveLite returned"); \
102 else \
103 ok_bool_false(ExIsResourceAcquiredExclusiveLite(Res), "ExIsResourceAcquiredExclusiveLite returned"); \
104 ok_eq_ulong(ExIsResourceAcquiredSharedLite(Res), Shared); \
105 ok_eq_ulong(ExGetExclusiveWaiterCount(Res), ExclusiveWaiters); \
106 ok_eq_ulong(ExGetSharedWaiterCount(Res), SharedWaiters); \
107 } while (0)
108
109 static
110 VOID
111 TestResourceSharedAccess(
112 IN PERESOURCE Res)
113 {
114 LONG Count = 0;
115
116 KeEnterCriticalRegion();
117 ok_bool_true(ExAcquireResourceSharedLite(Res, FALSE), "ExAcquireResourceSharedLite returned"); ++Count;
118 CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
119
120 ok_bool_true(ExAcquireResourceSharedLite(Res, FALSE), "ExAcquireResourceSharedLite returned"); ++Count;
121 ok_bool_true(ExAcquireResourceSharedLite(Res, TRUE), "ExAcquireResourceSharedLite returned"); ++Count;
122 ok_bool_true(ExAcquireSharedStarveExclusive(Res, FALSE), "ExAcquireSharedStarveExclusive returned"); ++Count;
123 ok_bool_true(ExAcquireSharedStarveExclusive(Res, TRUE), "ExAcquireSharedStarveExclusive returned"); ++Count;
124 ok_bool_true(ExAcquireSharedWaitForExclusive(Res, FALSE), "ExAcquireSharedWaitForExclusive returned"); ++Count;
125 ok_bool_true(ExAcquireSharedWaitForExclusive(Res, TRUE), "ExAcquireSharedWaitForExclusive returned"); ++Count;
126 CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
127
128 /* this one fails, TRUE would deadlock */
129 ok_bool_false(ExAcquireResourceExclusiveLite(Res, FALSE), "ExAcquireResourceExclusiveLite returned");
130 CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
131
132 /* this asserts */
133 if (!KmtIsCheckedBuild)
134 ExConvertExclusiveToSharedLite(Res);
135 CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
136
137 while (Count--)
138 ExReleaseResourceLite(Res);
139 KeLeaveCriticalRegion();
140 }
141
142 static
143 VOID
144 TestResourceExclusiveAccess(
145 IN PERESOURCE Res)
146 {
147 LONG Count = 0;
148
149 KeEnterCriticalRegion();
150 ok_bool_true(ExAcquireResourceExclusiveLite(Res, FALSE), "ExAcquireResourceExclusiveLite returned"); ++Count;
151
152 CheckResourceStatus(Res, TRUE, Count, 0LU, 0LU);
153
154 ok_bool_true(ExAcquireResourceExclusiveLite(Res, TRUE), "ExAcquireResourceExclusiveLite returned"); ++Count;
155 CheckResourceStatus(Res, TRUE, Count, 0LU, 0LU);
156
157 ok_bool_true(ExAcquireResourceSharedLite(Res, FALSE), "ExAcquireResourceSharedLite returned"); ++Count;
158 ok_bool_true(ExAcquireResourceSharedLite(Res, TRUE), "ExAcquireResourceSharedLite returned"); ++Count;
159 ok_bool_true(ExAcquireSharedStarveExclusive(Res, FALSE), "ExAcquireSharedStarveExclusive returned"); ++Count;
160 ok_bool_true(ExAcquireSharedStarveExclusive(Res, TRUE), "ExAcquireSharedStarveExclusive returned"); ++Count;
161 ok_bool_true(ExAcquireSharedWaitForExclusive(Res, FALSE), "ExAcquireSharedWaitForExclusive returned"); ++Count;
162 ok_bool_true(ExAcquireSharedWaitForExclusive(Res, TRUE), "ExAcquireSharedWaitForExclusive returned"); ++Count;
163 CheckResourceStatus(Res, TRUE, Count, 0LU, 0LU);
164
165 ExConvertExclusiveToSharedLite(Res);
166 CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
167
168 while (Count--)
169 ExReleaseResourceLite(Res);
170 KeLeaveCriticalRegion();
171 }
172
173 static
174 VOID
175 TestResourceUndocumentedShortcuts(
176 IN PERESOURCE Res,
177 IN BOOLEAN AreApcsDisabled)
178 {
179 PVOID Ret;
180 LONG Count = 0;
181
182 ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
183 if (pKeAreAllApcsDisabled)
184 ok_eq_uint(pKeAreAllApcsDisabled(), AreApcsDisabled);
185
186 if (skip(pExEnterCriticalRegionAndAcquireResourceShared &&
187 pExEnterCriticalRegionAndAcquireSharedWaitForExclusive &&
188 pExEnterCriticalRegionAndAcquireResourceExclusive &&
189 pExReleaseResourceAndLeaveCriticalRegion, "No shortcuts\n"))
190 {
191 return;
192 }
193 /* ExEnterCriticalRegionAndAcquireResourceShared, ExEnterCriticalRegionAndAcquireSharedWaitForExclusive */
194 Count = 0;
195 Ret = pExEnterCriticalRegionAndAcquireResourceShared(Res); ++Count;
196 ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread);
197 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
198 if (pKeAreAllApcsDisabled)
199 ok_eq_bool(pKeAreAllApcsDisabled(), AreApcsDisabled);
200 CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
201
202 Ret = pExEnterCriticalRegionAndAcquireResourceShared(Res); ++Count;
203 ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread);
204 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
205 if (pKeAreAllApcsDisabled)
206 ok_eq_bool(pKeAreAllApcsDisabled(), AreApcsDisabled);
207 CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
208
209 pExEnterCriticalRegionAndAcquireSharedWaitForExclusive(Res); ++Count;
210 ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread);
211 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
212 if (pKeAreAllApcsDisabled)
213 ok_eq_bool(pKeAreAllApcsDisabled(), AreApcsDisabled);
214 CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
215
216 while (Count-- > 1)
217 {
218 pExReleaseResourceAndLeaveCriticalRegion(Res);
219 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
220 if (pKeAreAllApcsDisabled)
221 ok_eq_bool(pKeAreAllApcsDisabled(), AreApcsDisabled);
222 CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
223 }
224
225 pExReleaseResourceAndLeaveCriticalRegion(Res);
226 ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
227 if (pKeAreAllApcsDisabled)
228 ok_eq_bool(pKeAreAllApcsDisabled(), AreApcsDisabled);
229 CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
230
231 /* ExEnterCriticalRegionAndAcquireResourceExclusive */
232 Count = 0;
233 ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
234 if (pKeAreAllApcsDisabled)
235 ok_eq_bool(pKeAreAllApcsDisabled(), AreApcsDisabled);
236 Ret = pExEnterCriticalRegionAndAcquireResourceExclusive(Res); ++Count;
237 ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread);
238 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
239 if (pKeAreAllApcsDisabled)
240 ok_eq_bool(pKeAreAllApcsDisabled(), AreApcsDisabled);
241 CheckResourceStatus(Res, TRUE, Count, 0LU, 0LU);
242
243 Ret = pExEnterCriticalRegionAndAcquireResourceExclusive(Res); ++Count;
244 ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread);
245 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
246 if (pKeAreAllApcsDisabled)
247 ok_eq_bool(pKeAreAllApcsDisabled(), AreApcsDisabled);
248 CheckResourceStatus(Res, TRUE, Count, 0LU, 0LU);
249
250 pExReleaseResourceAndLeaveCriticalRegion(Res); --Count;
251 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
252 if (pKeAreAllApcsDisabled)
253 ok_eq_bool(pKeAreAllApcsDisabled(), AreApcsDisabled);
254 CheckResourceStatus(Res, TRUE, Count, 0LU, 0LU);
255
256 pExReleaseResourceAndLeaveCriticalRegion(Res); --Count;
257 ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
258 if (pKeAreAllApcsDisabled)
259 ok_eq_uint(pKeAreAllApcsDisabled(), AreApcsDisabled);
260 CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
261 }
262
263 typedef BOOLEAN (NTAPI *PACQUIRE_FUNCTION)(PERESOURCE, BOOLEAN);
264
265 typedef struct
266 {
267 HANDLE Handle;
268 PKTHREAD Thread;
269 PERESOURCE Res;
270 KEVENT InEvent;
271 KEVENT OutEvent;
272 PACQUIRE_FUNCTION AcquireResource;
273 BOOLEAN Wait;
274 BOOLEAN RetExpected;
275 } THREAD_DATA, *PTHREAD_DATA;
276
277 static
278 VOID
279 NTAPI
280 AcquireResourceThread(
281 PVOID Context)
282 {
283 NTSTATUS Status = STATUS_SUCCESS;
284 PTHREAD_DATA ThreadData = Context;
285 BOOLEAN Ret;
286
287 KeEnterCriticalRegion();
288 Ret = ThreadData->AcquireResource(ThreadData->Res, ThreadData->Wait);
289 if (ThreadData->RetExpected)
290 ok_bool_true(Ret, "AcquireResource returned");
291 else
292 ok_bool_false(Ret, "AcquireResource returned");
293
294 ok_bool_false(KeSetEvent(&ThreadData->OutEvent, 0, TRUE), "KeSetEvent returned");
295 Status = KeWaitForSingleObject(&ThreadData->InEvent, Executive, KernelMode, FALSE, NULL);
296 ok_eq_hex(Status, STATUS_SUCCESS);
297
298 if (Ret)
299 ExReleaseResource(ThreadData->Res);
300 KeLeaveCriticalRegion();
301 }
302
303 static
304 VOID
305 InitThreadData(
306 PTHREAD_DATA ThreadData,
307 PERESOURCE Res,
308 PACQUIRE_FUNCTION AcquireFunction)
309 {
310 ThreadData->Res = Res;
311 KeInitializeEvent(&ThreadData->InEvent, NotificationEvent, FALSE);
312 KeInitializeEvent(&ThreadData->OutEvent, NotificationEvent, FALSE);
313 ThreadData->AcquireResource = AcquireFunction;
314 }
315
316 static
317 NTSTATUS
318 StartThread(
319 PTHREAD_DATA ThreadData,
320 PLARGE_INTEGER Timeout,
321 BOOLEAN Wait,
322 BOOLEAN RetExpected)
323 {
324 NTSTATUS Status = STATUS_SUCCESS;
325 OBJECT_ATTRIBUTES Attributes;
326
327 ThreadData->Wait = Wait;
328 ThreadData->RetExpected = RetExpected;
329 InitializeObjectAttributes(&Attributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
330 Status = PsCreateSystemThread(&ThreadData->Handle, GENERIC_ALL, &Attributes, NULL, NULL, AcquireResourceThread, ThreadData);
331 ok_eq_hex(Status, STATUS_SUCCESS);
332 Status = ObReferenceObjectByHandle(ThreadData->Handle, SYNCHRONIZE, *PsThreadType, KernelMode, (PVOID *)&ThreadData->Thread, NULL);
333 ok_eq_hex(Status, STATUS_SUCCESS);
334
335 return KeWaitForSingleObject(&ThreadData->OutEvent, Executive, KernelMode, FALSE, Timeout);
336 }
337
338 static
339 VOID
340 FinishThread(
341 PTHREAD_DATA ThreadData)
342 {
343 NTSTATUS Status = STATUS_SUCCESS;
344
345 KeSetEvent(&ThreadData->InEvent, 0, TRUE);
346 Status = KeWaitForSingleObject(ThreadData->Thread, Executive, KernelMode, FALSE, NULL);
347 ok_eq_hex(Status, STATUS_SUCCESS);
348
349 ObDereferenceObject(ThreadData->Thread);
350 Status = ZwClose(ThreadData->Handle);
351 ok_eq_hex(Status, STATUS_SUCCESS);
352 KeClearEvent(&ThreadData->InEvent);
353 KeClearEvent(&ThreadData->OutEvent);
354 }
355
356 static
357 VOID
358 TestResourceWithThreads(
359 IN PERESOURCE Res)
360 {
361 NTSTATUS Status = STATUS_SUCCESS;
362 THREAD_DATA ThreadDataShared;
363 THREAD_DATA ThreadDataShared2;
364 THREAD_DATA ThreadDataExclusive;
365 THREAD_DATA ThreadDataSharedStarve;
366 THREAD_DATA ThreadDataSharedWait;
367 LARGE_INTEGER Timeout;
368 Timeout.QuadPart = -10 * 1000 * 10; /* 10 ms */
369
370 InitThreadData(&ThreadDataShared, Res, ExAcquireResourceSharedLite);
371 InitThreadData(&ThreadDataShared2, Res, ExAcquireResourceSharedLite);
372 InitThreadData(&ThreadDataExclusive, Res, ExAcquireResourceExclusiveLite);
373 InitThreadData(&ThreadDataSharedStarve, Res, ExAcquireSharedStarveExclusive);
374 InitThreadData(&ThreadDataSharedWait, Res, ExAcquireSharedWaitForExclusive);
375
376 /* have a thread acquire the resource shared */
377 Status = StartThread(&ThreadDataShared, NULL, FALSE, TRUE);
378 ok_eq_hex(Status, STATUS_SUCCESS);
379 CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
380 ok_eq_int(Res->ActiveCount, 1);
381
382 /* a second thread should be able to acquire the resource shared */
383 Status = StartThread(&ThreadDataShared2, NULL, FALSE, TRUE);
384 ok_eq_hex(Status, STATUS_SUCCESS);
385 CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
386 ok_eq_int(Res->ActiveCount, 2);
387 FinishThread(&ThreadDataShared2);
388 CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
389 ok_eq_int(Res->ActiveCount, 1);
390
391 /* now have a thread that tries to acquire the resource exclusive -- it should fail */
392 Status = StartThread(&ThreadDataExclusive, NULL, FALSE, FALSE);
393 ok_eq_hex(Status, STATUS_SUCCESS);
394 CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
395 ok_eq_int(Res->ActiveCount, 1);
396 FinishThread(&ThreadDataExclusive);
397 CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
398 ok_eq_int(Res->ActiveCount, 1);
399
400 /* as above, but this time it should block */
401 Status = StartThread(&ThreadDataExclusive, &Timeout, TRUE, TRUE);
402 ok_eq_hex(Status, STATUS_TIMEOUT);
403 CheckResourceStatus(Res, FALSE, 0LU, 1LU, 0LU);
404 ok_eq_int(Res->ActiveCount, 1);
405
406 /* now try another shared one -- it should fail */
407 Status = StartThread(&ThreadDataShared2, NULL, FALSE, FALSE);
408 ok_eq_hex(Status, STATUS_SUCCESS);
409 CheckResourceStatus(Res, FALSE, 0LU, 1LU, 0LU);
410 ok_eq_int(Res->ActiveCount, 1);
411 FinishThread(&ThreadDataShared2);
412
413 /* same for ExAcquireSharedWaitForExclusive */
414 Status = StartThread(&ThreadDataSharedWait, NULL, FALSE, FALSE);
415 ok_eq_hex(Status, STATUS_SUCCESS);
416 CheckResourceStatus(Res, FALSE, 0LU, 1LU, 0LU);
417 ok_eq_int(Res->ActiveCount, 1);
418 FinishThread(&ThreadDataSharedWait);
419
420 /* ExAcquireSharedStarveExclusive must get access though! */
421 Status = StartThread(&ThreadDataSharedStarve, NULL, TRUE, TRUE);
422 ok_eq_hex(Status, STATUS_SUCCESS);
423 CheckResourceStatus(Res, FALSE, 0LU, 1LU, 0LU);
424 ok_eq_int(Res->ActiveCount, 2);
425 FinishThread(&ThreadDataSharedStarve);
426 CheckResourceStatus(Res, FALSE, 0LU, 1LU, 0LU);
427 ok_eq_int(Res->ActiveCount, 1);
428
429 /* block another shared one */
430 Status = StartThread(&ThreadDataShared2, &Timeout, TRUE, TRUE);
431 ok_eq_hex(Status, STATUS_TIMEOUT);
432 CheckResourceStatus(Res, FALSE, 0LU, 1LU, 1LU);
433 ok_eq_int(Res->ActiveCount, 1);
434
435 /* finish the very first one */
436 FinishThread(&ThreadDataShared);
437
438 /* now the blocked exclusive one should get the resource */
439 Status = KeWaitForSingleObject(&ThreadDataExclusive.OutEvent, Executive, KernelMode, FALSE, NULL);
440 ok_eq_hex(Status, STATUS_SUCCESS);
441 CheckResourceStatus(Res, FALSE, 0LU, 0LU, 1LU);
442 ok_eq_int(Res->ActiveCount, 1);
443 ok_eq_uint((Res->Flag & ResourceOwnedExclusive) != 0, 1);
444
445 FinishThread(&ThreadDataExclusive);
446 CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
447
448 /* now the blocked shared one should resume */
449 Status = KeWaitForSingleObject(&ThreadDataShared2.OutEvent, Executive, KernelMode, FALSE, NULL);
450 ok_eq_hex(Status, STATUS_SUCCESS);
451 CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
452 ok_eq_int(Res->ActiveCount, 1);
453 FinishThread(&ThreadDataShared2);
454 CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
455 ok_eq_int(Res->ActiveCount, 0);
456 }
457
458 START_TEST(ExResource)
459 {
460 NTSTATUS Status;
461 ERESOURCE Res;
462 KIRQL Irql;
463
464 pExEnterCriticalRegionAndAcquireResourceShared = KmtGetSystemRoutineAddress(L"ExEnterCriticalRegionAndAcquireResourceShared");
465 pExEnterCriticalRegionAndAcquireSharedWaitForExclusive = KmtGetSystemRoutineAddress(L"ExEnterCriticalRegionAndAcquireSharedWaitForExclusive");
466 pExEnterCriticalRegionAndAcquireResourceExclusive = KmtGetSystemRoutineAddress(L"ExEnterCriticalRegionAndAcquireResourceExclusive");
467 pExReleaseResourceAndLeaveCriticalRegion = KmtGetSystemRoutineAddress(L"ExReleaseResourceAndLeaveCriticalRegion");
468 pKeAreAllApcsDisabled = KmtGetSystemRoutineAddress(L"KeAreAllApcsDisabled");
469
470 if (skip(pKeAreAllApcsDisabled != NULL, "KeAreAllApcsDisabled unavailable\n"))
471 {
472 /* We can live without this function here */
473 }
474
475 /* this must be true even with the different structure versions */
476 ASSERT(sizeof(ERESOURCE) == sizeof(ERESOURCE_2K3));
477
478 /* functional tests & internals */
479 Irql = KeRaiseIrqlToDpcLevel();
480 Status = ExInitializeResourceLite(&Res);
481 ok_eq_hex(Status, STATUS_SUCCESS);
482 KeLowerIrql(APC_LEVEL);
483
484 Status = ExDeleteResourceLite(&Res);
485 ok_eq_hex(Status, STATUS_SUCCESS);
486 KeLowerIrql(Irql);
487
488 memset(&Res, 0x55, sizeof Res);
489 Status = ExInitializeResourceLite(&Res);
490 ok_eq_hex(Status, STATUS_SUCCESS);
491 CheckResourceFields((PERESOURCE_2K3)&Res, FALSE);
492
493 CheckResourceStatus(&Res, FALSE, 0LU, 0LU, 0LU);
494
495 TestResourceSharedAccess(&Res);
496 CheckResourceStatus(&Res, FALSE, 0LU, 0LU, 0LU);
497
498 TestResourceExclusiveAccess(&Res);
499 CheckResourceStatus(&Res, FALSE, 0LU, 0LU, 0LU);
500
501 TestResourceUndocumentedShortcuts(&Res, FALSE);
502 CheckResourceStatus(&Res, FALSE, 0LU, 0LU, 0LU);
503 KeRaiseIrql(APC_LEVEL, &Irql);
504 TestResourceUndocumentedShortcuts(&Res, TRUE);
505 KeLowerIrql(Irql);
506 ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
507 CheckResourceStatus(&Res, FALSE, 0LU, 0LU, 0LU);
508
509 TestResourceWithThreads(&Res);
510
511 /* ExReinitializeResourceLite cleans up after us */
512 Status = ExReinitializeResourceLite(&Res);
513 ok_eq_hex(Status, STATUS_SUCCESS);
514 CheckResourceFields((PERESOURCE_2K3)&Res, TRUE);
515 CheckResourceStatus(&Res, FALSE, 0LU, 0LU, 0LU);
516
517 Status = ExDeleteResourceLite(&Res);
518 ok_eq_hex(Status, STATUS_SUCCESS);
519
520 /* parameter checks */
521 Status = STATUS_SUCCESS;
522 _SEH2_TRY {
523 ExInitializeResourceLite(NULL);
524 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
525 Status = _SEH2_GetExceptionCode();
526 } _SEH2_END;
527 ok_eq_hex(Status, STATUS_ACCESS_VIOLATION);
528
529 /* these bugcheck
530 ExDeleteResourceLite(NULL);
531 Status = ExDeleteResourceLite(&Res);*/
532 }