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>
13 /* TODO: This is getting pretty long, make it somehow easier to read if possible */
15 /* TODO: this is the Windows Server 2003 version! ROS should use this!
16 * This declaration can be removed once ROS headers are corrected */
17 typedef struct _ERESOURCE_2K3
{
18 LIST_ENTRY SystemResourcesList
;
19 POWNER_ENTRY OwnerTable
;
22 volatile PKSEMAPHORE SharedWaiters
;
23 volatile PKEVENT ExclusiveWaiters
;
24 OWNER_ENTRY OwnerThreads
[2];
25 ULONG ContentionCount
;
26 USHORT NumberOfSharedWaiters
;
27 USHORT NumberOfExclusiveWaiters
;
28 _ANONYMOUS_UNION
union {
30 ULONG_PTR CreatorBackTraceIndex
;
33 } ERESOURCE_2K3
, *PERESOURCE_2K3
;
35 #define CheckResourceFields(Res, Reinit) do \
37 ok_eq_pointer((Res)->SystemResourcesList.Flink->Blink, &(Res)->SystemResourcesList); \
38 ok_eq_pointer((Res)->SystemResourcesList.Blink->Flink, &(Res)->SystemResourcesList); \
39 if (!Reinit) ok_eq_pointer((Res)->OwnerTable, NULL); \
40 ok_eq_int((Res)->ActiveCount, 0); \
41 ok_eq_uint((Res)->Flag, 0); \
42 if (!Reinit) ok_eq_pointer((Res)->SharedWaiters, NULL); \
43 if (!Reinit) ok_eq_pointer((Res)->ExclusiveWaiters, NULL); \
44 ok_eq_ulongptr((Res)->OwnerThreads[0].OwnerThread, 0); \
45 ok_eq_ulong((Res)->OwnerThreads[0].TableSize, 0LU); \
46 ok_eq_ulongptr((Res)->OwnerThreads[1].OwnerThread, 0); \
47 ok_eq_ulong((Res)->OwnerThreads[1].TableSize, 0LU); \
48 ok_eq_ulong((Res)->ContentionCount, 0LU); \
49 ok_eq_uint((Res)->NumberOfSharedWaiters, 0); \
50 ok_eq_uint((Res)->NumberOfExclusiveWaiters, 0); \
51 ok_eq_pointer((Res)->Address, NULL); \
52 ok_eq_ulongptr((Res)->SpinLock, 0); \
55 #define CheckResourceStatus(Res, Exclusive, Shared, ExclusiveWaiters, SharedWaiters) do \
58 ok_bool_true(ExIsResourceAcquiredExclusiveLite(Res), "ExIsResourceAcquiredExclusiveLite returned"); \
60 ok_bool_false(ExIsResourceAcquiredExclusiveLite(Res), "ExIsResourceAcquiredExclusiveLite returned"); \
61 ok_eq_ulong(ExIsResourceAcquiredSharedLite(Res), Shared); \
62 ok_eq_ulong(ExGetExclusiveWaiterCount(Res), ExclusiveWaiters); \
63 ok_eq_ulong(ExGetSharedWaiterCount(Res), SharedWaiters); \
68 TestResourceSharedAccess(
73 KeEnterCriticalRegion();
74 ok_bool_true(ExAcquireResourceSharedLite(Res
, FALSE
), "ExAcquireResourceSharedLite returned"); ++Count
;
75 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
77 ok_bool_true(ExAcquireResourceSharedLite(Res
, FALSE
), "ExAcquireResourceSharedLite returned"); ++Count
;
78 ok_bool_true(ExAcquireResourceSharedLite(Res
, TRUE
), "ExAcquireResourceSharedLite returned"); ++Count
;
79 ok_bool_true(ExAcquireSharedStarveExclusive(Res
, FALSE
), "ExAcquireSharedStarveExclusive returned"); ++Count
;
80 ok_bool_true(ExAcquireSharedStarveExclusive(Res
, TRUE
), "ExAcquireSharedStarveExclusive returned"); ++Count
;
81 ok_bool_true(ExAcquireSharedWaitForExclusive(Res
, FALSE
), "ExAcquireSharedWaitForExclusive returned"); ++Count
;
82 ok_bool_true(ExAcquireSharedWaitForExclusive(Res
, TRUE
), "ExAcquireSharedWaitForExclusive returned"); ++Count
;
83 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
85 /* this one fails, TRUE would deadlock */
86 ok_bool_false(ExAcquireResourceExclusiveLite(Res
, FALSE
), "ExAcquireResourceExclusiveLite returned");
87 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
90 if (!KmtIsCheckedBuild
)
91 ExConvertExclusiveToSharedLite(Res
);
92 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
95 ExReleaseResourceLite(Res
);
96 KeLeaveCriticalRegion();
101 TestResourceExclusiveAccess(
106 KeEnterCriticalRegion();
107 ok_bool_true(ExAcquireResourceExclusiveLite(Res
, FALSE
), "ExAcquireResourceExclusiveLite returned"); ++Count
;
109 CheckResourceStatus(Res
, TRUE
, Count
, 0LU, 0LU);
111 ok_bool_true(ExAcquireResourceExclusiveLite(Res
, TRUE
), "ExAcquireResourceExclusiveLite returned"); ++Count
;
112 CheckResourceStatus(Res
, TRUE
, Count
, 0LU, 0LU);
114 ok_bool_true(ExAcquireResourceSharedLite(Res
, FALSE
), "ExAcquireResourceSharedLite returned"); ++Count
;
115 ok_bool_true(ExAcquireResourceSharedLite(Res
, TRUE
), "ExAcquireResourceSharedLite returned"); ++Count
;
116 ok_bool_true(ExAcquireSharedStarveExclusive(Res
, FALSE
), "ExAcquireSharedStarveExclusive returned"); ++Count
;
117 ok_bool_true(ExAcquireSharedStarveExclusive(Res
, TRUE
), "ExAcquireSharedStarveExclusive returned"); ++Count
;
118 ok_bool_true(ExAcquireSharedWaitForExclusive(Res
, FALSE
), "ExAcquireSharedWaitForExclusive returned"); ++Count
;
119 ok_bool_true(ExAcquireSharedWaitForExclusive(Res
, TRUE
), "ExAcquireSharedWaitForExclusive returned"); ++Count
;
120 CheckResourceStatus(Res
, TRUE
, Count
, 0LU, 0LU);
122 ExConvertExclusiveToSharedLite(Res
);
123 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
126 ExReleaseResourceLite(Res
);
127 KeLeaveCriticalRegion();
132 TestResourceUndocumentedShortcuts(
134 IN BOOLEAN AreApcsDisabled
)
139 ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
140 ok_eq_uint(KeAreAllApcsDisabled(), AreApcsDisabled
);
142 /* ExEnterCriticalRegionAndAcquireResourceShared, ExEnterCriticalRegionAndAcquireSharedWaitForExclusive */
144 Ret
= ExEnterCriticalRegionAndAcquireResourceShared(Res
); ++Count
;
145 ok_eq_pointer(Ret
, KeGetCurrentThread()->Win32Thread
);
146 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
147 ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled
);
148 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
150 Ret
= ExEnterCriticalRegionAndAcquireResourceShared(Res
); ++Count
;
151 ok_eq_pointer(Ret
, KeGetCurrentThread()->Win32Thread
);
152 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
153 ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled
);
154 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
156 ExEnterCriticalRegionAndAcquireSharedWaitForExclusive(Res
); ++Count
;
157 ok_eq_pointer(Ret
, KeGetCurrentThread()->Win32Thread
);
158 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
159 ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled
);
160 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
164 ExReleaseResourceAndLeaveCriticalRegion(Res
);
165 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
166 ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled
);
167 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
170 ExReleaseResourceAndLeaveCriticalRegion(Res
);
171 ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
172 ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled
);
173 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
175 /* ExEnterCriticalRegionAndAcquireResourceExclusive */
177 ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
178 ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled
);
179 Ret
= ExEnterCriticalRegionAndAcquireResourceExclusive(Res
); ++Count
;
180 ok_eq_pointer(Ret
, KeGetCurrentThread()->Win32Thread
);
181 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
182 ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled
);
183 CheckResourceStatus(Res
, TRUE
, Count
, 0LU, 0LU);
185 Ret
= ExEnterCriticalRegionAndAcquireResourceExclusive(Res
); ++Count
;
186 ok_eq_pointer(Ret
, KeGetCurrentThread()->Win32Thread
);
187 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
188 ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled
);
189 CheckResourceStatus(Res
, TRUE
, Count
, 0LU, 0LU);
191 ExReleaseResourceAndLeaveCriticalRegion(Res
); --Count
;
192 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
193 ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled
);
194 CheckResourceStatus(Res
, TRUE
, Count
, 0LU, 0LU);
196 ExReleaseResourceAndLeaveCriticalRegion(Res
); --Count
;
197 ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
198 ok_eq_uint(KeAreAllApcsDisabled(), AreApcsDisabled
);
199 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
202 typedef BOOLEAN (NTAPI
*PACQUIRE_FUNCTION
)(PERESOURCE
, BOOLEAN
);
211 PACQUIRE_FUNCTION AcquireResource
;
214 } THREAD_DATA
, *PTHREAD_DATA
;
219 AcquireResourceThread(
222 NTSTATUS Status
= STATUS_SUCCESS
;
223 PTHREAD_DATA ThreadData
= Context
;
226 KeEnterCriticalRegion();
227 Ret
= ThreadData
->AcquireResource(ThreadData
->Res
, ThreadData
->Wait
);
228 if (ThreadData
->RetExpected
)
229 ok_bool_true(Ret
, "AcquireResource returned");
231 ok_bool_false(Ret
, "AcquireResource returned");
233 ok_bool_false(KeSetEvent(&ThreadData
->OutEvent
, 0, TRUE
), "KeSetEvent returned");
234 Status
= KeWaitForSingleObject(&ThreadData
->InEvent
, Executive
, KernelMode
, FALSE
, NULL
);
235 ok_eq_hex(Status
, STATUS_SUCCESS
);
238 ExReleaseResource(ThreadData
->Res
);
239 KeLeaveCriticalRegion();
245 PTHREAD_DATA ThreadData
,
247 PACQUIRE_FUNCTION AcquireFunction
)
249 ThreadData
->Res
= Res
;
250 KeInitializeEvent(&ThreadData
->InEvent
, NotificationEvent
, FALSE
);
251 KeInitializeEvent(&ThreadData
->OutEvent
, NotificationEvent
, FALSE
);
252 ThreadData
->AcquireResource
= AcquireFunction
;
258 PTHREAD_DATA ThreadData
,
259 PLARGE_INTEGER Timeout
,
263 NTSTATUS Status
= STATUS_SUCCESS
;
264 OBJECT_ATTRIBUTES Attributes
;
266 ThreadData
->Wait
= Wait
;
267 ThreadData
->RetExpected
= RetExpected
;
268 InitializeObjectAttributes(&Attributes
, NULL
, OBJ_KERNEL_HANDLE
, NULL
, NULL
);
269 Status
= PsCreateSystemThread(&ThreadData
->Handle
, GENERIC_ALL
, &Attributes
, NULL
, NULL
, AcquireResourceThread
, ThreadData
);
270 ok_eq_hex(Status
, STATUS_SUCCESS
);
271 Status
= ObReferenceObjectByHandle(ThreadData
->Handle
, SYNCHRONIZE
, PsThreadType
, KernelMode
, (PVOID
*)&ThreadData
->Thread
, NULL
);
272 ok_eq_hex(Status
, STATUS_SUCCESS
);
274 return KeWaitForSingleObject(&ThreadData
->OutEvent
, Executive
, KernelMode
, FALSE
, Timeout
);
280 PTHREAD_DATA ThreadData
)
282 NTSTATUS Status
= STATUS_SUCCESS
;
284 KeSetEvent(&ThreadData
->InEvent
, 0, TRUE
);
285 Status
= KeWaitForSingleObject(ThreadData
->Thread
, Executive
, KernelMode
, FALSE
, NULL
);
286 ok_eq_hex(Status
, STATUS_SUCCESS
);
288 ObDereferenceObject(ThreadData
->Thread
);
289 Status
= ZwClose(ThreadData
->Handle
);
290 ok_eq_hex(Status
, STATUS_SUCCESS
);
291 KeClearEvent(&ThreadData
->InEvent
);
292 KeClearEvent(&ThreadData
->OutEvent
);
297 TestResourceWithThreads(
300 NTSTATUS Status
= STATUS_SUCCESS
;
301 THREAD_DATA ThreadDataShared
;
302 THREAD_DATA ThreadDataShared2
;
303 THREAD_DATA ThreadDataExclusive
;
304 THREAD_DATA ThreadDataSharedStarve
;
305 THREAD_DATA ThreadDataSharedWait
;
306 LARGE_INTEGER Timeout
;
307 Timeout
.QuadPart
= -10 * 1000 * 10; /* 10 ms */
309 InitThreadData(&ThreadDataShared
, Res
, ExAcquireResourceSharedLite
);
310 InitThreadData(&ThreadDataShared2
, Res
, ExAcquireResourceSharedLite
);
311 InitThreadData(&ThreadDataExclusive
, Res
, ExAcquireResourceExclusiveLite
);
312 InitThreadData(&ThreadDataSharedStarve
, Res
, ExAcquireSharedStarveExclusive
);
313 InitThreadData(&ThreadDataSharedWait
, Res
, ExAcquireSharedWaitForExclusive
);
315 /* have a thread acquire the resource shared */
316 Status
= StartThread(&ThreadDataShared
, NULL
, FALSE
, TRUE
);
317 ok_eq_hex(Status
, STATUS_SUCCESS
);
318 CheckResourceStatus(Res
, FALSE
, 0LU, 0LU, 0LU);
319 ok_eq_int(Res
->ActiveCount
, 1);
321 /* a second thread should be able to acquire the resource shared */
322 Status
= StartThread(&ThreadDataShared2
, NULL
, FALSE
, TRUE
);
323 ok_eq_hex(Status
, STATUS_SUCCESS
);
324 CheckResourceStatus(Res
, FALSE
, 0LU, 0LU, 0LU);
325 ok_eq_int(Res
->ActiveCount
, 2);
326 FinishThread(&ThreadDataShared2
);
327 CheckResourceStatus(Res
, FALSE
, 0LU, 0LU, 0LU);
328 ok_eq_int(Res
->ActiveCount
, 1);
330 /* now have a thread that tries to acquire the resource exclusive -- it should fail */
331 Status
= StartThread(&ThreadDataExclusive
, NULL
, FALSE
, FALSE
);
332 ok_eq_hex(Status
, STATUS_SUCCESS
);
333 CheckResourceStatus(Res
, FALSE
, 0LU, 0LU, 0LU);
334 ok_eq_int(Res
->ActiveCount
, 1);
335 FinishThread(&ThreadDataExclusive
);
336 CheckResourceStatus(Res
, FALSE
, 0LU, 0LU, 0LU);
337 ok_eq_int(Res
->ActiveCount
, 1);
339 /* as above, but this time it should block */
340 Status
= StartThread(&ThreadDataExclusive
, &Timeout
, TRUE
, TRUE
);
341 ok_eq_hex(Status
, STATUS_TIMEOUT
);
342 CheckResourceStatus(Res
, FALSE
, 0LU, 1LU, 0LU);
343 ok_eq_int(Res
->ActiveCount
, 1);
345 /* now try another shared one -- it should fail */
346 Status
= StartThread(&ThreadDataShared2
, NULL
, FALSE
, FALSE
);
347 ok_eq_hex(Status
, STATUS_SUCCESS
);
348 CheckResourceStatus(Res
, FALSE
, 0LU, 1LU, 0LU);
349 ok_eq_int(Res
->ActiveCount
, 1);
350 FinishThread(&ThreadDataShared2
);
352 /* same for ExAcquireSharedWaitForExclusive */
353 Status
= StartThread(&ThreadDataSharedWait
, 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(&ThreadDataSharedWait
);
359 /* ExAcquireSharedStarveExclusive must get access though! */
360 Status
= StartThread(&ThreadDataSharedStarve
, NULL
, TRUE
, TRUE
);
361 ok_eq_hex(Status
, STATUS_SUCCESS
);
362 CheckResourceStatus(Res
, FALSE
, 0LU, 1LU, 0LU);
363 ok_eq_int(Res
->ActiveCount
, 2);
364 FinishThread(&ThreadDataSharedStarve
);
365 CheckResourceStatus(Res
, FALSE
, 0LU, 1LU, 0LU);
366 ok_eq_int(Res
->ActiveCount
, 1);
368 /* block another shared one */
369 Status
= StartThread(&ThreadDataShared2
, &Timeout
, TRUE
, TRUE
);
370 ok_eq_hex(Status
, STATUS_TIMEOUT
);
371 CheckResourceStatus(Res
, FALSE
, 0LU, 1LU, 1LU);
372 ok_eq_int(Res
->ActiveCount
, 1);
374 /* finish the very first one */
375 FinishThread(&ThreadDataShared
);
377 /* now the blocked exclusive one should get the resource */
378 Status
= KeWaitForSingleObject(&ThreadDataExclusive
.OutEvent
, Executive
, KernelMode
, FALSE
, NULL
);
379 ok_eq_hex(Status
, STATUS_SUCCESS
);
380 CheckResourceStatus(Res
, FALSE
, 0LU, 0LU, 1LU);
381 ok_eq_int(Res
->ActiveCount
, 1);
382 ok_eq_uint((Res
->Flag
& ResourceOwnedExclusive
) != 0, 1);
384 FinishThread(&ThreadDataExclusive
);
385 CheckResourceStatus(Res
, FALSE
, 0LU, 0LU, 0LU);
387 /* now the blocked shared one should resume */
388 Status
= KeWaitForSingleObject(&ThreadDataShared2
.OutEvent
, Executive
, KernelMode
, FALSE
, NULL
);
389 ok_eq_hex(Status
, STATUS_SUCCESS
);
390 CheckResourceStatus(Res
, FALSE
, 0LU, 0LU, 0LU);
391 ok_eq_int(Res
->ActiveCount
, 1);
392 FinishThread(&ThreadDataShared2
);
393 CheckResourceStatus(Res
, FALSE
, 0LU, 0LU, 0LU);
394 ok_eq_int(Res
->ActiveCount
, 0);
397 START_TEST(ExResource
)
403 /* this must be true even with the different structure versions */
404 ASSERT(sizeof(ERESOURCE
) == sizeof(ERESOURCE_2K3
));
406 /* functional tests & internals */
407 Irql
= KeRaiseIrqlToDpcLevel();
408 Status
= ExInitializeResourceLite(&Res
);
409 ok_eq_hex(Status
, STATUS_SUCCESS
);
410 KeLowerIrql(APC_LEVEL
);
412 Status
= ExDeleteResourceLite(&Res
);
413 ok_eq_hex(Status
, STATUS_SUCCESS
);
416 memset(&Res
, 0x55, sizeof Res
);
417 Status
= ExInitializeResourceLite(&Res
);
418 ok_eq_hex(Status
, STATUS_SUCCESS
);
419 CheckResourceFields((PERESOURCE_2K3
)&Res
, FALSE
);
421 CheckResourceStatus(&Res
, FALSE
, 0LU, 0LU, 0LU);
423 TestResourceSharedAccess(&Res
);
424 CheckResourceStatus(&Res
, FALSE
, 0LU, 0LU, 0LU);
426 TestResourceExclusiveAccess(&Res
);
427 CheckResourceStatus(&Res
, FALSE
, 0LU, 0LU, 0LU);
429 TestResourceUndocumentedShortcuts(&Res
, FALSE
);
430 CheckResourceStatus(&Res
, FALSE
, 0LU, 0LU, 0LU);
431 KeRaiseIrql(APC_LEVEL
, &Irql
);
432 TestResourceUndocumentedShortcuts(&Res
, TRUE
);
434 ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
435 CheckResourceStatus(&Res
, FALSE
, 0LU, 0LU, 0LU);
437 TestResourceWithThreads(&Res
);
439 /* ExReinitializeResourceLite cleans up after us */
440 Status
= ExReinitializeResourceLite(&Res
);
441 ok_eq_hex(Status
, STATUS_SUCCESS
);
442 CheckResourceFields((PERESOURCE_2K3
)&Res
, TRUE
);
443 CheckResourceStatus(&Res
, FALSE
, 0LU, 0LU, 0LU);
445 Status
= ExDeleteResourceLite(&Res
);
446 ok_eq_hex(Status
, STATUS_SUCCESS
);
448 /* parameter checks */
449 Status
= STATUS_SUCCESS
;
451 ExInitializeResourceLite(NULL
);
452 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
453 Status
= _SEH2_GetExceptionCode();
455 ok_eq_hex(Status
, STATUS_ACCESS_VIOLATION
);
458 ExDeleteResourceLite(NULL);
459 Status = ExDeleteResourceLite(&Res);*/