[USP10_WINETEST] Sync with Wine Staging 2.9. CORE-13362
[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 PKSTART_ROUTINE StartRoutine;
276 } THREAD_DATA, *PTHREAD_DATA;
277
278 static
279 VOID
280 NTAPI
281 AcquireResourceThread(
282 PVOID Context)
283 {
284 NTSTATUS Status = STATUS_SUCCESS;
285 PTHREAD_DATA ThreadData = Context;
286 BOOLEAN Ret;
287
288 KeEnterCriticalRegion();
289 Ret = ThreadData->AcquireResource(ThreadData->Res, ThreadData->Wait);
290 if (ThreadData->RetExpected)
291 ok_bool_true(Ret, "AcquireResource returned");
292 else
293 ok_bool_false(Ret, "AcquireResource returned");
294
295 ok_bool_false(KeSetEvent(&ThreadData->OutEvent, 0, TRUE), "KeSetEvent returned");
296 Status = KeWaitForSingleObject(&ThreadData->InEvent, Executive, KernelMode, FALSE, NULL);
297 ok_eq_hex(Status, STATUS_SUCCESS);
298
299 if (Ret)
300 ExReleaseResource(ThreadData->Res);
301 KeLeaveCriticalRegion();
302 }
303
304 static
305 VOID
306 InitThreadDataEx(
307 PTHREAD_DATA ThreadData,
308 PERESOURCE Res,
309 PACQUIRE_FUNCTION AcquireFunction,
310 PKSTART_ROUTINE StartRoutine)
311 {
312 ThreadData->Res = Res;
313 KeInitializeEvent(&ThreadData->InEvent, NotificationEvent, FALSE);
314 KeInitializeEvent(&ThreadData->OutEvent, NotificationEvent, FALSE);
315 ThreadData->AcquireResource = AcquireFunction;
316 ThreadData->StartRoutine = StartRoutine;
317 }
318
319 static
320 VOID
321 InitThreadData(
322 PTHREAD_DATA ThreadData,
323 PERESOURCE Res,
324 PACQUIRE_FUNCTION AcquireFunction)
325 {
326 InitThreadDataEx(ThreadData, Res, AcquireFunction, AcquireResourceThread);
327 }
328
329 static
330 NTSTATUS
331 StartThread(
332 PTHREAD_DATA ThreadData,
333 PLARGE_INTEGER Timeout,
334 BOOLEAN Wait,
335 BOOLEAN RetExpected)
336 {
337 NTSTATUS Status = STATUS_SUCCESS;
338 OBJECT_ATTRIBUTES Attributes;
339
340 ThreadData->Wait = Wait;
341 ThreadData->RetExpected = RetExpected;
342 InitializeObjectAttributes(&Attributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
343 Status = PsCreateSystemThread(&ThreadData->Handle, GENERIC_ALL, &Attributes, NULL, NULL, ThreadData->StartRoutine, ThreadData);
344 ok_eq_hex(Status, STATUS_SUCCESS);
345 Status = ObReferenceObjectByHandle(ThreadData->Handle, SYNCHRONIZE, *PsThreadType, KernelMode, (PVOID *)&ThreadData->Thread, NULL);
346 ok_eq_hex(Status, STATUS_SUCCESS);
347
348 return KeWaitForSingleObject(&ThreadData->OutEvent, Executive, KernelMode, FALSE, Timeout);
349 }
350
351 static
352 VOID
353 FinishThread(
354 PTHREAD_DATA ThreadData)
355 {
356 NTSTATUS Status = STATUS_SUCCESS;
357
358 KeSetEvent(&ThreadData->InEvent, 0, TRUE);
359 Status = KeWaitForSingleObject(ThreadData->Thread, Executive, KernelMode, FALSE, NULL);
360 ok_eq_hex(Status, STATUS_SUCCESS);
361
362 ObDereferenceObject(ThreadData->Thread);
363 Status = ZwClose(ThreadData->Handle);
364 ok_eq_hex(Status, STATUS_SUCCESS);
365 KeClearEvent(&ThreadData->InEvent);
366 KeClearEvent(&ThreadData->OutEvent);
367 }
368
369 static
370 VOID
371 TestResourceWithThreads(
372 IN PERESOURCE Res)
373 {
374 NTSTATUS Status = STATUS_SUCCESS;
375 THREAD_DATA ThreadDataShared;
376 THREAD_DATA ThreadDataShared2;
377 THREAD_DATA ThreadDataExclusive;
378 THREAD_DATA ThreadDataSharedStarve;
379 THREAD_DATA ThreadDataSharedWait;
380 LARGE_INTEGER Timeout;
381 Timeout.QuadPart = -10 * 1000 * 10; /* 10 ms */
382
383 InitThreadData(&ThreadDataShared, Res, ExAcquireResourceSharedLite);
384 InitThreadData(&ThreadDataShared2, Res, ExAcquireResourceSharedLite);
385 InitThreadData(&ThreadDataExclusive, Res, ExAcquireResourceExclusiveLite);
386 InitThreadData(&ThreadDataSharedStarve, Res, ExAcquireSharedStarveExclusive);
387 InitThreadData(&ThreadDataSharedWait, Res, ExAcquireSharedWaitForExclusive);
388
389 /* have a thread acquire the resource shared */
390 Status = StartThread(&ThreadDataShared, NULL, FALSE, TRUE);
391 ok_eq_hex(Status, STATUS_SUCCESS);
392 CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
393 ok_eq_int(Res->ActiveCount, 1);
394
395 /* a second thread should be able to acquire the resource shared */
396 Status = StartThread(&ThreadDataShared2, NULL, FALSE, TRUE);
397 ok_eq_hex(Status, STATUS_SUCCESS);
398 CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
399 ok_eq_int(Res->ActiveCount, 2);
400 FinishThread(&ThreadDataShared2);
401 CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
402 ok_eq_int(Res->ActiveCount, 1);
403
404 /* now have a thread that tries to acquire the resource exclusive -- it should fail */
405 Status = StartThread(&ThreadDataExclusive, NULL, FALSE, FALSE);
406 ok_eq_hex(Status, STATUS_SUCCESS);
407 CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
408 ok_eq_int(Res->ActiveCount, 1);
409 FinishThread(&ThreadDataExclusive);
410 CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
411 ok_eq_int(Res->ActiveCount, 1);
412
413 /* as above, but this time it should block */
414 Status = StartThread(&ThreadDataExclusive, &Timeout, TRUE, TRUE);
415 ok_eq_hex(Status, STATUS_TIMEOUT);
416 CheckResourceStatus(Res, FALSE, 0LU, 1LU, 0LU);
417 ok_eq_int(Res->ActiveCount, 1);
418
419 /* now try another shared one -- it should fail */
420 Status = StartThread(&ThreadDataShared2, NULL, FALSE, FALSE);
421 ok_eq_hex(Status, STATUS_SUCCESS);
422 CheckResourceStatus(Res, FALSE, 0LU, 1LU, 0LU);
423 ok_eq_int(Res->ActiveCount, 1);
424 FinishThread(&ThreadDataShared2);
425
426 /* same for ExAcquireSharedWaitForExclusive */
427 Status = StartThread(&ThreadDataSharedWait, NULL, FALSE, FALSE);
428 ok_eq_hex(Status, STATUS_SUCCESS);
429 CheckResourceStatus(Res, FALSE, 0LU, 1LU, 0LU);
430 ok_eq_int(Res->ActiveCount, 1);
431 FinishThread(&ThreadDataSharedWait);
432
433 /* ExAcquireSharedStarveExclusive must get access though! */
434 Status = StartThread(&ThreadDataSharedStarve, NULL, TRUE, TRUE);
435 ok_eq_hex(Status, STATUS_SUCCESS);
436 CheckResourceStatus(Res, FALSE, 0LU, 1LU, 0LU);
437 ok_eq_int(Res->ActiveCount, 2);
438 FinishThread(&ThreadDataSharedStarve);
439 CheckResourceStatus(Res, FALSE, 0LU, 1LU, 0LU);
440 ok_eq_int(Res->ActiveCount, 1);
441
442 /* block another shared one */
443 Status = StartThread(&ThreadDataShared2, &Timeout, TRUE, TRUE);
444 ok_eq_hex(Status, STATUS_TIMEOUT);
445 CheckResourceStatus(Res, FALSE, 0LU, 1LU, 1LU);
446 ok_eq_int(Res->ActiveCount, 1);
447
448 /* finish the very first one */
449 FinishThread(&ThreadDataShared);
450
451 /* now the blocked exclusive one should get the resource */
452 Status = KeWaitForSingleObject(&ThreadDataExclusive.OutEvent, Executive, KernelMode, FALSE, NULL);
453 ok_eq_hex(Status, STATUS_SUCCESS);
454 CheckResourceStatus(Res, FALSE, 0LU, 0LU, 1LU);
455 ok_eq_int(Res->ActiveCount, 1);
456 ok_eq_uint((Res->Flag & ResourceOwnedExclusive) != 0, 1);
457
458 FinishThread(&ThreadDataExclusive);
459 CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
460
461 /* now the blocked shared one should resume */
462 Status = KeWaitForSingleObject(&ThreadDataShared2.OutEvent, Executive, KernelMode, FALSE, NULL);
463 ok_eq_hex(Status, STATUS_SUCCESS);
464 CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
465 ok_eq_int(Res->ActiveCount, 1);
466 FinishThread(&ThreadDataShared2);
467 CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
468 ok_eq_int(Res->ActiveCount, 0);
469 }
470
471 static
472 VOID
473 NTAPI
474 TestOwnerRes(
475 PVOID Context)
476 {
477 NTSTATUS Status = STATUS_SUCCESS;
478 PTHREAD_DATA ThreadData = Context;
479 BOOLEAN Ret;
480
481 KeEnterCriticalRegion();
482 Ret = ThreadData->AcquireResource(ThreadData->Res, ThreadData->Wait);
483 if (ThreadData->RetExpected)
484 ok_bool_true(Ret, "AcquireResource returned");
485 else
486 ok_bool_false(Ret, "AcquireResource returned");
487 KeLeaveCriticalRegion();
488
489 ExReleaseResourceForThreadLite(ThreadData->Res, (ULONG_PTR)ThreadData->Res | 3);
490
491 ok_bool_false(KeSetEvent(&ThreadData->OutEvent, 0, TRUE), "KeSetEvent returned");
492 Status = KeWaitForSingleObject(&ThreadData->InEvent, Executive, KernelMode, FALSE, NULL);
493 ok_eq_hex(Status, STATUS_SUCCESS);
494 }
495
496 static
497 VOID
498 TestResourceWithOwner(
499 IN PERESOURCE Res)
500 {
501 NTSTATUS Status;
502 THREAD_DATA ThreadDataOwner;
503
504 InitThreadDataEx(&ThreadDataOwner, Res, ExAcquireResourceExclusiveLite, TestOwnerRes);
505
506 KeEnterCriticalRegion();
507 ok_bool_true(ExAcquireResourceExclusiveLite(Res, FALSE), "ExAcquireResourceExclusiveLite returned");
508 ExSetResourceOwnerPointer(Res, (PVOID)(ULONG_PTR)3);
509 ExReleaseResourceForThreadLite(Res, 3);
510
511 ok_bool_true(ExAcquireResourceExclusiveLite(Res, FALSE), "ExAcquireResourceExclusiveLite returned");
512 ExSetResourceOwnerPointer(Res, (PVOID)((ULONG_PTR)Res | 3));
513 KeLeaveCriticalRegion();
514
515 Status = StartThread(&ThreadDataOwner, NULL, FALSE, FALSE);
516 ok_eq_hex(Status, STATUS_SUCCESS);
517
518 FinishThread(&ThreadDataOwner);
519 }
520
521 START_TEST(ExResource)
522 {
523 NTSTATUS Status;
524 ERESOURCE Res;
525 KIRQL Irql;
526
527 pExEnterCriticalRegionAndAcquireResourceShared = KmtGetSystemRoutineAddress(L"ExEnterCriticalRegionAndAcquireResourceShared");
528 pExEnterCriticalRegionAndAcquireSharedWaitForExclusive = KmtGetSystemRoutineAddress(L"ExEnterCriticalRegionAndAcquireSharedWaitForExclusive");
529 pExEnterCriticalRegionAndAcquireResourceExclusive = KmtGetSystemRoutineAddress(L"ExEnterCriticalRegionAndAcquireResourceExclusive");
530 pExReleaseResourceAndLeaveCriticalRegion = KmtGetSystemRoutineAddress(L"ExReleaseResourceAndLeaveCriticalRegion");
531 pKeAreAllApcsDisabled = KmtGetSystemRoutineAddress(L"KeAreAllApcsDisabled");
532
533 if (skip(pKeAreAllApcsDisabled != NULL, "KeAreAllApcsDisabled unavailable\n"))
534 {
535 /* We can live without this function here */
536 }
537
538 /* this must be true even with the different structure versions */
539 ASSERT(sizeof(ERESOURCE) == sizeof(ERESOURCE_2K3));
540
541 /* functional tests & internals */
542 Irql = KeRaiseIrqlToDpcLevel();
543 Status = ExInitializeResourceLite(&Res);
544 ok_eq_hex(Status, STATUS_SUCCESS);
545 KeLowerIrql(APC_LEVEL);
546
547 Status = ExDeleteResourceLite(&Res);
548 ok_eq_hex(Status, STATUS_SUCCESS);
549 KeLowerIrql(Irql);
550
551 memset(&Res, 0x55, sizeof Res);
552 Status = ExInitializeResourceLite(&Res);
553 ok_eq_hex(Status, STATUS_SUCCESS);
554 CheckResourceFields((PERESOURCE_2K3)&Res, FALSE);
555
556 CheckResourceStatus(&Res, FALSE, 0LU, 0LU, 0LU);
557
558 TestResourceSharedAccess(&Res);
559 CheckResourceStatus(&Res, FALSE, 0LU, 0LU, 0LU);
560
561 TestResourceExclusiveAccess(&Res);
562 CheckResourceStatus(&Res, FALSE, 0LU, 0LU, 0LU);
563
564 TestResourceUndocumentedShortcuts(&Res, FALSE);
565 CheckResourceStatus(&Res, FALSE, 0LU, 0LU, 0LU);
566 KeRaiseIrql(APC_LEVEL, &Irql);
567 TestResourceUndocumentedShortcuts(&Res, TRUE);
568 KeLowerIrql(Irql);
569 ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
570 CheckResourceStatus(&Res, FALSE, 0LU, 0LU, 0LU);
571
572 TestResourceWithThreads(&Res);
573
574 /* ExReinitializeResourceLite cleans up after us */
575 Status = ExReinitializeResourceLite(&Res);
576 ok_eq_hex(Status, STATUS_SUCCESS);
577 CheckResourceFields((PERESOURCE_2K3)&Res, TRUE);
578 CheckResourceStatus(&Res, FALSE, 0LU, 0LU, 0LU);
579
580 TestResourceWithOwner(&Res);
581 CheckResourceStatus(&Res, FALSE, 0LU, 0LU, 0LU);
582
583 Status = ExDeleteResourceLite(&Res);
584 ok_eq_hex(Status, STATUS_SUCCESS);
585
586 /* parameter checks */
587 Status = STATUS_SUCCESS;
588 _SEH2_TRY {
589 ExInitializeResourceLite(NULL);
590 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
591 Status = _SEH2_GetExceptionCode();
592 } _SEH2_END;
593 ok_eq_hex(Status, STATUS_ACCESS_VIOLATION);
594
595 /* these bugcheck
596 ExDeleteResourceLite(NULL);
597 Status = ExDeleteResourceLite(&Res);*/
598 }