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
;
29 PVOID Reserved2
; /* TODO: not sure if this should be in here for 2k3 */
31 _ANONYMOUS_UNION
union {
33 ULONG_PTR CreatorBackTraceIndex
;
36 } ERESOURCE_2K3
, *PERESOURCE_2K3
;
38 #define CheckResourceFields(Res, Reinit) do \
40 ok_eq_pointer((Res)->SystemResourcesList.Flink->Blink, &(Res)->SystemResourcesList); \
41 ok_eq_pointer((Res)->SystemResourcesList.Blink->Flink, &(Res)->SystemResourcesList); \
42 if (!Reinit) ok_eq_pointer((Res)->OwnerTable, NULL); \
43 ok_eq_int((Res)->ActiveCount, 0); \
44 ok_eq_uint((Res)->Flag, 0); \
45 if (!Reinit) ok_eq_pointer((Res)->SharedWaiters, NULL); \
46 if (!Reinit) ok_eq_pointer((Res)->ExclusiveWaiters, NULL); \
47 ok_eq_pointer((PVOID)(Res)->OwnerThreads[0].OwnerThread, NULL); \
48 ok_eq_ulong((Res)->OwnerThreads[0].TableSize, 0LU); \
49 ok_eq_pointer((PVOID)(Res)->OwnerThreads[1].OwnerThread, NULL); \
50 ok_eq_ulong((Res)->OwnerThreads[1].TableSize, 0LU); \
51 ok_eq_ulong((Res)->ContentionCount, 0LU); \
52 ok_eq_uint((Res)->NumberOfSharedWaiters, 0); \
53 ok_eq_uint((Res)->NumberOfExclusiveWaiters, 0); \
54 /* ok_eq_pointer((Res)->Reserved2, NULL); */ \
55 ok_eq_pointer((Res)->Address, NULL); \
56 ok_eq_pointer((PVOID)(Res)->SpinLock, NULL); \
59 #define CheckResourceStatus(Res, Exclusive, Shared, ExclusiveWaiters, SharedWaiters) do \
62 ok_bool_true(ExIsResourceAcquiredExclusiveLite(Res), "ExIsResourceAcquiredExclusiveLite returned"); \
64 ok_bool_false(ExIsResourceAcquiredExclusiveLite(Res), "ExIsResourceAcquiredExclusiveLite returned"); \
65 ok_eq_ulong(ExIsResourceAcquiredSharedLite(Res), Shared); \
66 ok_eq_ulong(ExGetExclusiveWaiterCount(Res), ExclusiveWaiters); \
67 ok_eq_ulong(ExGetSharedWaiterCount(Res), SharedWaiters); \
72 TestResourceSharedAccess(
77 KeEnterCriticalRegion();
78 ok_bool_true(ExAcquireResourceSharedLite(Res
, FALSE
), "ExAcquireResourceSharedLite returned"); ++Count
;
79 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
81 ok_bool_true(ExAcquireResourceSharedLite(Res
, FALSE
), "ExAcquireResourceSharedLite returned"); ++Count
;
82 ok_bool_true(ExAcquireResourceSharedLite(Res
, TRUE
), "ExAcquireResourceSharedLite returned"); ++Count
;
83 ok_bool_true(ExAcquireSharedStarveExclusive(Res
, FALSE
), "ExAcquireSharedStarveExclusive returned"); ++Count
;
84 ok_bool_true(ExAcquireSharedStarveExclusive(Res
, TRUE
), "ExAcquireSharedStarveExclusive returned"); ++Count
;
85 ok_bool_true(ExAcquireSharedWaitForExclusive(Res
, FALSE
), "ExAcquireSharedWaitForExclusive returned"); ++Count
;
86 ok_bool_true(ExAcquireSharedWaitForExclusive(Res
, TRUE
), "ExAcquireSharedWaitForExclusive returned"); ++Count
;
87 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
89 /* this one fails, TRUE would deadlock */
90 ok_bool_false(ExAcquireResourceExclusiveLite(Res
, FALSE
), "ExAcquireResourceExclusiveLite returned");
91 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
93 /* this must not crash or deadlock (but can assert) */
94 ExConvertExclusiveToSharedLite(Res
);
95 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
98 ExReleaseResourceLite(Res
);
99 KeLeaveCriticalRegion();
104 TestResourceExclusiveAccess(
109 KeEnterCriticalRegion();
110 ok_bool_true(ExAcquireResourceExclusiveLite(Res
, FALSE
), "ExAcquireResourceExclusiveLite returned"); ++Count
;
112 CheckResourceStatus(Res
, TRUE
, Count
, 0LU, 0LU);
114 ok_bool_true(ExAcquireResourceExclusiveLite(Res
, TRUE
), "ExAcquireResourceExclusiveLite returned"); ++Count
;
115 CheckResourceStatus(Res
, TRUE
, Count
, 0LU, 0LU);
117 ok_bool_true(ExAcquireResourceSharedLite(Res
, FALSE
), "ExAcquireResourceSharedLite returned"); ++Count
;
118 ok_bool_true(ExAcquireResourceSharedLite(Res
, TRUE
), "ExAcquireResourceSharedLite returned"); ++Count
;
119 ok_bool_true(ExAcquireSharedStarveExclusive(Res
, FALSE
), "ExAcquireSharedStarveExclusive returned"); ++Count
;
120 ok_bool_true(ExAcquireSharedStarveExclusive(Res
, TRUE
), "ExAcquireSharedStarveExclusive returned"); ++Count
;
121 ok_bool_true(ExAcquireSharedWaitForExclusive(Res
, FALSE
), "ExAcquireSharedWaitForExclusive returned"); ++Count
;
122 ok_bool_true(ExAcquireSharedWaitForExclusive(Res
, TRUE
), "ExAcquireSharedWaitForExclusive returned"); ++Count
;
123 CheckResourceStatus(Res
, TRUE
, Count
, 0LU, 0LU);
125 ExConvertExclusiveToSharedLite(Res
);
126 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
129 ExReleaseResourceLite(Res
);
130 KeLeaveCriticalRegion();
135 TestResourceUndocumentedShortcuts(
137 IN BOOLEAN AreApcsDisabled
)
142 ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
143 ok_eq_uint(KeAreAllApcsDisabled(), AreApcsDisabled
);
145 /* ExEnterCriticalRegionAndAcquireResourceShared, ExEnterCriticalRegionAndAcquireSharedWaitForExclusive */
147 Ret
= ExEnterCriticalRegionAndAcquireResourceShared(Res
); ++Count
;
148 ok_eq_pointer(Ret
, KeGetCurrentThread()->Win32Thread
);
149 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
150 ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled
);
151 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
153 Ret
= ExEnterCriticalRegionAndAcquireResourceShared(Res
); ++Count
;
154 ok_eq_pointer(Ret
, KeGetCurrentThread()->Win32Thread
);
155 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
156 ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled
);
157 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
159 ExEnterCriticalRegionAndAcquireSharedWaitForExclusive(Res
); ++Count
;
160 ok_eq_pointer(Ret
, KeGetCurrentThread()->Win32Thread
);
161 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
162 ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled
);
163 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
167 ExReleaseResourceAndLeaveCriticalRegion(Res
);
168 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
169 ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled
);
170 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
173 ExReleaseResourceAndLeaveCriticalRegion(Res
);
174 ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
175 ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled
);
176 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
178 /* ExEnterCriticalRegionAndAcquireResourceExclusive */
180 ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
181 ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled
);
182 Ret
= ExEnterCriticalRegionAndAcquireResourceExclusive(Res
); ++Count
;
183 ok_eq_pointer(Ret
, KeGetCurrentThread()->Win32Thread
);
184 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
185 ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled
);
186 CheckResourceStatus(Res
, TRUE
, Count
, 0LU, 0LU);
188 Ret
= ExEnterCriticalRegionAndAcquireResourceExclusive(Res
); ++Count
;
189 ok_eq_pointer(Ret
, KeGetCurrentThread()->Win32Thread
);
190 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
191 ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled
);
192 CheckResourceStatus(Res
, TRUE
, Count
, 0LU, 0LU);
194 ExReleaseResourceAndLeaveCriticalRegion(Res
); --Count
;
195 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
196 ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled
);
197 CheckResourceStatus(Res
, TRUE
, Count
, 0LU, 0LU);
199 ExReleaseResourceAndLeaveCriticalRegion(Res
); --Count
;
200 ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
201 ok_eq_uint(KeAreAllApcsDisabled(), AreApcsDisabled
);
202 CheckResourceStatus(Res
, FALSE
, Count
, 0LU, 0LU);
205 typedef BOOLEAN (NTAPI
*PACQUIRE_FUNCTION
)(PERESOURCE
, BOOLEAN
);
214 PACQUIRE_FUNCTION AcquireResource
;
217 } THREAD_DATA
, *PTHREAD_DATA
;
222 AcquireResourceThread(
225 NTSTATUS Status
= STATUS_SUCCESS
;
226 PTHREAD_DATA ThreadData
= Context
;
229 KeEnterCriticalRegion();
230 Ret
= ThreadData
->AcquireResource(ThreadData
->Res
, ThreadData
->Wait
);
231 if (ThreadData
->RetExpected
)
232 ok_bool_true(Ret
, "AcquireResource returned");
234 ok_bool_false(Ret
, "AcquireResource returned");
236 ok_bool_false(KeSetEvent(&ThreadData
->OutEvent
, 0, TRUE
), "KeSetEvent returned");
237 Status
= KeWaitForSingleObject(&ThreadData
->InEvent
, Executive
, KernelMode
, FALSE
, NULL
);
238 ok_eq_hex(Status
, STATUS_SUCCESS
);
241 ExReleaseResource(ThreadData
->Res
);
242 KeLeaveCriticalRegion();
248 PTHREAD_DATA ThreadData
,
250 PACQUIRE_FUNCTION AcquireFunction
)
252 ThreadData
->Res
= Res
;
253 KeInitializeEvent(&ThreadData
->InEvent
, NotificationEvent
, FALSE
);
254 KeInitializeEvent(&ThreadData
->OutEvent
, NotificationEvent
, FALSE
);
255 ThreadData
->AcquireResource
= AcquireFunction
;
261 PTHREAD_DATA ThreadData
,
262 PLARGE_INTEGER Timeout
,
266 NTSTATUS Status
= STATUS_SUCCESS
;
267 OBJECT_ATTRIBUTES Attributes
;
269 ThreadData
->Wait
= Wait
;
270 ThreadData
->RetExpected
= RetExpected
;
271 InitializeObjectAttributes(&Attributes
, NULL
, OBJ_KERNEL_HANDLE
, NULL
, NULL
);
272 Status
= PsCreateSystemThread(&ThreadData
->Handle
, GENERIC_ALL
, &Attributes
, NULL
, NULL
, AcquireResourceThread
, ThreadData
);
273 ok_eq_hex(Status
, STATUS_SUCCESS
);
274 Status
= ObReferenceObjectByHandle(ThreadData
->Handle
, SYNCHRONIZE
, PsThreadType
, KernelMode
, (PVOID
*)&ThreadData
->Thread
, NULL
);
275 ok_eq_hex(Status
, STATUS_SUCCESS
);
277 return KeWaitForSingleObject(&ThreadData
->OutEvent
, Executive
, KernelMode
, FALSE
, Timeout
);
283 PTHREAD_DATA ThreadData
)
285 NTSTATUS Status
= STATUS_SUCCESS
;
287 KeSetEvent(&ThreadData
->InEvent
, 0, TRUE
);
288 Status
= KeWaitForSingleObject(ThreadData
->Thread
, Executive
, KernelMode
, FALSE
, NULL
);
289 ok_eq_hex(Status
, STATUS_SUCCESS
);
291 ObDereferenceObject(ThreadData
->Thread
);
292 Status
= ZwClose(ThreadData
->Handle
);
293 ok_eq_hex(Status
, STATUS_SUCCESS
);
294 KeClearEvent(&ThreadData
->InEvent
);
295 KeClearEvent(&ThreadData
->OutEvent
);
300 TestResourceWithThreads(
303 NTSTATUS Status
= STATUS_SUCCESS
;
304 THREAD_DATA ThreadDataShared
;
305 THREAD_DATA ThreadDataShared2
;
306 THREAD_DATA ThreadDataExclusive
;
307 THREAD_DATA ThreadDataSharedStarve
;
308 THREAD_DATA ThreadDataSharedWait
;
309 LARGE_INTEGER Timeout
;
310 Timeout
.QuadPart
= -10 * 1000 * 10; /* 10 ms */
312 InitThreadData(&ThreadDataShared
, Res
, ExAcquireResourceSharedLite
);
313 InitThreadData(&ThreadDataShared2
, Res
, ExAcquireResourceSharedLite
);
314 InitThreadData(&ThreadDataExclusive
, Res
, ExAcquireResourceExclusiveLite
);
315 InitThreadData(&ThreadDataSharedStarve
, Res
, ExAcquireSharedStarveExclusive
);
316 InitThreadData(&ThreadDataSharedWait
, Res
, ExAcquireSharedWaitForExclusive
);
318 /* have a thread acquire the resource shared */
319 Status
= StartThread(&ThreadDataShared
, NULL
, FALSE
, TRUE
);
320 ok_eq_hex(Status
, STATUS_SUCCESS
);
321 CheckResourceStatus(Res
, FALSE
, 0LU, 0LU, 0LU);
322 ok_eq_int(Res
->ActiveCount
, 1);
324 /* a second thread should be able to acquire the resource shared */
325 Status
= StartThread(&ThreadDataShared2
, NULL
, FALSE
, TRUE
);
326 ok_eq_hex(Status
, STATUS_SUCCESS
);
327 CheckResourceStatus(Res
, FALSE
, 0LU, 0LU, 0LU);
328 ok_eq_int(Res
->ActiveCount
, 2);
329 FinishThread(&ThreadDataShared2
);
330 CheckResourceStatus(Res
, FALSE
, 0LU, 0LU, 0LU);
331 ok_eq_int(Res
->ActiveCount
, 1);
333 /* now have a thread that tries to acquire the resource exclusive -- it should fail */
334 Status
= StartThread(&ThreadDataExclusive
, NULL
, FALSE
, FALSE
);
335 ok_eq_hex(Status
, STATUS_SUCCESS
);
336 CheckResourceStatus(Res
, FALSE
, 0LU, 0LU, 0LU);
337 ok_eq_int(Res
->ActiveCount
, 1);
338 FinishThread(&ThreadDataExclusive
);
339 CheckResourceStatus(Res
, FALSE
, 0LU, 0LU, 0LU);
340 ok_eq_int(Res
->ActiveCount
, 1);
342 /* as above, but this time it should block */
343 Status
= StartThread(&ThreadDataExclusive
, &Timeout
, TRUE
, TRUE
);
344 ok_eq_hex(Status
, STATUS_TIMEOUT
);
345 CheckResourceStatus(Res
, FALSE
, 0LU, 1LU, 0LU);
346 ok_eq_int(Res
->ActiveCount
, 1);
348 /* now try another shared one -- it should fail */
349 Status
= StartThread(&ThreadDataShared2
, NULL
, FALSE
, FALSE
);
350 ok_eq_hex(Status
, STATUS_SUCCESS
);
351 CheckResourceStatus(Res
, FALSE
, 0LU, 1LU, 0LU);
352 ok_eq_int(Res
->ActiveCount
, 1);
353 FinishThread(&ThreadDataShared2
);
355 /* same for ExAcquireSharedWaitForExclusive */
356 Status
= StartThread(&ThreadDataSharedWait
, NULL
, FALSE
, FALSE
);
357 ok_eq_hex(Status
, STATUS_SUCCESS
);
358 CheckResourceStatus(Res
, FALSE
, 0LU, 1LU, 0LU);
359 ok_eq_int(Res
->ActiveCount
, 1);
360 FinishThread(&ThreadDataSharedWait
);
362 /* ExAcquireSharedStarveExclusive must get access though! */
363 Status
= StartThread(&ThreadDataSharedStarve
, NULL
, TRUE
, TRUE
);
364 ok_eq_hex(Status
, STATUS_SUCCESS
);
365 CheckResourceStatus(Res
, FALSE
, 0LU, 1LU, 0LU);
366 ok_eq_int(Res
->ActiveCount
, 2);
367 FinishThread(&ThreadDataSharedStarve
);
368 CheckResourceStatus(Res
, FALSE
, 0LU, 1LU, 0LU);
369 ok_eq_int(Res
->ActiveCount
, 1);
371 /* block another shared one */
372 Status
= StartThread(&ThreadDataShared2
, &Timeout
, TRUE
, TRUE
);
373 ok_eq_hex(Status
, STATUS_TIMEOUT
);
374 CheckResourceStatus(Res
, FALSE
, 0LU, 1LU, 1LU);
375 ok_eq_int(Res
->ActiveCount
, 1);
377 /* finish the very first one */
378 FinishThread(&ThreadDataShared
);
380 /* now the blocked exclusive one should get the resource */
381 Status
= KeWaitForSingleObject(&ThreadDataExclusive
.OutEvent
, Executive
, KernelMode
, FALSE
, NULL
);
382 ok_eq_hex(Status
, STATUS_SUCCESS
);
383 CheckResourceStatus(Res
, FALSE
, 0LU, 0LU, 1LU);
384 ok_eq_int(Res
->ActiveCount
, 1);
385 ok_eq_uint((Res
->Flag
& ResourceOwnedExclusive
) != 0, 1);
387 FinishThread(&ThreadDataExclusive
);
388 CheckResourceStatus(Res
, FALSE
, 0LU, 0LU, 0LU);
390 /* now the blocked shared one should resume */
391 Status
= KeWaitForSingleObject(&ThreadDataShared2
.OutEvent
, Executive
, KernelMode
, FALSE
, NULL
);
392 ok_eq_hex(Status
, STATUS_SUCCESS
);
393 CheckResourceStatus(Res
, FALSE
, 0LU, 0LU, 0LU);
394 ok_eq_int(Res
->ActiveCount
, 1);
395 FinishThread(&ThreadDataShared2
);
396 CheckResourceStatus(Res
, FALSE
, 0LU, 0LU, 0LU);
397 ok_eq_int(Res
->ActiveCount
, 0);
400 START_TEST(ExResource
)
406 /* this must be true even with the different structure versions */
407 ASSERT(sizeof(ERESOURCE
) == sizeof(ERESOURCE_2K3
));
409 /* functional tests & internals */
410 Irql
= KeRaiseIrqlToDpcLevel();
411 Status
= ExInitializeResourceLite(&Res
);
412 ok_eq_hex(Status
, STATUS_SUCCESS
);
413 KeLowerIrql(APC_LEVEL
);
415 Status
= ExDeleteResourceLite(&Res
);
416 ok_eq_hex(Status
, STATUS_SUCCESS
);
419 memset(&Res
, 0x55, sizeof Res
);
420 Status
= ExInitializeResourceLite(&Res
);
421 ok_eq_hex(Status
, STATUS_SUCCESS
);
422 CheckResourceFields((PERESOURCE_2K3
)&Res
, FALSE
);
424 CheckResourceStatus(&Res
, FALSE
, 0LU, 0LU, 0LU);
426 TestResourceSharedAccess(&Res
);
427 CheckResourceStatus(&Res
, FALSE
, 0LU, 0LU, 0LU);
429 TestResourceExclusiveAccess(&Res
);
430 CheckResourceStatus(&Res
, FALSE
, 0LU, 0LU, 0LU);
432 TestResourceUndocumentedShortcuts(&Res
, FALSE
);
433 CheckResourceStatus(&Res
, FALSE
, 0LU, 0LU, 0LU);
434 KeRaiseIrql(APC_LEVEL
, &Irql
);
435 TestResourceUndocumentedShortcuts(&Res
, TRUE
);
437 ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
438 CheckResourceStatus(&Res
, FALSE
, 0LU, 0LU, 0LU);
440 TestResourceWithThreads(&Res
);
442 /* ExReinitializeResourceLite cleans up after us */
443 Status
= ExReinitializeResourceLite(&Res
);
444 ok_eq_hex(Status
, STATUS_SUCCESS
);
445 CheckResourceFields((PERESOURCE_2K3
)&Res
, TRUE
);
446 CheckResourceStatus(&Res
, FALSE
, 0LU, 0LU, 0LU);
448 Status
= ExDeleteResourceLite(&Res
);
449 ok_eq_hex(Status
, STATUS_SUCCESS
);
451 /* parameter checks */
452 Status
= STATUS_SUCCESS
;
454 ExInitializeResourceLite(NULL
);
455 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
456 Status
= _SEH2_GetExceptionCode();
458 ok_eq_hex(Status
, STATUS_ACCESS_VIOLATION
);
461 ExDeleteResourceLite(NULL);
462 Status = ExDeleteResourceLite(&Res);*/