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>
10 #define CheckEvent(Event, ExpectedType, State, ExpectedWaitNext, \
11 Irql, ThreadList, ThreadCount) do \
14 PLIST_ENTRY TheEntry; \
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) \
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; \
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); \
41 IN KIRQL OriginalIrql
)
44 PKTHREAD Thread
= KeGetCurrentThread();
46 memset(Event
, 0x55, sizeof *Event
);
47 KeInitializeEvent(Event
, Type
, FALSE
);
48 CheckEvent(Event
, Type
, 0L, FALSE
, OriginalIrql
, (PVOID
*)NULL
, 0);
50 memset(Event
, 0x55, sizeof *Event
);
51 KeInitializeEvent(Event
, Type
, TRUE
);
52 CheckEvent(Event
, Type
, 1L, FALSE
, OriginalIrql
, (PVOID
*)NULL
, 0);
54 Event
->Header
.SignalState
= 0x12345678L
;
55 CheckEvent(Event
, Type
, 0x12345678L
, FALSE
, OriginalIrql
, (PVOID
*)NULL
, 0);
57 State
= KePulseEvent(Event
, 0, FALSE
);
58 CheckEvent(Event
, Type
, 0L, FALSE
, OriginalIrql
, (PVOID
*)NULL
, 0);
59 ok_eq_long(State
, 0x12345678L
);
61 Event
->Header
.SignalState
= 0x12345678L
;
63 CheckEvent(Event
, Type
, 0L, FALSE
, OriginalIrql
, (PVOID
*)NULL
, 0);
65 State
= KeSetEvent(Event
, 0, FALSE
);
66 CheckEvent(Event
, Type
, 1L, FALSE
, OriginalIrql
, (PVOID
*)NULL
, 0);
67 ok_eq_long(State
, 0L);
69 State
= KeResetEvent(Event
);
70 CheckEvent(Event
, Type
, 0L, FALSE
, OriginalIrql
, (PVOID
*)NULL
, 0);
71 ok_eq_long(State
, 1L);
73 Event
->Header
.SignalState
= 0x23456789L
;
74 State
= KeSetEvent(Event
, 0, FALSE
);
75 CheckEvent(Event
, Type
, 1L, FALSE
, OriginalIrql
, (PVOID
*)NULL
, 0);
76 ok_eq_long(State
, 0x23456789L
);
78 Event
->Header
.SignalState
= 0x3456789AL
;
79 State
= KeResetEvent(Event
);
80 CheckEvent(Event
, Type
, 0L, FALSE
, OriginalIrql
, (PVOID
*)NULL
, 0);
81 ok_eq_long(State
, 0x3456789AL
);
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
) &&
86 !KmtIsMultiProcessorBuild
)
88 Event
->Header
.SignalState
= 0x456789ABL
;
89 State
= KeSetEvent(Event
, 0, TRUE
);
90 CheckEvent(Event
, Type
, 1L, TRUE
, DISPATCH_LEVEL
, (PVOID
*)NULL
, 0);
91 ok_eq_long(State
, 0x456789ABL
);
92 ok_eq_uint(Thread
->WaitIrql
, OriginalIrql
);
93 /* repair the "damage" */
94 Thread
->WaitNext
= FALSE
;
95 KmtSetIrql(OriginalIrql
);
97 Event
->Header
.SignalState
= 0x56789ABCL
;
98 State
= KePulseEvent(Event
, 0, TRUE
);
99 CheckEvent(Event
, Type
, 0L, TRUE
, DISPATCH_LEVEL
, (PVOID
*)NULL
, 0);
100 ok_eq_long(State
, 0x56789ABCL
);
101 ok_eq_uint(Thread
->WaitIrql
, OriginalIrql
);
102 /* repair the "damage" */
103 Thread
->WaitNext
= FALSE
;
104 KmtSetIrql(OriginalIrql
);
107 ok_irql(OriginalIrql
);
108 KmtSetIrql(OriginalIrql
);
116 volatile BOOLEAN Signal
;
117 } THREAD_DATA
, *PTHREAD_DATA
;
123 IN OUT PVOID Context
)
126 PTHREAD_DATA ThreadData
= Context
;
128 ok_irql(PASSIVE_LEVEL
);
129 ThreadData
->Signal
= TRUE
;
130 Status
= KeWaitForSingleObject(ThreadData
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
131 ok_eq_hex(Status
, STATUS_SUCCESS
);
132 ok_irql(PASSIVE_LEVEL
);
135 typedef LONG (NTAPI
*PSET_EVENT_FUNCTION
)(PRKEVENT
, KPRIORITY
, BOOLEAN
);
142 IN KIRQL OriginalIrql
,
143 PSET_EVENT_FUNCTION SetEvent
,
144 KPRIORITY PriorityIncrement
,
146 BOOLEAN SatisfiesAll
)
149 THREAD_DATA Threads
[5];
150 const INT ThreadCount
= sizeof Threads
/ sizeof Threads
[0];
152 LARGE_INTEGER LongTimeout
, ShortTimeout
;
154 KWAIT_BLOCK WaitBlock
[RTL_NUMBER_OF(Threads
)];
155 PVOID ThreadObjects
[RTL_NUMBER_OF(Threads
)];
157 PKTHREAD Thread
= KeGetCurrentThread();
159 LongTimeout
.QuadPart
= -100 * MILLISECOND
;
160 ShortTimeout
.QuadPart
= -1 * MILLISECOND
;
162 KeInitializeEvent(Event
, Type
, FALSE
);
164 for (i
= 0; i
< ThreadCount
; ++i
)
166 Threads
[i
].Event
= Event
;
167 Threads
[i
].Signal
= FALSE
;
168 Status
= PsCreateSystemThread(&Threads
[i
].Handle
, GENERIC_ALL
, NULL
, NULL
, NULL
, WaitForEventThread
, &Threads
[i
]);
169 ok_eq_hex(Status
, STATUS_SUCCESS
);
170 Status
= ObReferenceObjectByHandle(Threads
[i
].Handle
, SYNCHRONIZE
, *PsThreadType
, KernelMode
, (PVOID
*)&Threads
[i
].Thread
, NULL
);
171 ok_eq_hex(Status
, STATUS_SUCCESS
);
172 ThreadObjects
[i
] = Threads
[i
].Thread
;
173 Priority
= KeQueryPriorityThread(Threads
[i
].Thread
);
174 ok_eq_long(Priority
, 8L);
175 while (!Threads
[i
].Signal
)
177 Status
= KeDelayExecutionThread(KernelMode
, FALSE
, &ShortTimeout
);
178 if (Status
!= STATUS_SUCCESS
)
180 ok_eq_hex(Status
, STATUS_SUCCESS
);
183 CheckEvent(Event
, Type
, 0L, FALSE
, OriginalIrql
, ThreadObjects
, i
+ 1);
186 /* the threads shouldn't wake up on their own */
187 Status
= KeDelayExecutionThread(KernelMode
, FALSE
, &ShortTimeout
);
188 ok_eq_hex(Status
, STATUS_SUCCESS
);
190 for (i
= 0; i
< ThreadCount
; ++i
)
192 CheckEvent(Event
, Type
, 0L, FALSE
, OriginalIrql
, ThreadObjects
+ i
, ThreadCount
- i
);
193 State
= SetEvent(Event
, PriorityIncrement
+ i
, FALSE
);
195 ok_eq_long(State
, 0L);
196 CheckEvent(Event
, Type
, ExpectedState
, FALSE
, OriginalIrql
, ThreadObjects
+ i
+ 1, SatisfiesAll
? 0 : ThreadCount
- i
- 1);
197 Status
= KeWaitForMultipleObjects(ThreadCount
, ThreadObjects
, SatisfiesAll
? WaitAll
: WaitAny
, Executive
, KernelMode
, FALSE
, &LongTimeout
, WaitBlock
);
198 ok_eq_hex(Status
, STATUS_WAIT_0
+ i
);
201 for (; i
< ThreadCount
; ++i
)
203 Priority
= KeQueryPriorityThread(Threads
[i
].Thread
);
204 ok_eq_long(Priority
, max(min(8L + PriorityIncrement
, 15L), 8L));
208 Priority
= KeQueryPriorityThread(Threads
[i
].Thread
);
209 ok_eq_long(Priority
, max(min(8L + PriorityIncrement
+ i
, 15L), 8L));
210 /* replace the thread with the current thread - which will never signal */
211 if (!skip((Status
& 0x3F) < ThreadCount
, "Index out of bounds"))
212 ThreadObjects
[Status
& 0x3F] = Thread
;
213 Status
= KeWaitForMultipleObjects(ThreadCount
, ThreadObjects
, WaitAny
, Executive
, KernelMode
, FALSE
, &ShortTimeout
, WaitBlock
);
214 ok_eq_hex(Status
, STATUS_TIMEOUT
);
217 for (i
= 0; i
< ThreadCount
; ++i
)
219 ObDereferenceObject(Threads
[i
].Thread
);
220 Status
= ZwClose(Threads
[i
].Handle
);
221 ok_eq_hex(Status
, STATUS_SUCCESS
);
229 KIRQL Irqls
[] = { PASSIVE_LEVEL
, APC_LEVEL
, DISPATCH_LEVEL
};
231 KPRIORITY PriorityIncrement
;
233 for (i
= 0; i
< RTL_NUMBER_OF(Irqls
); ++i
)
235 KeRaiseIrql(Irqls
[i
], &Irql
);
236 TestEventFunctional(&Event
, NotificationEvent
, Irqls
[i
]);
237 TestEventFunctional(&Event
, SynchronizationEvent
, Irqls
[i
]);
241 for (i
= 0; i
< RTL_NUMBER_OF(Irqls
); ++i
)
243 /* creating threads above DISPATCH_LEVEL... nope */
244 if (Irqls
[i
] >= DISPATCH_LEVEL
)
246 KeRaiseIrql(Irqls
[i
], &Irql
);
247 trace("IRQL: %u\n", Irqls
[i
]);
248 for (PriorityIncrement
= -1; PriorityIncrement
<= 8; ++PriorityIncrement
)
250 if (PriorityIncrement
< 0 && KmtIsCheckedBuild
)
252 trace("PriorityIncrement: %ld\n", PriorityIncrement
);
253 trace("-> Checking KeSetEvent, NotificationEvent\n");
254 TestEventConcurrent(&Event
, NotificationEvent
, Irqls
[i
], KeSetEvent
, PriorityIncrement
, 1, TRUE
);
255 trace("-> Checking KeSetEvent, SynchronizationEvent\n");
256 TestEventConcurrent(&Event
, SynchronizationEvent
, Irqls
[i
], KeSetEvent
, PriorityIncrement
, 0, FALSE
);
257 trace("-> Checking KePulseEvent, NotificationEvent\n");
258 TestEventConcurrent(&Event
, NotificationEvent
, Irqls
[i
], KePulseEvent
, PriorityIncrement
, 0, TRUE
);
259 trace("-> Checking KePulseEvent, SynchronizationEvent\n");
260 TestEventConcurrent(&Event
, SynchronizationEvent
, Irqls
[i
], KePulseEvent
, PriorityIncrement
, 0, FALSE
);
265 ok_irql(PASSIVE_LEVEL
);
266 KmtSetIrql(PASSIVE_LEVEL
);