ReactOS 0.4.15-dev-7934-g1dc8d80
KeEvent.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Kernel-Mode Test Suite Event test
5 * PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
6 */
7
8#include <kmt_test.h>
9
10#define CheckEvent(Event, ExpectedType, State, ExpectedWaitNext, \
11 Irql, ThreadList, ThreadCount) do \
12{ \
13 INT TheIndex; \
14 PLIST_ENTRY TheEntry; \
15 PKTHREAD TheThread; \
16 ok_eq_uint((Event)->Header.Type, ExpectedType); \
17 ok_eq_uint((Event)->Header.Hand, sizeof *(Event) / sizeof(ULONG)); \
18 ok_eq_hex((Event)->Header.Lock & 0xFF00FF00L, 0x55005500L); \
19 ok_eq_long((Event)->Header.SignalState, State); \
20 TheEntry = (Event)->Header.WaitListHead.Flink; \
21 for (TheIndex = 0; TheIndex < (ThreadCount); ++TheIndex) \
22 { \
23 TheThread = CONTAINING_RECORD(TheEntry, KTHREAD, \
24 WaitBlock[0].WaitListEntry); \
25 ok_eq_pointer(TheThread, (ThreadList)[TheIndex]); \
26 ok_eq_pointer(TheEntry->Flink->Blink, TheEntry); \
27 TheEntry = TheEntry->Flink; \
28 } \
29 ok_eq_pointer(TheEntry, &(Event)->Header.WaitListHead); \
30 ok_eq_pointer(TheEntry->Flink->Blink, TheEntry); \
31 ok_eq_long(KeReadStateEvent(Event), State); \
32 ok_eq_bool(Thread->WaitNext, ExpectedWaitNext); \
33 ok_irql(Irql); \
34} while (0)
35
36static
37VOID
41 IN KIRQL OriginalIrql)
42{
43 LONG State;
45
46 memset(Event, 0x55, sizeof *Event);
48 CheckEvent(Event, Type, 0L, FALSE, OriginalIrql, (PVOID *)NULL, 0);
49
50 memset(Event, 0x55, sizeof *Event);
52 CheckEvent(Event, Type, 1L, FALSE, OriginalIrql, (PVOID *)NULL, 0);
53
54 Event->Header.SignalState = 0x12345678L;
55 CheckEvent(Event, Type, 0x12345678L, FALSE, OriginalIrql, (PVOID *)NULL, 0);
56
58 CheckEvent(Event, Type, 0L, FALSE, OriginalIrql, (PVOID *)NULL, 0);
59 ok_eq_long(State, 0x12345678L);
60
61 Event->Header.SignalState = 0x12345678L;
63 CheckEvent(Event, Type, 0L, FALSE, OriginalIrql, (PVOID *)NULL, 0);
64
66 CheckEvent(Event, Type, 1L, FALSE, OriginalIrql, (PVOID *)NULL, 0);
68
70 CheckEvent(Event, Type, 0L, FALSE, OriginalIrql, (PVOID *)NULL, 0);
71 ok_eq_long(State, 1L);
72
73 Event->Header.SignalState = 0x23456789L;
75 CheckEvent(Event, Type, 1L, FALSE, OriginalIrql, (PVOID *)NULL, 0);
76 ok_eq_long(State, 0x23456789L);
77
78 Event->Header.SignalState = 0x3456789AL;
80 CheckEvent(Event, Type, 0L, FALSE, OriginalIrql, (PVOID *)NULL, 0);
81 ok_eq_long(State, 0x3456789AL);
82
83 /* Irql is raised to DISPATCH_LEVEL here, which kills checked build,
84 * a spinlock is acquired and never released, which kills MP build */
85 if ((OriginalIrql <= DISPATCH_LEVEL || !KmtIsCheckedBuild) &&
87 {
88 Event->Header.SignalState = 0x456789ABL;
91 ok_eq_long(State, 0x456789ABL);
92 ok_eq_uint(Thread->WaitIrql, OriginalIrql);
93 /* repair the "damage" */
94 Thread->WaitNext = FALSE;
95 KmtSetIrql(OriginalIrql);
96
97 Event->Header.SignalState = 0x56789ABCL;
100 ok_eq_long(State, 0x56789ABCL);
101 ok_eq_uint(Thread->WaitIrql, OriginalIrql);
102 /* repair the "damage" */
103 Thread->WaitNext = FALSE;
104 KmtSetIrql(OriginalIrql);
105 }
106
107 ok_irql(OriginalIrql);
108 KmtSetIrql(OriginalIrql);
109}
110
111typedef struct
112{
116 volatile BOOLEAN Signal;
118
119static
120VOID
121NTAPI
124{
127
128 ok_irql(PASSIVE_LEVEL);
129 ThreadData->Signal = TRUE;
132 ok_irql(PASSIVE_LEVEL);
133}
134
136
137static
138VOID
142 IN KIRQL OriginalIrql,
144 KPRIORITY PriorityIncrement,
145 LONG ExpectedState,
146 BOOLEAN SatisfiesAll)
147{
149 THREAD_DATA Threads[5];
150 const INT ThreadCount = sizeof Threads / sizeof Threads[0];
152 LARGE_INTEGER LongTimeout, ShortTimeout;
153 INT i;
154 KWAIT_BLOCK WaitBlock[RTL_NUMBER_OF(Threads)];
155 PVOID ThreadObjects[RTL_NUMBER_OF(Threads)];
156 LONG State;
159
160 LongTimeout.QuadPart = -100 * MILLISECOND;
161 ShortTimeout.QuadPart = -1 * MILLISECOND;
162
164
165 for (i = 0; i < ThreadCount; ++i)
166 {
167 Threads[i].Event = Event;
168 Threads[i].Signal = FALSE;
170 NULL,
172 NULL,
173 NULL);
178 ThreadObjects[i] = Threads[i].Thread;
180 ok_eq_long(Priority, 8L);
181 while (!Threads[i].Signal)
182 {
184 if (Status != STATUS_SUCCESS)
185 {
187 }
188 }
189 CheckEvent(Event, Type, 0L, FALSE, OriginalIrql, ThreadObjects, i + 1);
190 }
191
192 /* the threads shouldn't wake up on their own */
195
196 for (i = 0; i < ThreadCount; ++i)
197 {
198 CheckEvent(Event, Type, 0L, FALSE, OriginalIrql, ThreadObjects + i, ThreadCount - i);
199 State = SetEvent(Event, PriorityIncrement + i, FALSE);
200
201 ok_eq_long(State, 0L);
202 CheckEvent(Event, Type, ExpectedState, FALSE, OriginalIrql, ThreadObjects + i + 1, SatisfiesAll ? 0 : ThreadCount - i - 1);
203 Status = KeWaitForMultipleObjects(ThreadCount, ThreadObjects, SatisfiesAll ? WaitAll : WaitAny, Executive, KernelMode, FALSE, &LongTimeout, WaitBlock);
205 if (SatisfiesAll)
206 {
207 for (; i < ThreadCount; ++i)
208 {
210 ok_eq_long(Priority, max(min(8L + PriorityIncrement, 15L), 8L));
211 }
212 break;
213 }
215 ok_eq_long(Priority, max(min(8L + PriorityIncrement + i, 15L), 8L));
216 /* replace the thread with the current thread - which will never signal */
217 if (!skip((Status & 0x3F) < ThreadCount, "Index out of bounds\n"))
218 ThreadObjects[Status & 0x3F] = Thread;
219 Status = KeWaitForMultipleObjects(ThreadCount, ThreadObjects, WaitAny, Executive, KernelMode, FALSE, &ShortTimeout, WaitBlock);
221 }
222
223 for (i = 0; i < ThreadCount; ++i)
224 {
225 ObDereferenceObject(Threads[i].Thread);
226 Status = ZwClose(Threads[i].Handle);
228 }
229}
230
231#define NUM_SCHED_TESTS 1000
232
233typedef struct
234{
239 ULONG CounterValues[NUM_SCHED_TESTS];
241
242static
243VOID
244NTAPI
247{
249 PKEVENT Event = &ThreadData->Event;
250 volatile ULONG *Counter = &ThreadData->Counter;
251 ULONG *CounterValue = ThreadData->CounterValues;
253
255 ok_eq_long(Priority, 8L);
256
257 while (CounterValue < &ThreadData->CounterValues[NUM_SCHED_TESTS])
258 {
261 *CounterValue++ = *Counter;
262 }
263
265 ok_eq_long(Priority, 8L + min(ThreadData->PriorityIncrement, 7));
266}
267
268static
269VOID
270NTAPI
273{
278 ULONG i;
279 volatile ULONG *Counter;
280 KPRIORITY PriorityIncrement;
282
284
286 if (skip(ThreadData != NULL, "Out of memory\n"))
287 {
288 return;
289 }
292 Counter = &ThreadData->Counter;
293
294 for (PriorityIncrement = 0; PriorityIncrement <= 8; PriorityIncrement++)
295 {
296 ThreadData->PriorityIncrement = PriorityIncrement;
297 ThreadData->Counter = 0;
298 RtlFillMemory(ThreadData->CounterValues,
299 sizeof(ThreadData->CounterValues),
300 0xFE);
303 ok(Priority == 8, "[%lu] Priority = %lu\n", PriorityIncrement, Priority);
304 for (i = 1; i <= NUM_SCHED_TESTS; i++)
305 {
308 PreviousState = KeSetEvent(&ThreadData->Event, PriorityIncrement, FALSE);
309 *Counter = i;
311 }
313 ok(Priority == 8, "[%lu] Priority = %lu\n", PriorityIncrement, Priority);
315
316 if (PriorityIncrement == 0)
317 {
318 /* Both threads have the same priority, so either can win the race */
319 ok(ThreadData->CounterValues[0] == 0 || ThreadData->CounterValues[0] == 1,
320 "[%lu] Counter 0 = %lu\n",
321 PriorityIncrement, ThreadData->CounterValues[0]);
322 }
323 else
324 {
325 /* CountThread has the higher priority, it will always win */
326 ok(ThreadData->CounterValues[0] == 0,
327 "[%lu] Counter 0 = %lu\n",
328 PriorityIncrement, ThreadData->CounterValues[0]);
329 }
330 for (i = 1; i < NUM_SCHED_TESTS; i++)
331 {
332 if (PriorityIncrement == 0)
333 {
334 ok(ThreadData->CounterValues[i] == i ||
335 ThreadData->CounterValues[i] == i + 1,
336 "[%lu] Counter %lu = %lu, expected %lu or %lu\n",
337 PriorityIncrement, i,
338 ThreadData->CounterValues[i], i, i + 1);
339 }
340 else
341 {
342 ok(ThreadData->CounterValues[i] == ThreadData->CounterValues[i - 1] + 1,
343 "[%lu] Counter %lu = %lu, expected %lu\n",
344 PriorityIncrement, i,
345 ThreadData->CounterValues[i], ThreadData->CounterValues[i - 1] + 1);
346 }
347 }
348 }
349
351}
352
354{
357 KIRQL Irql;
359 ULONG i;
360 KPRIORITY PriorityIncrement;
361
362 for (i = 0; i < RTL_NUMBER_OF(Irqls); ++i)
363 {
364 KeRaiseIrql(Irqls[i], &Irql);
368 }
369
370 for (i = 0; i < RTL_NUMBER_OF(Irqls); ++i)
371 {
372 /* creating threads above DISPATCH_LEVEL... nope */
373 if (Irqls[i] >= DISPATCH_LEVEL)
374 continue;
375 KeRaiseIrql(Irqls[i], &Irql);
376 trace("IRQL: %u\n", Irqls[i]);
377 for (PriorityIncrement = -1; PriorityIncrement <= 8; ++PriorityIncrement)
378 {
379 if (PriorityIncrement < 0 && KmtIsCheckedBuild)
380 continue;
381 trace("PriorityIncrement: %ld\n", PriorityIncrement);
382 trace("-> Checking KeSetEvent, NotificationEvent\n");
383 TestEventConcurrent(&Event, NotificationEvent, Irqls[i], KeSetEvent, PriorityIncrement, 1, TRUE);
384 trace("-> Checking KeSetEvent, SynchronizationEvent\n");
385 TestEventConcurrent(&Event, SynchronizationEvent, Irqls[i], KeSetEvent, PriorityIncrement, 0, FALSE);
386 trace("-> Checking KePulseEvent, NotificationEvent\n");
387 TestEventConcurrent(&Event, NotificationEvent, Irqls[i], KePulseEvent, PriorityIncrement, 0, TRUE);
388 trace("-> Checking KePulseEvent, SynchronizationEvent\n");
389 TestEventConcurrent(&Event, SynchronizationEvent, Irqls[i], KePulseEvent, PriorityIncrement, 0, FALSE);
390 }
392 }
393
394 ok_irql(PASSIVE_LEVEL);
396
399}
static VOID TestEventFunctional(IN PKEVENT Event, IN EVENT_TYPE Type, IN KIRQL OriginalIrql)
Definition: KeEvent.c:38
#define CheckEvent(Event, ExpectedType, State, ExpectedWaitNext, Irql, ThreadList, ThreadCount)
Definition: KeEvent.c:10
LONG(NTAPI * PSET_EVENT_FUNCTION)(PRKEVENT, KPRIORITY, BOOLEAN)
Definition: KeEvent.c:135
static VOID NTAPI WaitForEventThread(IN OUT PVOID Context)
Definition: KeEvent.c:122
static VOID TestEventConcurrent(IN PKEVENT Event, IN EVENT_TYPE Type, IN KIRQL OriginalIrql, PSET_EVENT_FUNCTION SetEvent, KPRIORITY PriorityIncrement, LONG ExpectedState, BOOLEAN SatisfiesAll)
Definition: KeEvent.c:139
static VOID NTAPI TestEventScheduling(_In_ PVOID Context)
Definition: KeEvent.c:271
#define NUM_SCHED_TESTS
Definition: KeEvent.c:231
struct THREAD_DATA * PTHREAD_DATA
static VOID NTAPI CountThread(IN OUT PVOID Context)
Definition: KeEvent.c:245
struct COUNT_THREAD_DATA * PCOUNT_THREAD_DATA
unsigned char BOOLEAN
#define RTL_NUMBER_OF(x)
Definition: RtlRegistry.c:12
Type
Definition: Type.h:7
#define ok_eq_hex(value, expected)
Definition: apitest.h:77
#define ok_eq_long(value, expected)
Definition: apitest.h:62
#define ok_eq_uint(value, expected)
Definition: apitest.h:61
#define trace
Definition: atltest.h:70
#define ok(value,...)
Definition: atltest.h:57
#define skip(...)
Definition: atltest.h:64
#define START_TEST(x)
Definition: atltest.h:75
LONG NTSTATUS
Definition: precomp.h:26
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:36
_Out_ PKIRQL Irql
Definition: csq.h:179
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
LONG KPRIORITY
Definition: compat.h:803
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define KeRaiseIrql(irql, oldIrql)
Definition: env_spec_w32.h:597
#define KeWaitForSingleObject(pEvt, foo, a, b, c)
Definition: env_spec_w32.h:478
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define APC_LEVEL
Definition: env_spec_w32.h:695
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
#define KeSetEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:476
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
#define KeDelayExecutionThread(mode, foo, t)
Definition: env_spec_w32.h:484
#define PagedPool
Definition: env_spec_w32.h:308
LONG NTAPI KePulseEvent(IN PKEVENT Event, IN KPRIORITY Increment, IN BOOLEAN Wait)
Definition: eventobj.c:68
VOID NTAPI KeClearEvent(IN PKEVENT Event)
Definition: eventobj.c:22
LONG NTAPI KeResetEvent(IN PKEVENT Event)
Definition: eventobj.c:133
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
ULONG Handle
Definition: gdb_input.c:15
Status
Definition: gdiplustypes.h:25
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define KeGetCurrentThread
Definition: hal.h:55
#define OBJ_KERNEL_HANDLE
Definition: winternl.h:231
#define RtlFillMemory(Dest, Length, Fill)
Definition: winternl.h:599
#define MILLISECOND
Definition: kmt_test.h:276
PKTHREAD KmtStartThread(IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext OPTIONAL)
VOID KmtSetIrql(IN KIRQL NewIrql)
BOOLEAN KmtIsCheckedBuild
BOOLEAN KmtIsMultiProcessorBuild
VOID KmtFinishThread(IN PKTHREAD Thread OPTIONAL, IN PKEVENT Event OPTIONAL)
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
#define min(a, b)
Definition: monoChain.cc:55
#define _In_
Definition: ms_sal.h:308
#define KernelMode
Definition: asm.h:34
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
#define SYNCHRONIZE
Definition: nt_native.h:61
#define GENERIC_ALL
Definition: nt_native.h:92
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
@ NotificationEvent
@ SynchronizationEvent
@ WaitAll
@ WaitAny
enum _EVENT_TYPE EVENT_TYPE
NTSTATUS NTAPI KeWaitForMultipleObjects(IN ULONG Count, IN PVOID Object[], IN WAIT_TYPE WaitType, IN KWAIT_REASON WaitReason, IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL, OUT PKWAIT_BLOCK WaitBlockArray OPTIONAL)
Definition: wait.c:586
POBJECT_TYPE PsThreadType
Definition: thread.c:20
NTSTATUS NTAPI PsCreateSystemThread(OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN HANDLE ProcessHandle, IN PCLIENT_ID ClientId, IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext)
Definition: thread.c:602
#define STATUS_TIMEOUT
Definition: ntstatus.h:81
#define STATUS_WAIT_0
Definition: ntstatus.h:237
#define L(x)
Definition: ntvdm.h:50
NTSTATUS NTAPI ObReferenceObjectByHandle(IN HANDLE Handle, IN ACCESS_MASK DesiredAccess, IN POBJECT_TYPE ObjectType, IN KPROCESSOR_MODE AccessMode, OUT PVOID *Object, OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL)
Definition: obref.c:494
#define BOOLEAN
Definition: pedump.c:73
long LONG
Definition: pedump.c:60
#define memset(x, y, z)
Definition: compat.h:39
#define STATUS_SUCCESS
Definition: shellext.h:65
KEVENT WaitEvent
Definition: KeEvent.c:236
KPRIORITY PriorityIncrement
Definition: KeEvent.c:238
volatile BOOLEAN Signal
Definition: KeEvent.c:116
PKTHREAD Thread
Definition: ExFastMutex.c:143
PKEVENT Event
Definition: KeEvent.c:115
static LARGE_INTEGER Counter
Definition: clock.c:43
#define max(a, b)
Definition: svc.c:63
BOOL WINAPI DECLSPEC_HOTPATCH SetEvent(IN HANDLE hEvent)
Definition: synch.c:733
KPRIORITY NTAPI KeQueryPriorityThread(IN PKTHREAD Thread)
Definition: thrdobj.c:1008
#define NTAPI
Definition: typedefs.h:36
int32_t INT
Definition: typedefs.h:58
#define IN
Definition: typedefs.h:39
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
LONGLONG QuadPart
Definition: typedefs.h:114
_In_ WDF_POWER_DEVICE_STATE PreviousState
Definition: wdfdevice.h:829
_In_ WDFINTERRUPT _In_ WDF_INTERRUPT_POLICY _In_ WDF_INTERRUPT_PRIORITY Priority
Definition: wdfinterrupt.h:655
#define IO_NO_INCREMENT
Definition: iotypes.h:598
@ Executive
Definition: ketypes.h:415
struct _KEVENT PRKEVENT
#define ObDereferenceObject
Definition: obfuncs.h:203