ReactOS 0.4.16-dev-1946-g52006dd
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
163 if (skip(GetNTVersion() < _WIN32_WINNT_VISTA, "TestEventConcurrent() is broken on Vista+.\n"))
164 return;
165
167
168 for (i = 0; i < ThreadCount; ++i)
169 {
170 Threads[i].Event = Event;
171 Threads[i].Signal = FALSE;
173 NULL,
175 NULL,
176 NULL);
181 ThreadObjects[i] = Threads[i].Thread;
183 ok_eq_long(Priority, 8L);
184 while (!Threads[i].Signal)
185 {
187 if (Status != STATUS_SUCCESS)
188 {
190 }
191 }
192 CheckEvent(Event, Type, 0L, FALSE, OriginalIrql, ThreadObjects, i + 1);
193 }
194
195 /* the threads shouldn't wake up on their own */
198
199 for (i = 0; i < ThreadCount; ++i)
200 {
201 CheckEvent(Event, Type, 0L, FALSE, OriginalIrql, ThreadObjects + i, ThreadCount - i);
202 State = SetEvent(Event, PriorityIncrement + i, FALSE);
203
204 ok_eq_long(State, 0L);
205 CheckEvent(Event, Type, ExpectedState, FALSE, OriginalIrql, ThreadObjects + i + 1, SatisfiesAll ? 0 : ThreadCount - i - 1);
206 Status = KeWaitForMultipleObjects(ThreadCount, ThreadObjects, SatisfiesAll ? WaitAll : WaitAny, Executive, KernelMode, FALSE, &LongTimeout, WaitBlock);
208 if (SatisfiesAll)
209 {
210 for (; i < ThreadCount; ++i)
211 {
213 ok_eq_long(Priority, max(min(8L + PriorityIncrement, 15L), 8L));
214 }
215 break;
216 }
218 ok_eq_long(Priority, max(min(8L + PriorityIncrement + i, 15L), 8L));
219 /* replace the thread with the current thread - which will never signal */
220 if (!skip((Status & 0x3F) < ThreadCount, "Index out of bounds\n"))
221 ThreadObjects[Status & 0x3F] = Thread;
222 Status = KeWaitForMultipleObjects(ThreadCount, ThreadObjects, WaitAny, Executive, KernelMode, FALSE, &ShortTimeout, WaitBlock);
224 }
225
226 for (i = 0; i < ThreadCount; ++i)
227 {
228 ObDereferenceObject(Threads[i].Thread);
229 Status = ZwClose(Threads[i].Handle);
231 }
232}
233
234#define NUM_SCHED_TESTS 1000
235
236typedef struct
237{
242 ULONG CounterValues[NUM_SCHED_TESTS];
244
245static
246VOID
247NTAPI
250{
252 PKEVENT Event = &ThreadData->Event;
253 volatile ULONG *Counter = &ThreadData->Counter;
254 ULONG *CounterValue = ThreadData->CounterValues;
256
258 ok_eq_long(Priority, 8L);
259
260 while (CounterValue < &ThreadData->CounterValues[NUM_SCHED_TESTS])
261 {
264 *CounterValue++ = *Counter;
265 }
266
268 ok_eq_long(Priority, 8L + min(ThreadData->PriorityIncrement, 7));
269}
270
271static
272VOID
273NTAPI
276{
281 ULONG i;
282 volatile ULONG *Counter;
283 KPRIORITY PriorityIncrement;
285
287
289 if (skip(ThreadData != NULL, "Out of memory\n"))
290 {
291 return;
292 }
295 Counter = &ThreadData->Counter;
296
297 for (PriorityIncrement = 0; PriorityIncrement <= 8; PriorityIncrement++)
298 {
299 ThreadData->PriorityIncrement = PriorityIncrement;
300 ThreadData->Counter = 0;
301 RtlFillMemory(ThreadData->CounterValues,
302 sizeof(ThreadData->CounterValues),
303 0xFE);
306 ok(Priority == 8, "[%lu] Priority = %lu\n", PriorityIncrement, Priority);
307 for (i = 1; i <= NUM_SCHED_TESTS; i++)
308 {
311 PreviousState = KeSetEvent(&ThreadData->Event, PriorityIncrement, FALSE);
312 *Counter = i;
314 }
316 ok(Priority == 8, "[%lu] Priority = %lu\n", PriorityIncrement, Priority);
318
319 if (PriorityIncrement == 0)
320 {
321 /* Both threads have the same priority, so either can win the race */
322 ok(ThreadData->CounterValues[0] == 0 || ThreadData->CounterValues[0] == 1,
323 "[%lu] Counter 0 = %lu\n",
324 PriorityIncrement, ThreadData->CounterValues[0]);
325 }
326 else
327 {
328 /* CountThread has the higher priority, it will always win */
329 ok(ThreadData->CounterValues[0] == 0,
330 "[%lu] Counter 0 = %lu\n",
331 PriorityIncrement, ThreadData->CounterValues[0]);
332 }
333 for (i = 1; i < NUM_SCHED_TESTS; i++)
334 {
335 if (PriorityIncrement == 0)
336 {
337 ok(ThreadData->CounterValues[i] == i ||
338 ThreadData->CounterValues[i] == i + 1,
339 "[%lu] Counter %lu = %lu, expected %lu or %lu\n",
340 PriorityIncrement, i,
341 ThreadData->CounterValues[i], i, i + 1);
342 }
343 else
344 {
345 ok(ThreadData->CounterValues[i] == ThreadData->CounterValues[i - 1] + 1,
346 "[%lu] Counter %lu = %lu, expected %lu\n",
347 PriorityIncrement, i,
348 ThreadData->CounterValues[i], ThreadData->CounterValues[i - 1] + 1);
349 }
350 }
351 }
352
354}
355
357{
360 KIRQL Irql;
362 ULONG i;
363 KPRIORITY PriorityIncrement;
364
365 for (i = 0; i < RTL_NUMBER_OF(Irqls); ++i)
366 {
367 KeRaiseIrql(Irqls[i], &Irql);
371 }
372
373 for (i = 0; i < RTL_NUMBER_OF(Irqls); ++i)
374 {
375 /* creating threads above DISPATCH_LEVEL... nope */
376 if (Irqls[i] >= DISPATCH_LEVEL)
377 continue;
378 KeRaiseIrql(Irqls[i], &Irql);
379 trace("IRQL: %u\n", Irqls[i]);
380 for (PriorityIncrement = -1; PriorityIncrement <= 8; ++PriorityIncrement)
381 {
382 if (PriorityIncrement < 0 && KmtIsCheckedBuild)
383 continue;
384 trace("PriorityIncrement: %ld\n", PriorityIncrement);
385 trace("-> Checking KeSetEvent, NotificationEvent\n");
386 TestEventConcurrent(&Event, NotificationEvent, Irqls[i], KeSetEvent, PriorityIncrement, 1, TRUE);
387 trace("-> Checking KeSetEvent, SynchronizationEvent\n");
388 TestEventConcurrent(&Event, SynchronizationEvent, Irqls[i], KeSetEvent, PriorityIncrement, 0, FALSE);
389 trace("-> Checking KePulseEvent, NotificationEvent\n");
390 TestEventConcurrent(&Event, NotificationEvent, Irqls[i], KePulseEvent, PriorityIncrement, 0, TRUE);
391 trace("-> Checking KePulseEvent, SynchronizationEvent\n");
392 TestEventConcurrent(&Event, SynchronizationEvent, Irqls[i], KePulseEvent, PriorityIncrement, 0, FALSE);
393 }
395 }
396
397 ok_irql(PASSIVE_LEVEL);
399
402}
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:274
#define NUM_SCHED_TESTS
Definition: KeEvent.c:234
struct THREAD_DATA * PTHREAD_DATA
static VOID NTAPI CountThread(IN OUT PVOID Context)
Definition: KeEvent.c:248
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:134
#define ok_eq_long(value, expected)
Definition: apitest.h:119
#define GetNTVersion()
Definition: apitest.h:17
#define ok_eq_uint(value, expected)
Definition: apitest.h:118
#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 STATUS_TIMEOUT
Definition: d3dkmdt.h:49
#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 L(x)
Definition: resources.c:13
#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:69
VOID NTAPI KeClearEvent(IN PKEVENT Event)
Definition: eventobj.c:22
LONG NTAPI KeResetEvent(IN PKEVENT Event)
Definition: eventobj.c:134
_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:603
#define MILLISECOND
Definition: kmt_test.h:279
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 KernelMode
Definition: asm.h:38
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
#define _In_
Definition: no_sal2.h:158
#define SYNCHRONIZE
Definition: nt_native.h:61
#define GENERIC_ALL
Definition: nt_native.h:92
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:329
@ 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_WAIT_0
Definition: ntstatus.h:330
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 _WIN32_WINNT_VISTA
Definition: sdkddkver.h:25
#define STATUS_SUCCESS
Definition: shellext.h:65
KEVENT WaitEvent
Definition: KeEvent.c:239
KPRIORITY PriorityIncrement
Definition: KeEvent.c:241
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:467
struct _KEVENT PRKEVENT
#define ObDereferenceObject
Definition: obfuncs.h:203