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 <thfabba@gmx.de>
10 #include <ndk/extypes.h>
12 #include <pseh/pseh2.h>
17 /* TODO: This is getting pretty long, make it somehow easier to read if possible */
19 /* TODO: this is the Windows Server 2003 version! ROS should use this!
20 * This declaration can be removed once ROS headers are corrected */
21 typedef struct _ERESOURCE_2K3
{
22 LIST_ENTRY SystemResourcesList
;
23 POWNER_ENTRY OwnerTable
;
26 volatile PKSEMAPHORE SharedWaiters
;
27 volatile PKEVENT ExclusiveWaiters
;
28 OWNER_ENTRY OwnerThreads
[2];
29 ULONG ContentionCount
;
30 USHORT NumberOfSharedWaiters
;
31 USHORT NumberOfExclusiveWaiters
;
33 PVOID Reserved2
; /* TODO: not sure if this should be in here for 2k3 */
35 _ANONYMOUS_UNION
union {
37 ULONG_PTR CreatorBackTraceIndex
;
40 } ERESOURCE_2K3
, *PERESOURCE_2K3
;
42 #define CheckResourceFields(Res, Reinit) do \
44 ok_eq_pointer((Res)->SystemResourcesList.Flink->Blink, &(Res)->SystemResourcesList); \
45 ok_eq_pointer((Res)->SystemResourcesList.Blink->Flink, &(Res)->SystemResourcesList); \
46 if (!Reinit) ok_eq_pointer((Res)->OwnerTable, NULL); \
47 ok_eq_int((Res)->ActiveCount, 0); \
48 ok_eq_uint((Res)->Flag, 0); \
49 if (!Reinit) ok_eq_pointer((Res)->SharedWaiters, NULL); \
50 if (!Reinit) ok_eq_pointer((Res)->ExclusiveWaiters, NULL); \
51 ok_eq_pointer((PVOID)(Res)->OwnerThreads[0].OwnerThread, NULL); \
52 ok_eq_ulong((Res)->OwnerThreads[0].TableSize, 0LU); \
53 ok_eq_pointer((PVOID)(Res)->OwnerThreads[1].OwnerThread, NULL); \
54 ok_eq_ulong((Res)->OwnerThreads[1].TableSize, 0LU); \
55 ok_eq_ulong((Res)->ContentionCount, 0LU); \
56 ok_eq_uint((Res)->NumberOfSharedWaiters, 0); \
57 ok_eq_uint((Res)->NumberOfExclusiveWaiters, 0); \
58 /* ok_eq_pointer((Res)->Reserved2, NULL); */ \
59 ok_eq_pointer((Res)->Address, NULL); \
60 ok_eq_pointer((PVOID)(Res)->SpinLock, NULL); \
63 #define CheckResourceStatus(Res, Exclusive, Shared, ExclusiveWaiters, SharedWaiters) do \
66 ok_bool_true(ExIsResourceAcquiredExclusiveLite(Res), "ExIsResourceAcquiredExclusiveLite returned"); \
68 ok_bool_false(ExIsResourceAcquiredExclusiveLite(Res), "ExIsResourceAcquiredExclusiveLite returned"); \
69 ok_eq_ulong(ExIsResourceAcquiredSharedLite(Res), Shared); \
70 ok_eq_ulong(ExGetExclusiveWaiterCount(Res), ExclusiveWaiters); \
71 ok_eq_ulong(ExGetSharedWaiterCount(Res), SharedWaiters); \
76 TestResourceSharedAccess(
81 KeEnterCriticalRegion();
82 ok_bool_true(ExAcquireResourceSharedLite(Res
, FALSE
), "ExAcquireResourceSharedLite returned"); ++Count
;
83 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
85 ok_bool_true(ExAcquireResourceSharedLite(Res
, FALSE
), "ExAcquireResourceSharedLite returned"); ++Count
;
86 ok_bool_true(ExAcquireResourceSharedLite(Res
, TRUE
), "ExAcquireResourceSharedLite returned"); ++Count
;
87 ok_bool_true(ExAcquireSharedStarveExclusive(Res
, FALSE
), "ExAcquireSharedStarveExclusive returned"); ++Count
;
88 ok_bool_true(ExAcquireSharedStarveExclusive(Res
, TRUE
), "ExAcquireSharedStarveExclusive returned"); ++Count
;
89 ok_bool_true(ExAcquireSharedWaitForExclusive(Res
, FALSE
), "ExAcquireSharedWaitForExclusive returned"); ++Count
;
90 ok_bool_true(ExAcquireSharedWaitForExclusive(Res
, TRUE
), "ExAcquireSharedWaitForExclusive returned"); ++Count
;
91 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
93 /* this one fails, TRUE would deadlock */
94 ok_bool_false(ExAcquireResourceExclusiveLite(Res
, FALSE
), "ExAcquireResourceExclusiveLite returned");
95 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
97 /* this must not crash or deadlock (but can assert) */
98 ExConvertExclusiveToSharedLite(Res
);
99 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
102 ExReleaseResourceLite(Res
);
103 KeLeaveCriticalRegion();
108 TestResourceExclusiveAccess(
113 KeEnterCriticalRegion();
114 ok_bool_true(ExAcquireResourceExclusiveLite(Res
, FALSE
), "ExAcquireResourceExclusiveLite returned"); ++Count
;
116 CheckResourceStatus(Res
, TRUE
, Count
, 0LU, 0LU);
118 ok_bool_true(ExAcquireResourceExclusiveLite(Res
, TRUE
), "ExAcquireResourceExclusiveLite returned"); ++Count
;
119 CheckResourceStatus(Res
, TRUE
, Count
, 0LU, 0LU);
121 ok_bool_true(ExAcquireResourceSharedLite(Res
, FALSE
), "ExAcquireResourceSharedLite returned"); ++Count
;
122 ok_bool_true(ExAcquireResourceSharedLite(Res
, TRUE
), "ExAcquireResourceSharedLite returned"); ++Count
;
123 ok_bool_true(ExAcquireSharedStarveExclusive(Res
, FALSE
), "ExAcquireSharedStarveExclusive returned"); ++Count
;
124 ok_bool_true(ExAcquireSharedStarveExclusive(Res
, TRUE
), "ExAcquireSharedStarveExclusive returned"); ++Count
;
125 ok_bool_true(ExAcquireSharedWaitForExclusive(Res
, FALSE
), "ExAcquireSharedWaitForExclusive returned"); ++Count
;
126 ok_bool_true(ExAcquireSharedWaitForExclusive(Res
, TRUE
), "ExAcquireSharedWaitForExclusive returned"); ++Count
;
127 CheckResourceStatus(Res
, TRUE
, Count
, 0LU, 0LU);
129 ExConvertExclusiveToSharedLite(Res
);
130 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
133 ExReleaseResourceLite(Res
);
134 KeLeaveCriticalRegion();
139 TestResourceUndocumentedShortcuts(
141 IN BOOLEAN AreApcsDisabled
)
146 ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
147 ok_eq_uint(KeAreAllApcsDisabled(), AreApcsDisabled
);
149 /* ExEnterCriticalRegionAndAcquireResourceShared, ExEnterCriticalRegionAndAcquireSharedWaitForExclusive */
151 Ret
= ExEnterCriticalRegionAndAcquireResourceShared(Res
); ++Count
;
152 ok_eq_pointer(Ret
, KeGetCurrentThread()->Win32Thread
);
153 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
154 ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled
);
155 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
157 Ret
= ExEnterCriticalRegionAndAcquireResourceShared(Res
); ++Count
;
158 ok_eq_pointer(Ret
, KeGetCurrentThread()->Win32Thread
);
159 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
160 ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled
);
161 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
163 ExEnterCriticalRegionAndAcquireSharedWaitForExclusive(Res
); ++Count
;
164 ok_eq_pointer(Ret
, KeGetCurrentThread()->Win32Thread
);
165 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
166 ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled
);
167 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
171 ExReleaseResourceAndLeaveCriticalRegion(Res
);
172 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
173 ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled
);
174 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
177 ExReleaseResourceAndLeaveCriticalRegion(Res
);
178 ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
179 ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled
);
180 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
182 /* ExEnterCriticalRegionAndAcquireResourceExclusive */
184 ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
185 ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled
);
186 Ret
= ExEnterCriticalRegionAndAcquireResourceExclusive(Res
); ++Count
;
187 ok_eq_pointer(Ret
, KeGetCurrentThread()->Win32Thread
);
188 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
189 ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled
);
190 CheckResourceStatus(Res
, TRUE
, Count
, 0LU, 0LU);
192 Ret
= ExEnterCriticalRegionAndAcquireResourceExclusive(Res
); ++Count
;
193 ok_eq_pointer(Ret
, KeGetCurrentThread()->Win32Thread
);
194 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
195 ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled
);
196 CheckResourceStatus(Res
, TRUE
, Count
, 0LU, 0LU);
198 ExReleaseResourceAndLeaveCriticalRegion(Res
); --Count
;
199 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
200 ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled
);
201 CheckResourceStatus(Res
, TRUE
, Count
, 0LU, 0LU);
203 ExReleaseResourceAndLeaveCriticalRegion(Res
); --Count
;
204 ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
205 ok_eq_uint(KeAreAllApcsDisabled(), AreApcsDisabled
);
206 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
209 typedef BOOLEAN (NTAPI
*PACQUIRE_FUNCTION
)(PERESOURCE
, BOOLEAN
);
218 PACQUIRE_FUNCTION AcquireResource
;
221 } THREAD_DATA
, *PTHREAD_DATA
;
226 AcquireResourceThread(
229 NTSTATUS Status
= STATUS_SUCCESS
;
230 PTHREAD_DATA ThreadData
= Context
;
233 KeEnterCriticalRegion();
234 Ret
= ThreadData
->AcquireResource(ThreadData
->Res
, ThreadData
->Wait
);
235 if (ThreadData
->RetExpected
)
236 ok_bool_true(Ret
, "AcquireResource returned");
238 ok_bool_false(Ret
, "AcquireResource returned");
240 ok_bool_false(KeSetEvent(&ThreadData
->OutEvent
, 0, TRUE
), "KeSetEvent returned");
241 Status
= KeWaitForSingleObject(&ThreadData
->InEvent
, Executive
, KernelMode
, FALSE
, NULL
);
242 ok_eq_hex(Status
, STATUS_SUCCESS
);
245 ExReleaseResource(ThreadData
->Res
);
246 KeLeaveCriticalRegion();
252 PTHREAD_DATA ThreadData
,
254 PACQUIRE_FUNCTION AcquireFunction
)
256 ThreadData
->Res
= Res
;
257 KeInitializeEvent(&ThreadData
->InEvent
, NotificationEvent
, FALSE
);
258 KeInitializeEvent(&ThreadData
->OutEvent
, NotificationEvent
, FALSE
);
259 ThreadData
->AcquireResource
= AcquireFunction
;
265 PTHREAD_DATA ThreadData
,
266 PLARGE_INTEGER Timeout
,
270 NTSTATUS Status
= STATUS_SUCCESS
;
271 OBJECT_ATTRIBUTES Attributes
;
273 ThreadData
->Wait
= Wait
;
274 ThreadData
->RetExpected
= RetExpected
;
275 InitializeObjectAttributes(&Attributes
, NULL
, OBJ_KERNEL_HANDLE
, NULL
, NULL
);
276 Status
= PsCreateSystemThread(&ThreadData
->Handle
, GENERIC_ALL
, &Attributes
, NULL
, NULL
, AcquireResourceThread
, ThreadData
);
277 ok_eq_hex(Status
, STATUS_SUCCESS
);
278 Status
= ObReferenceObjectByHandle(ThreadData
->Handle
, SYNCHRONIZE
, PsThreadType
, KernelMode
, (PVOID
*)&ThreadData
->Thread
, NULL
);
279 ok_eq_hex(Status
, STATUS_SUCCESS
);
281 return KeWaitForSingleObject(&ThreadData
->OutEvent
, Executive
, KernelMode
, FALSE
, Timeout
);
287 PTHREAD_DATA ThreadData
)
289 NTSTATUS Status
= STATUS_SUCCESS
;
291 KeSetEvent(&ThreadData
->InEvent
, 0, TRUE
);
292 Status
= KeWaitForSingleObject(ThreadData
->Thread
, Executive
, KernelMode
, FALSE
, NULL
);
293 ok_eq_hex(Status
, STATUS_SUCCESS
);
295 ObDereferenceObject(ThreadData
->Thread
);
296 Status
= ZwClose(ThreadData
->Handle
);
297 ok_eq_hex(Status
, STATUS_SUCCESS
);
298 KeClearEvent(&ThreadData
->InEvent
);
299 KeClearEvent(&ThreadData
->OutEvent
);
304 TestResourceWithThreads(
307 NTSTATUS Status
= STATUS_SUCCESS
;
308 THREAD_DATA ThreadDataShared
;
309 THREAD_DATA ThreadDataShared2
;
310 THREAD_DATA ThreadDataExclusive
;
311 THREAD_DATA ThreadDataSharedStarve
;
312 THREAD_DATA ThreadDataSharedWait
;
313 LARGE_INTEGER Timeout
;
314 Timeout
.QuadPart
= -10 * 1000 * 10; /* 10 ms */
316 InitThreadData(&ThreadDataShared
, Res
, ExAcquireResourceSharedLite
);
317 InitThreadData(&ThreadDataShared2
, Res
, ExAcquireResourceSharedLite
);
318 InitThreadData(&ThreadDataExclusive
, Res
, ExAcquireResourceExclusiveLite
);
319 InitThreadData(&ThreadDataSharedStarve
, Res
, ExAcquireSharedStarveExclusive
);
320 InitThreadData(&ThreadDataSharedWait
, Res
, ExAcquireSharedWaitForExclusive
);
322 /* have a thread acquire the resource shared */
323 Status
= StartThread(&ThreadDataShared
, NULL
, FALSE
, TRUE
);
324 ok_eq_hex(Status
, STATUS_SUCCESS
);
325 CheckResourceStatus(Res
, FALSE
, 0LU, 0LU, 0LU);
326 ok_eq_int(Res
->ActiveCount
, 1);
328 /* a second thread should be able to acquire the resource shared */
329 Status
= StartThread(&ThreadDataShared2
, NULL
, FALSE
, TRUE
);
330 ok_eq_hex(Status
, STATUS_SUCCESS
);
331 CheckResourceStatus(Res
, FALSE
, 0LU, 0LU, 0LU);
332 ok_eq_int(Res
->ActiveCount
, 2);
333 FinishThread(&ThreadDataShared2
);
334 CheckResourceStatus(Res
, FALSE
, 0LU, 0LU, 0LU);
335 ok_eq_int(Res
->ActiveCount
, 1);
337 /* now have a thread that tries to acquire the resource exclusive -- it should fail */
338 Status
= StartThread(&ThreadDataExclusive
, NULL
, FALSE
, FALSE
);
339 ok_eq_hex(Status
, STATUS_SUCCESS
);
340 CheckResourceStatus(Res
, FALSE
, 0LU, 0LU, 0LU);
341 ok_eq_int(Res
->ActiveCount
, 1);
342 FinishThread(&ThreadDataExclusive
);
343 CheckResourceStatus(Res
, FALSE
, 0LU, 0LU, 0LU);
344 ok_eq_int(Res
->ActiveCount
, 1);
346 /* as above, but this time it should block */
347 Status
= StartThread(&ThreadDataExclusive
, &Timeout
, TRUE
, TRUE
);
348 ok_eq_hex(Status
, STATUS_TIMEOUT
);
349 CheckResourceStatus(Res
, FALSE
, 0LU, 1LU, 0LU);
350 ok_eq_int(Res
->ActiveCount
, 1);
352 /* now try another shared one -- it should fail */
353 Status
= StartThread(&ThreadDataShared2
, NULL
, FALSE
, FALSE
);
354 ok_eq_hex(Status
, STATUS_SUCCESS
);
355 CheckResourceStatus(Res
, FALSE
, 0LU, 1LU, 0LU);
356 ok_eq_int(Res
->ActiveCount
, 1);
357 FinishThread(&ThreadDataShared2
);
359 /* same for ExAcquireSharedWaitForExclusive */
360 Status
= StartThread(&ThreadDataSharedWait
, NULL
, FALSE
, FALSE
);
361 ok_eq_hex(Status
, STATUS_SUCCESS
);
362 CheckResourceStatus(Res
, FALSE
, 0LU, 1LU, 0LU);
363 ok_eq_int(Res
->ActiveCount
, 1);
364 FinishThread(&ThreadDataSharedWait
);
366 /* ExAcquireSharedStarveExclusive must get access though! */
367 Status
= StartThread(&ThreadDataSharedStarve
, NULL
, TRUE
, TRUE
);
368 ok_eq_hex(Status
, STATUS_SUCCESS
);
369 CheckResourceStatus(Res
, FALSE
, 0LU, 1LU, 0LU);
370 ok_eq_int(Res
->ActiveCount
, 2);
371 FinishThread(&ThreadDataSharedStarve
);
372 CheckResourceStatus(Res
, FALSE
, 0LU, 1LU, 0LU);
373 ok_eq_int(Res
->ActiveCount
, 1);
375 /* block another shared one */
376 Status
= StartThread(&ThreadDataShared2
, &Timeout
, TRUE
, TRUE
);
377 ok_eq_hex(Status
, STATUS_TIMEOUT
);
378 CheckResourceStatus(Res
, FALSE
, 0LU, 1LU, 1LU);
379 ok_eq_int(Res
->ActiveCount
, 1);
381 /* finish the very first one */
382 FinishThread(&ThreadDataShared
);
384 /* now the blocked exclusive one should get the resource */
385 Status
= KeWaitForSingleObject(&ThreadDataExclusive
.OutEvent
, Executive
, KernelMode
, FALSE
, NULL
);
386 ok_eq_hex(Status
, STATUS_SUCCESS
);
387 CheckResourceStatus(Res
, FALSE
, 0LU, 0LU, 1LU);
388 ok_eq_int(Res
->ActiveCount
, 1);
389 ok_eq_uint((Res
->Flag
& ResourceOwnedExclusive
) != 0, 1);
391 FinishThread(&ThreadDataExclusive
);
392 CheckResourceStatus(Res
, FALSE
, 0LU, 0LU, 0LU);
394 /* now the blocked shared one should resume */
395 Status
= KeWaitForSingleObject(&ThreadDataShared2
.OutEvent
, Executive
, KernelMode
, FALSE
, NULL
);
396 ok_eq_hex(Status
, STATUS_SUCCESS
);
397 CheckResourceStatus(Res
, FALSE
, 0LU, 0LU, 0LU);
398 ok_eq_int(Res
->ActiveCount
, 1);
399 FinishThread(&ThreadDataShared2
);
400 CheckResourceStatus(Res
, FALSE
, 0LU, 0LU, 0LU);
401 ok_eq_int(Res
->ActiveCount
, 0);
404 START_TEST(ExResource
)
410 /* this must be true even with the different structure versions */
411 ASSERT(sizeof(ERESOURCE
) == sizeof(ERESOURCE_2K3
));
413 /* functional tests & internals */
414 Irql
= KeRaiseIrqlToDpcLevel();
415 Status
= ExInitializeResourceLite(&Res
);
416 ok_eq_hex(Status
, STATUS_SUCCESS
);
417 KeLowerIrql(APC_LEVEL
);
419 Status
= ExDeleteResourceLite(&Res
);
420 ok_eq_hex(Status
, STATUS_SUCCESS
);
423 memset(&Res
, 0x55, sizeof Res
);
424 Status
= ExInitializeResourceLite(&Res
);
425 ok_eq_hex(Status
, STATUS_SUCCESS
);
426 CheckResourceFields((PERESOURCE_2K3
)&Res
, FALSE
);
428 CheckResourceStatus(&Res
, FALSE
, 0LU, 0LU, 0LU);
430 TestResourceSharedAccess(&Res
);
431 CheckResourceStatus(&Res
, FALSE
, 0LU, 0LU, 0LU);
433 TestResourceExclusiveAccess(&Res
);
434 CheckResourceStatus(&Res
, FALSE
, 0LU, 0LU, 0LU);
436 TestResourceUndocumentedShortcuts(&Res
, FALSE
);
437 CheckResourceStatus(&Res
, FALSE
, 0LU, 0LU, 0LU);
438 KeRaiseIrql(APC_LEVEL
, &Irql
);
439 TestResourceUndocumentedShortcuts(&Res
, TRUE
);
441 ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
442 CheckResourceStatus(&Res
, FALSE
, 0LU, 0LU, 0LU);
444 TestResourceWithThreads(&Res
);
446 /* ExReinitializeResourceLite cleans up after us */
447 Status
= ExReinitializeResourceLite(&Res
);
448 ok_eq_hex(Status
, STATUS_SUCCESS
);
449 CheckResourceFields((PERESOURCE_2K3
)&Res
, TRUE
);
450 CheckResourceStatus(&Res
, FALSE
, 0LU, 0LU, 0LU);
452 Status
= ExDeleteResourceLite(&Res
);
453 ok_eq_hex(Status
, STATUS_SUCCESS
);
455 /* parameter checks */
456 Status
= STATUS_SUCCESS
;
458 ExInitializeResourceLite(NULL
);
459 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
460 Status
= _SEH2_GetExceptionCode();
462 ok_eq_hex(Status
, STATUS_ACCESS_VIOLATION
);
465 ExDeleteResourceLite(NULL);
466 Status = ExDeleteResourceLite(&Res);*/