2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Kernel-Mode Test Suite Mutant/Mutex test
5 * PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
11 _IRQL_requires_min_(PASSIVE_LEVEL
)
12 _IRQL_requires_max_(DISPATCH_LEVEL
)
15 *pKeAreAllApcsDisabled
)(VOID
);
17 #define ULONGS_PER_POINTER (sizeof(PVOID) / sizeof(ULONG))
18 #define MUTANT_SIZE (2 + 6 * ULONGS_PER_POINTER)
20 C_ASSERT(sizeof(DISPATCHER_HEADER
) == 8 + 2 * sizeof(PVOID
));
21 C_ASSERT(sizeof(KMUTANT
) == sizeof(DISPATCHER_HEADER
) + 3 * sizeof(PVOID
) + sizeof(PVOID
));
22 C_ASSERT(sizeof(KMUTANT
) == MUTANT_SIZE
* sizeof(ULONG
));
24 #define CheckMutex(Mutex, State, New, ExpectedApcDisable) do { \
25 PKTHREAD Thread = KeGetCurrentThread(); \
26 ok_eq_uint((Mutex)->Header.Type, MutantObject); \
27 ok_eq_uint((Mutex)->Header.Abandoned, 0x55); \
28 ok_eq_uint((Mutex)->Header.Size, MUTANT_SIZE); \
29 ok_eq_uint((Mutex)->Header.DpcActive, 0x55); \
30 ok_eq_pointer((Mutex)->Header.WaitListHead.Flink, \
31 &(Mutex)->Header.WaitListHead); \
32 ok_eq_pointer((Mutex)->Header.WaitListHead.Blink, \
33 &(Mutex)->Header.WaitListHead); \
36 ok_eq_long((Mutex)->Header.SignalState, State); \
37 ok_eq_pointer((Mutex)->MutantListEntry.Flink, &Thread->MutantListHead); \
38 ok_eq_pointer((Mutex)->MutantListEntry.Blink, &Thread->MutantListHead); \
39 ok_eq_pointer(Thread->MutantListHead.Flink, &(Mutex)->MutantListEntry); \
40 ok_eq_pointer(Thread->MutantListHead.Blink, &(Mutex)->MutantListEntry); \
41 ok_eq_pointer((Mutex)->OwnerThread, Thread); \
45 ok_eq_long((Mutex)->Header.SignalState, State); \
48 ok_eq_pointer((Mutex)->MutantListEntry.Flink, \
49 (PVOID)0x5555555555555555ULL); \
50 ok_eq_pointer((Mutex)->MutantListEntry.Blink, \
51 (PVOID)0x5555555555555555ULL); \
53 ok_eq_pointer(Thread->MutantListHead.Flink, &Thread->MutantListHead); \
54 ok_eq_pointer(Thread->MutantListHead.Blink, &Thread->MutantListHead); \
55 ok_eq_pointer((Mutex)->OwnerThread, NULL); \
57 ok_eq_uint((Mutex)->Abandoned, 0); \
58 ok_eq_uint((Mutex)->ApcDisable, ExpectedApcDisable); \
61 #define CheckApcs(KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, Irql) do \
63 ok_eq_bool(KeAreApcsDisabled(), KernelApcsDisabled || SpecialApcsDisabled); \
64 ok_eq_int(Thread->KernelApcDisable, KernelApcsDisabled); \
65 if (pKeAreAllApcsDisabled) \
66 ok_eq_bool(pKeAreAllApcsDisabled(), AllApcsDisabled); \
67 ok_eq_int(Thread->SpecialApcDisable, SpecialApcsDisabled); \
79 PKTHREAD Thread
= KeGetCurrentThread();
81 CheckApcs(0, 0, FALSE
, PASSIVE_LEVEL
);
82 RtlFillMemory(&Mutant
, sizeof(Mutant
), 0x55);
83 KeInitializeMutant(&Mutant
, FALSE
);
84 CheckMutex(&Mutant
, 1L, TRUE
, 0);
85 CheckApcs(0, 0, FALSE
, PASSIVE_LEVEL
);
87 RtlFillMemory(&Mutant
, sizeof(Mutant
), 0x55);
88 KeInitializeMutant(&Mutant
, TRUE
);
89 CheckApcs(0, 0, FALSE
, PASSIVE_LEVEL
);
90 CheckMutex(&Mutant
, 0L, TRUE
, 0);
91 State
= KeReleaseMutant(&Mutant
, 1, FALSE
, FALSE
);
92 ok_eq_long(State
, 0L);
93 CheckMutex(&Mutant
, 1L, FALSE
, 0);
94 CheckApcs(0, 0, FALSE
, PASSIVE_LEVEL
);
96 /* Acquire and release */
97 Status
= KeWaitForSingleObject(&Mutant
,
102 ok_eq_hex(Status
, STATUS_SUCCESS
);
103 CheckMutex(&Mutant
, 0L, TRUE
, 0);
104 CheckApcs(0, 0, FALSE
, PASSIVE_LEVEL
);
106 State
= KeReleaseMutant(&Mutant
, 1, FALSE
, FALSE
);
107 ok_eq_long(State
, 0L);
108 CheckMutex(&Mutant
, 1L, FALSE
, 0);
109 CheckApcs(0, 0, FALSE
, PASSIVE_LEVEL
);
111 /* Acquire recursively */
112 for (i
= 0; i
< 8; i
++)
115 Status
= KeWaitForSingleObject(&Mutant
,
120 KmtEndSeh(STATUS_SUCCESS
);
121 ok_eq_hex(Status
, STATUS_SUCCESS
);
122 CheckMutex(&Mutant
, -i
, FALSE
, 0);
123 CheckApcs(0, 0, FALSE
, PASSIVE_LEVEL
);
126 for (i
= 0; i
< 7; i
++)
129 State
= KeReleaseMutant(&Mutant
, 1, FALSE
, FALSE
);
130 KmtEndSeh(STATUS_SUCCESS
);
131 ok_eq_long(State
, -7L + i
);
132 CheckMutex(&Mutant
, -6L + i
, FALSE
, 0);
133 CheckApcs(0, 0, FALSE
, PASSIVE_LEVEL
);
136 State
= KeReleaseMutant(&Mutant
, 1, FALSE
, FALSE
);
137 ok_eq_long(State
, 0L);
138 CheckMutex(&Mutant
, 1L, FALSE
, 0);
139 CheckApcs(0, 0, FALSE
, PASSIVE_LEVEL
);
141 /* Pretend to acquire it recursively -MINLONG times */
143 Status
= KeWaitForSingleObject(&Mutant
,
148 KmtEndSeh(STATUS_SUCCESS
);
149 ok_eq_hex(Status
, STATUS_SUCCESS
);
150 CheckMutex(&Mutant
, 0L, FALSE
, 0);
151 CheckApcs(0, 0, FALSE
, PASSIVE_LEVEL
);
153 Mutant
.Header
.SignalState
= MINLONG
+ 1;
155 Status
= KeWaitForSingleObject(&Mutant
,
160 KmtEndSeh(STATUS_SUCCESS
);
161 ok_eq_hex(Status
, STATUS_SUCCESS
);
162 CheckMutex(&Mutant
, (LONG
)MINLONG
, FALSE
, 0);
163 CheckApcs(0, 0, FALSE
, PASSIVE_LEVEL
);
166 KeWaitForSingleObject(&Mutant
,
171 KmtEndSeh(STATUS_MUTANT_LIMIT_EXCEEDED
);
172 CheckMutex(&Mutant
, (LONG
)MINLONG
, FALSE
, 0);
173 CheckApcs(0, 0, FALSE
, PASSIVE_LEVEL
);
175 State
= KeReleaseMutant(&Mutant
, 1, FALSE
, FALSE
);
176 ok_eq_long(State
, (LONG
)MINLONG
);
177 CheckMutex(&Mutant
, (LONG
)MINLONG
+ 1L, FALSE
, 0);
178 CheckApcs(0, 0, FALSE
, PASSIVE_LEVEL
);
180 Mutant
.Header
.SignalState
= -1;
181 State
= KeReleaseMutant(&Mutant
, 1, FALSE
, FALSE
);
182 ok_eq_long(State
, -1L);
183 CheckMutex(&Mutant
, 0L, FALSE
, 0);
184 CheckApcs(0, 0, FALSE
, PASSIVE_LEVEL
);
186 State
= KeReleaseMutant(&Mutant
, 1, FALSE
, FALSE
);
187 ok_eq_long(State
, 0L);
188 CheckMutex(&Mutant
, 1L, FALSE
, 0);
189 CheckApcs(0, 0, FALSE
, PASSIVE_LEVEL
);
191 /* Now release it once too often */
193 KeReleaseMutant(&Mutant
, 1, FALSE
, FALSE
);
194 KmtEndSeh(STATUS_MUTANT_NOT_OWNED
);
195 CheckMutex(&Mutant
, 1L, FALSE
, 0);
196 CheckApcs(0, 0, FALSE
, PASSIVE_LEVEL
);
207 PKTHREAD Thread
= KeGetCurrentThread();
209 CheckApcs(0, 0, FALSE
, PASSIVE_LEVEL
);
210 RtlFillMemory(&Mutex
, sizeof(Mutex
), 0x55);
211 KeInitializeMutex(&Mutex
, 0);
212 CheckMutex(&Mutex
, 1L, TRUE
, 1);
213 CheckApcs(0, 0, FALSE
, PASSIVE_LEVEL
);
215 RtlFillMemory(&Mutex
, sizeof(Mutex
), 0x55);
216 KeInitializeMutex(&Mutex
, 123);
217 CheckMutex(&Mutex
, 1L, TRUE
, 1);
218 CheckApcs(0, 0, FALSE
, PASSIVE_LEVEL
);
220 /* Acquire and release */
221 Status
= KeWaitForSingleObject(&Mutex
,
226 ok_eq_hex(Status
, STATUS_SUCCESS
);
227 CheckMutex(&Mutex
, 0L, FALSE
, 1);
228 CheckApcs(-1, 0, FALSE
, PASSIVE_LEVEL
);
230 State
= KeReleaseMutex(&Mutex
, FALSE
);
231 ok_eq_long(State
, 0L);
232 CheckMutex(&Mutex
, 1L, FALSE
, 1);
233 CheckApcs(0, 0, FALSE
, PASSIVE_LEVEL
);
235 /* Acquire recursively */
236 for (i
= 0; i
< 8; i
++)
239 Status
= KeWaitForSingleObject(&Mutex
,
244 KmtEndSeh(STATUS_SUCCESS
);
245 ok_eq_hex(Status
, STATUS_SUCCESS
);
246 CheckMutex(&Mutex
, -i
, FALSE
, 1);
247 CheckApcs(-1, 0, FALSE
, PASSIVE_LEVEL
);
250 for (i
= 0; i
< 7; i
++)
253 State
= KeReleaseMutex(&Mutex
, FALSE
);
254 KmtEndSeh(STATUS_SUCCESS
);
255 ok_eq_long(State
, -7L + i
);
256 CheckMutex(&Mutex
, -6L + i
, FALSE
, 1);
257 CheckApcs(-1, 0, FALSE
, PASSIVE_LEVEL
);
260 State
= KeReleaseMutex(&Mutex
, FALSE
);
261 ok_eq_long(State
, 0L);
262 CheckMutex(&Mutex
, 1L, FALSE
, 1);
263 CheckApcs(0, 0, FALSE
, PASSIVE_LEVEL
);
265 /* Pretend to acquire it recursively -MINLONG times */
267 Status
= KeWaitForSingleObject(&Mutex
,
272 KmtEndSeh(STATUS_SUCCESS
);
273 ok_eq_hex(Status
, STATUS_SUCCESS
);
274 CheckMutex(&Mutex
, 0L, FALSE
, 1);
275 CheckApcs(-1, 0, FALSE
, PASSIVE_LEVEL
);
277 Mutex
.Header
.SignalState
= MINLONG
+ 1;
279 Status
= KeWaitForSingleObject(&Mutex
,
284 KmtEndSeh(STATUS_SUCCESS
);
285 ok_eq_hex(Status
, STATUS_SUCCESS
);
286 CheckMutex(&Mutex
, (LONG
)MINLONG
, FALSE
, 1);
287 CheckApcs(-1, 0, FALSE
, PASSIVE_LEVEL
);
290 KeWaitForSingleObject(&Mutex
,
295 KmtEndSeh(STATUS_MUTANT_LIMIT_EXCEEDED
);
296 CheckMutex(&Mutex
, (LONG
)MINLONG
, FALSE
, 1);
297 CheckApcs(-1, 0, FALSE
, PASSIVE_LEVEL
);
299 State
= KeReleaseMutex(&Mutex
, FALSE
);
300 ok_eq_long(State
, (LONG
)MINLONG
);
301 CheckMutex(&Mutex
, (LONG
)MINLONG
+ 1L, FALSE
, 1);
302 CheckApcs(-1, 0, FALSE
, PASSIVE_LEVEL
);
304 Mutex
.Header
.SignalState
= -1;
305 State
= KeReleaseMutex(&Mutex
, FALSE
);
306 ok_eq_long(State
, -1L);
307 CheckMutex(&Mutex
, 0L, FALSE
, 1);
308 CheckApcs(-1, 0, FALSE
, PASSIVE_LEVEL
);
310 State
= KeReleaseMutex(&Mutex
, FALSE
);
311 ok_eq_long(State
, 0L);
312 CheckMutex(&Mutex
, 1L, FALSE
, 1);
313 CheckApcs(0, 0, FALSE
, PASSIVE_LEVEL
);
315 /* Now release it once too often */
317 KeReleaseMutex(&Mutex
, FALSE
);
318 KmtEndSeh(STATUS_MUTANT_NOT_OWNED
);
319 CheckMutex(&Mutex
, 1L, FALSE
, 1);
320 CheckApcs(0, 0, FALSE
, PASSIVE_LEVEL
);
325 pKeAreAllApcsDisabled
= KmtGetSystemRoutineAddress(L
"KeAreAllApcsDisabled");
326 if (skip(pKeAreAllApcsDisabled
!= NULL
, "KeAreAllApcsDisabled unavailable\n"))
328 /* We can live without this function here */