2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Kernel-Mode Test Suite Interlocked function test
5 * PROGRAMMER: Thomas Faber <thfabba@gmx.de>
8 /* missing prototypes >:| */
10 typedef long long __int64
;
13 __declspec(dllimport
) long __fastcall
InterlockedCompareExchange(volatile long *, long, long);
14 __declspec(dllimport
) __int64 __fastcall
ExInterlockedCompareExchange64(volatile __int64
*, __int64
*, __int64
*, void *);
15 __declspec(dllimport
) __int64 __fastcall
ExfInterlockedCompareExchange64(volatile __int64
*, __int64
*, __int64
*);
16 __declspec(dllimport
) long __fastcall
InterlockedExchange(volatile long *, long);
17 __declspec(dllimport
) unsigned long __stdcall
ExInterlockedExchangeUlong(unsigned long *, unsigned long, void *);
18 __declspec(dllimport
) long __fastcall
InterlockedExchangeAdd(volatile long *, long);
19 __declspec(dllimport
) unsigned long __stdcall
ExInterlockedAddUlong(unsigned long *, unsigned long, void *);
20 __declspec(dllimport
) unsigned long __stdcall
Exi386InterlockedExchangeUlong(unsigned long *, unsigned long);
21 __declspec(dllimport
) long __fastcall
InterlockedIncrement(long *);
22 __declspec(dllimport
) long __fastcall
InterlockedDecrement(long *);
23 __declspec(dllimport
) int __stdcall
ExInterlockedIncrementLong(long *, void *);
24 __declspec(dllimport
) int __stdcall
ExInterlockedDecrementLong(long *, void *);
25 __declspec(dllimport
) int __stdcall
Exi386InterlockedIncrementLong(long *);
26 __declspec(dllimport
) int __stdcall
Exi386InterlockedDecrementLong(long *);
30 /* TODO: There are quite some changes needed for other architectures!
31 ExInterlockedAddLargeInteger, ExInterlockedAddUlong are the only two
32 functions actually exported by my win7/x64 kernel! */
34 /* TODO: stress-testing */
36 static KSPIN_LOCK SpinLock
;
41 unsigned long esi
, edi
, ebx
, ebp
, esp
;
43 #elif defined(_M_AMD64)
46 unsigned long long rsi
, rdi
, rbx
, rbp
, rsp
, r12
, r13
, r14
, r15
;
50 typedef int PROCESSOR_STATE
;
53 #if defined(_MSC_VER) && defined(_M_IX86)
54 #define SaveState(State) do \
56 __asm lea ecx, [State] \
57 __asm mov [ecx], esi \
58 __asm mov [ecx+4], edi \
59 __asm mov [ecx+8], ebx \
60 __asm mov [ecx+12], ebp \
61 __asm mov [ecx+16], esp \
64 #define CheckState(OldState, NewState) do \
66 ok_eq_hex((OldState)->esi, (NewState)->esi); \
67 ok_eq_hex((OldState)->edi, (NewState)->edi); \
68 ok_eq_hex((OldState)->ebx, (NewState)->ebx); \
69 ok_eq_hex((OldState)->ebp, (NewState)->ebp); \
70 ok_eq_hex((OldState)->esp, (NewState)->esp); \
73 #elif defined(__GNUC__) && defined(_M_IX86)
74 #define SaveState(State) \
76 ".intel_syntax noprefix\n\t" \
77 "mov\t[ecx], esi\n\t" \
78 "mov\t[ecx+4], edi\n\t" \
79 "mov\t[ecx+8], ebx\n\t" \
80 "mov\t[ecx+12], ebp\n\t" \
81 "mov\t[ecx+16], esp\n\t" \
82 ".att_syntax prefix" \
83 : : "c" (&State) : "memory" \
86 #define CheckState(OldState, NewState) do \
88 ok_eq_hex((OldState)->esi, (NewState)->esi); \
89 ok_eq_hex((OldState)->edi, (NewState)->edi); \
90 ok_eq_hex((OldState)->ebx, (NewState)->ebx); \
91 ok_eq_hex((OldState)->ebp, (NewState)->ebp); \
92 ok_eq_hex((OldState)->esp, (NewState)->esp); \
94 #elif defined(__GNUC__) && defined(_M_AMD64)
95 #define SaveState(State) \
97 ".intel_syntax noprefix\n\t" \
98 "mov\t[rcx], rsi\n\t" \
99 "mov\t[rcx+8], rdi\n\t" \
100 "mov\t[rcx+16], rbx\n\t" \
101 "mov\t[rcx+24], rbp\n\t" \
102 "mov\t[rcx+32], rsp\n\t" \
103 "mov\t[rcx+40], r12\n\t" \
104 "mov\t[rcx+48], r13\n\t" \
105 "mov\t[rcx+56], r14\n\t" \
106 "mov\t[rcx+64], r15\n\t" \
107 ".att_syntax prefix" \
108 : : "c" (&State) : "memory" \
111 #define CheckState(OldState, NewState) do \
113 ok_eq_hex((OldState)->rsi, (NewState)->rsi); \
114 ok_eq_hex((OldState)->rdi, (NewState)->rdi); \
115 ok_eq_hex((OldState)->rbx, (NewState)->rbx); \
116 ok_eq_hex((OldState)->rbp, (NewState)->rbp); \
117 ok_eq_hex((OldState)->rsp, (NewState)->rsp); \
118 ok_eq_hex((OldState)->r12, (NewState)->r12); \
119 ok_eq_hex((OldState)->r13, (NewState)->r13); \
120 ok_eq_hex((OldState)->r14, (NewState)->r14); \
121 ok_eq_hex((OldState)->r15, (NewState)->r15); \
124 #define SaveState(State)
125 #define CheckState(OldState, NewState)
134 Ret
.QuadPart
= Value
;
138 #define CheckInterlockedCmpXchg(Function, Type, Print, Val, Cmp, Xchg, \
139 ExpectedValue, ExpectedRet) do \
141 Type Ret##Type = 0; \
142 Type Value##Type = Val; \
143 Status = STATUS_SUCCESS; \
145 SaveState(OldState); \
146 Ret##Type = Function(&Value##Type, Xchg, Cmp); \
147 SaveState(NewState); \
148 CheckState(&OldState, &NewState); \
149 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { \
150 Status = _SEH2_GetExceptionCode(); \
152 ok_eq_hex(Status, STATUS_SUCCESS); \
153 ok_eq_print(Ret##Type, ExpectedRet, Print); \
154 ok_eq_print(Value##Type, ExpectedValue, Print); \
157 #define CheckInterlockedCmpXchgI(Function, Type, Print, Val, Cmp, Xchg, \
158 ExpectedValue, ExpectedRet, ...) do \
160 Type Ret##Type = 0; \
161 Type Value##Type = Val; \
162 Type Compare##Type = Cmp; \
163 Type Exchange##Type = Xchg; \
164 Status = STATUS_SUCCESS; \
166 SaveState(OldState); \
167 Ret##Type = Function(&Value##Type, &Exchange##Type, \
168 &Compare##Type, ##__VA_ARGS__); \
169 SaveState(NewState); \
170 CheckState(&OldState, &NewState); \
171 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { \
172 Status = _SEH2_GetExceptionCode(); \
174 ok_eq_hex(Status, STATUS_SUCCESS); \
175 ok_eq_print(Ret##Type, ExpectedRet, Print); \
176 ok_eq_print(Value##Type, ExpectedValue, Print); \
177 ok_eq_print(Exchange##Type, Xchg, Print); \
178 ok_eq_print(Compare##Type, Cmp, Print); \
181 #define CheckInterlockedOp(Function, Type, Print, Val, Op, \
182 ExpectedValue, ExpectedRet, ...) do \
184 Type Ret##Type = 0; \
185 Type Value##Type = Val; \
186 Status = STATUS_SUCCESS; \
188 SaveState(OldState); \
189 Ret##Type = Function(&Value##Type, Op, ##__VA_ARGS__); \
190 SaveState(NewState); \
191 CheckState(&OldState, &NewState); \
192 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { \
193 Status = _SEH2_GetExceptionCode(); \
195 ok_eq_hex(Status, STATUS_SUCCESS); \
196 ok_eq_print(Ret##Type, ExpectedRet, Print); \
197 ok_eq_print(Value##Type, ExpectedValue, Print); \
200 #define CheckInterlockedOpNoArg(Function, Type, Print, Val, \
201 ExpectedValue, ExpectedRet, ...) do \
203 Type Ret##Type = 0; \
204 Type Value##Type = Val; \
205 Status = STATUS_SUCCESS; \
207 SaveState(OldState); \
208 Ret##Type = Function(&Value##Type, ##__VA_ARGS__); \
209 SaveState(NewState); \
210 CheckState(&OldState, &NewState); \
211 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { \
212 Status = _SEH2_GetExceptionCode(); \
214 ok_eq_hex(Status, STATUS_SUCCESS); \
215 ok_eq_print(Ret##Type, ExpectedRet, Print); \
216 ok_eq_print(Value##Type, ExpectedValue, Print); \
219 #define CheckInterlockedOpLarge(Function, Type, Print, Val, Op, \
220 ExpectedValue, ExpectedRet, ...) do \
222 Type Ret##Type = Large(0); \
223 Type Value##Type = Val; \
224 Status = STATUS_SUCCESS; \
226 SaveState(OldState); \
227 Ret##Type = Function(&Value##Type, Op, ##__VA_ARGS__); \
228 SaveState(NewState); \
229 CheckState(&OldState, &NewState); \
230 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { \
231 Status = _SEH2_GetExceptionCode(); \
233 ok_eq_hex(Status, STATUS_SUCCESS); \
234 ok_eq_print(Ret##Type.QuadPart, ExpectedRet, Print); \
235 ok_eq_print(Value##Type.QuadPart, ExpectedValue, Print); \
238 #define CheckInterlockedOpLargeNoRet(Function, Type, Print, Val, Op, \
241 Type Value##Type = Val; \
242 Status = STATUS_SUCCESS; \
244 SaveState(OldState); \
245 Function(&Value##Type, Op); \
246 SaveState(NewState); \
247 CheckState(&OldState, &NewState); \
248 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { \
249 Status = _SEH2_GetExceptionCode(); \
251 ok_eq_hex(Status, STATUS_SUCCESS); \
252 ok_eq_print(Value##Type.QuadPart, ExpectedValue, Print); \
255 /* TODO: missing in wdm.h! */
256 #define InterlockedCompareExchangeAcquire InterlockedCompareExchange
257 #define InterlockedCompareExchangeRelease InterlockedCompareExchange
258 #define InterlockedIncrementAcquire InterlockedIncrement
259 #define InterlockedIncrementRelease InterlockedIncrement
260 #define InterlockedDecrementAcquire InterlockedDecrement
261 #define InterlockedDecrementRelease InterlockedDecrement
265 TestInterlockedFunctional(VOID
)
268 PKSPIN_LOCK pSpinLock
= &SpinLock
;
269 PROCESSOR_STATE OldState
, NewState
;
271 /* on x86, most of these are supported intrinsically and don't need a spinlock! */
272 #if defined _M_IX86 || defined _M_AMD64
276 /* CompareExchange */
278 CheckInterlockedCmpXchg(InterlockedCompareExchange
, LONG
, "%ld", 5, 6, 8, 5L, 5L);
279 CheckInterlockedCmpXchg(InterlockedCompareExchange
, LONG
, "%ld", 5, 5, 9, 9L, 5L);
280 /* these only exist as macros on x86 */
281 CheckInterlockedCmpXchg(InterlockedCompareExchangeAcquire
, LONG
, "%ld", 16, 9, 12, 16L, 16L);
282 CheckInterlockedCmpXchg(InterlockedCompareExchangeAcquire
, LONG
, "%ld", 16, 16, 4, 4L, 16L);
283 CheckInterlockedCmpXchg(InterlockedCompareExchangeRelease
, LONG
, "%ld", 27, 123, 38, 27L, 27L);
284 CheckInterlockedCmpXchg(InterlockedCompareExchangeRelease
, LONG
, "%ld", 27, 27, 39, 39L, 27L);
285 /* exported function */
286 #undef InterlockedCompareExchange
288 CheckInterlockedCmpXchg(InterlockedCompareExchange
, LONG
, "%ld", 5, 6, 8, 5L, 5L);
289 CheckInterlockedCmpXchg(InterlockedCompareExchange
, LONG
, "%ld", 5, 5, 9, 9L, 5L);
291 /* only exists as a macro */
292 CheckInterlockedCmpXchg(InterlockedCompareExchangePointer
, PVOID
, "%p", (PVOID
)117, (PVOID
)711, (PVOID
)12, (PVOID
)117, (PVOID
)117);
293 CheckInterlockedCmpXchg(InterlockedCompareExchangePointer
, PVOID
, "%p", (PVOID
)117, (PVOID
)117, (PVOID
)228, (PVOID
)228, (PVOID
)117);
295 CheckInterlockedCmpXchgI(ExInterlockedCompareExchange64
, LONGLONG
, "%I64d", 17, 4LL, 20LL, 17LL, 17LL, pSpinLock
);
296 CheckInterlockedCmpXchgI(ExInterlockedCompareExchange64
, LONGLONG
, "%I64d", 17, 17LL, 21LL, 21LL, 17LL, pSpinLock
);
298 /* exported function */
299 CheckInterlockedCmpXchgI((ExInterlockedCompareExchange64
), LONGLONG
, "%I64d", 17, 4LL, 20LL, 17LL, 17LL, pSpinLock
);
300 CheckInterlockedCmpXchgI((ExInterlockedCompareExchange64
), LONGLONG
, "%I64d", 17, 17LL, 21LL, 21LL, 17LL, pSpinLock
);
301 /* fastcall version */
302 CheckInterlockedCmpXchgI(ExfInterlockedCompareExchange64
, LONGLONG
, "%I64d", 17, 4LL, 20LL, 17LL, 17LL);
303 CheckInterlockedCmpXchgI(ExfInterlockedCompareExchange64
, LONGLONG
, "%I64d", 17, 17LL, 21LL, 21LL, 17LL);
307 CheckInterlockedOp(InterlockedExchange
, LONG
, "%ld", 5, 8, 8L, 5L);
308 CheckInterlockedOpNoArg(InterlockedExchangePointer
, PVOID
, "%p", (PVOID
)700, (PVOID
)93, (PVOID
)700, (PVOID
)93);
309 #undef InterlockedExchange
311 CheckInterlockedOp(InterlockedExchange
, LONG
, "%ld", 5, 8, 8L, 5L);
312 CheckInterlockedOp(ExInterlockedExchangeUlong
, ULONG
, "%lu", 212, 121, 121LU, 212LU, pSpinLock
);
313 CheckInterlockedOp((ExInterlockedExchangeUlong
), ULONG
, "%lu", 212, 121, 121LU, 212LU, pSpinLock
);
314 CheckInterlockedOp(Exi386InterlockedExchangeUlong
, ULONG
, "%lu", 212, 121, 121LU, 212LU);
315 CheckInterlockedOp(Exfi386InterlockedExchangeUlong
, ULONG
, "%lu", 212, 121, 121LU, 212LU);
319 /* TODO: ExInterlockedExchangeAddLargeInteger? */
320 CheckInterlockedOp(InterlockedExchangeAdd
, LONG
, "%ld", 312, 7, 319L, 312L);
321 #undef InterlockedExchangeAdd
323 CheckInterlockedOp(InterlockedExchangeAdd
, LONG
, "%ld", 312, 7, 319L, 312L);
327 /* these DO need a valid spinlock even on x86 */
328 CheckInterlockedOpLarge(ExInterlockedAddLargeInteger
, LARGE_INTEGER
, "%I64d", Large(23), Large(7), 30LL, 23LL, &SpinLock
);
329 CheckInterlockedOpLargeNoRet(ExInterlockedAddLargeStatistic
, LARGE_INTEGER
, "%I64d", Large(15), 17LL, 32LL);
330 CheckInterlockedOp(ExInterlockedAddUlong
, ULONG
, "%lu", 239, 44, 283LU, 239LU, &SpinLock
);
331 #undef ExInterlockedAddUlong
332 CheckInterlockedOp(ExInterlockedAddUlong
, ULONG
, "%lu", 239, 44, 283LU, 239LU, &SpinLock
);
335 CheckInterlockedOpNoArg(InterlockedIncrement
, LONG
, "%ld", 2341L, 2342L, 2342L);
336 CheckInterlockedOpNoArg(InterlockedIncrement
, LONG
, "%ld", (LONG
)MAXLONG
, (LONG
)MINLONG
, (LONG
)MINLONG
);
337 CheckInterlockedOpNoArg(InterlockedIncrementAcquire
, LONG
, "%ld", 2341L, 2342L, 2342L);
338 CheckInterlockedOpNoArg(InterlockedIncrementRelease
, LONG
, "%ld", 2341L, 2342L, 2342L);
339 #undef InterlockedIncrement
341 CheckInterlockedOpNoArg(InterlockedIncrement
, LONG
, "%ld", 2341L, 2342L, 2342L);
342 CheckInterlockedOpNoArg(InterlockedIncrement
, LONG
, "%ld", (LONG
)MAXLONG
, (LONG
)MINLONG
, (LONG
)MINLONG
);
343 CheckInterlockedOpNoArg(ExInterlockedIncrementLong
, LONG
, "%ld", -2L, -1L, (LONG
)ResultNegative
, pSpinLock
);
344 CheckInterlockedOpNoArg(ExInterlockedIncrementLong
, LONG
, "%ld", -1L, 0L, (LONG
)ResultZero
, pSpinLock
);
345 CheckInterlockedOpNoArg(ExInterlockedIncrementLong
, LONG
, "%ld", 0L, 1L, (LONG
)ResultPositive
, pSpinLock
);
346 CheckInterlockedOpNoArg(ExInterlockedIncrementLong
, LONG
, "%ld", (LONG
)MAXLONG
, (LONG
)MINLONG
, (LONG
)ResultNegative
, pSpinLock
);
347 CheckInterlockedOpNoArg((ExInterlockedIncrementLong
), LONG
, "%ld", -2L, -1L, (LONG
)ResultNegative
, pSpinLock
);
348 CheckInterlockedOpNoArg((ExInterlockedIncrementLong
), LONG
, "%ld", -1L, 0L, (LONG
)ResultZero
, pSpinLock
);
349 CheckInterlockedOpNoArg((ExInterlockedIncrementLong
), LONG
, "%ld", 0L, 1L, (LONG
)ResultPositive
, pSpinLock
);
350 CheckInterlockedOpNoArg((ExInterlockedIncrementLong
), LONG
, "%ld", (LONG
)MAXLONG
, (LONG
)MINLONG
, (LONG
)ResultNegative
, pSpinLock
);
351 CheckInterlockedOpNoArg(Exi386InterlockedIncrementLong
, LONG
, "%ld", -2L, -1L, (LONG
)ResultNegative
);
352 CheckInterlockedOpNoArg(Exi386InterlockedIncrementLong
, LONG
, "%ld", -1L, 0L, (LONG
)ResultZero
);
353 CheckInterlockedOpNoArg(Exi386InterlockedIncrementLong
, LONG
, "%ld", 0L, 1L, (LONG
)ResultPositive
);
354 CheckInterlockedOpNoArg(Exi386InterlockedIncrementLong
, LONG
, "%ld", (LONG
)MAXLONG
, (LONG
)MINLONG
, (LONG
)ResultNegative
);
358 CheckInterlockedOpNoArg(InterlockedDecrement
, LONG
, "%ld", 1745L, 1744L, 1744L);
359 CheckInterlockedOpNoArg(InterlockedDecrement
, LONG
, "%ld", (LONG
)MINLONG
, (LONG
)MAXLONG
, (LONG
)MAXLONG
);
360 CheckInterlockedOpNoArg(InterlockedDecrementAcquire
, LONG
, "%ld", 1745L, 1744L, 1744L);
361 CheckInterlockedOpNoArg(InterlockedDecrementRelease
, LONG
, "%ld", 1745L, 1744L, 1744L);
362 #undef InterlockedDecrement
364 CheckInterlockedOpNoArg(InterlockedDecrement
, LONG
, "%ld", 1745L, 1744L, 1744L);
365 CheckInterlockedOpNoArg(InterlockedDecrement
, LONG
, "%ld", (LONG
)MINLONG
, (LONG
)MAXLONG
, (LONG
)MAXLONG
);
366 CheckInterlockedOpNoArg(ExInterlockedDecrementLong
, LONG
, "%ld", (LONG
)MINLONG
, (LONG
)MAXLONG
, (LONG
)ResultPositive
, pSpinLock
);
367 CheckInterlockedOpNoArg(ExInterlockedDecrementLong
, LONG
, "%ld", 0L, -1L, (LONG
)ResultNegative
, pSpinLock
);
368 CheckInterlockedOpNoArg(ExInterlockedDecrementLong
, LONG
, "%ld", 1L, 0L, (LONG
)ResultZero
, pSpinLock
);
369 CheckInterlockedOpNoArg(ExInterlockedDecrementLong
, LONG
, "%ld", 2L, 1L, (LONG
)ResultPositive
, pSpinLock
);
370 CheckInterlockedOpNoArg((ExInterlockedDecrementLong
), LONG
, "%ld", (LONG
)MINLONG
, (LONG
)MAXLONG
, (LONG
)ResultPositive
, pSpinLock
);
371 CheckInterlockedOpNoArg((ExInterlockedDecrementLong
), LONG
, "%ld", 0L, -1L, (LONG
)ResultNegative
, pSpinLock
);
372 CheckInterlockedOpNoArg((ExInterlockedDecrementLong
), LONG
, "%ld", 1L, 0L, (LONG
)ResultZero
, pSpinLock
);
373 CheckInterlockedOpNoArg((ExInterlockedDecrementLong
), LONG
, "%ld", 2L, 1L, (LONG
)ResultPositive
, pSpinLock
);
374 CheckInterlockedOpNoArg(Exi386InterlockedDecrementLong
, LONG
, "%ld", (LONG
)MINLONG
, (LONG
)MAXLONG
, (LONG
)ResultPositive
);
375 CheckInterlockedOpNoArg(Exi386InterlockedDecrementLong
, LONG
, "%ld", 0L, -1L, (LONG
)ResultNegative
);
376 CheckInterlockedOpNoArg(Exi386InterlockedDecrementLong
, LONG
, "%ld", 1L, 0L, (LONG
)ResultZero
);
377 CheckInterlockedOpNoArg(Exi386InterlockedDecrementLong
, LONG
, "%ld", 2L, 1L, (LONG
)ResultPositive
);
381 CheckInterlockedOp(InterlockedAnd
, LONG
, "0x%lx", 0x1234L
, 0x1111L
, 0x1010L
, 0x1234L
);
382 CheckInterlockedOp(InterlockedOr
, LONG
, "0x%lx", 0x1234L
, 0x1111L
, 0x1335L
, 0x1234L
);
383 CheckInterlockedOp(InterlockedXor
, LONG
, "0x%lx", 0x1234L
, 0x1111L
, 0x0325L
, 0x1234L
);
385 CheckInterlockedOp(InterlockedXor64
, LONGLONG
, "0x%I64x", 0x200001234LL
, 0x100001111LL
, 0x300000325LL
, 0x200001234LL
);
389 START_TEST(ExInterlocked
)
392 KeInitializeSpinLock(&SpinLock
);
394 /* functional testing */
395 TestInterlockedFunctional();
396 KeRaiseIrql(HIGH_LEVEL
, &Irql
);
397 TestInterlockedFunctional();