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