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 <thfabba@gmx.de>
10 /* TODO: why does GCC have 3 tests less than MSVC?! */
12 #define CheckEvent(Event, ExpectedType, State, ExpectedWaitNext, \
13 Irql, ThreadList, ThreadCount) do \
16 PLIST_ENTRY TheEntry; \
18 ok_eq_uint((Event)->Header.Type, ExpectedType); \
19 ok_eq_uint((Event)->Header.Hand, sizeof *(Event) / sizeof(ULONG)); \
20 ok_eq_hex((Event)->Header.Lock & 0xFF00FF00L, 0x55005500L); \
21 ok_eq_long((Event)->Header.SignalState, State); \
22 TheEntry = (Event)->Header.WaitListHead.Flink; \
23 for (TheIndex = 0; TheIndex < (ThreadCount); ++TheIndex) \
25 TheThread = CONTAINING_RECORD(TheEntry, KTHREAD, \
26 WaitBlock[0].WaitListEntry); \
27 ok_eq_pointer(TheThread, (ThreadList)[TheIndex]); \
28 ok_eq_pointer(TheEntry->Flink->Blink, TheEntry); \
29 TheEntry = TheEntry->Flink; \
31 ok_eq_pointer(TheEntry, &(Event)->Header.WaitListHead); \
32 ok_eq_pointer(TheEntry->Flink->Blink, TheEntry); \
33 ok_eq_long(KeReadStateEvent(Event), State); \
34 ok_eq_bool(Thread->WaitNext, ExpectedWaitNext); \
43 IN KIRQL OriginalIrql
)
46 PKTHREAD Thread
= KeGetCurrentThread();
48 memset(Event
, 0x55, sizeof *Event
);
49 KeInitializeEvent(Event
, Type
, FALSE
);
50 CheckEvent(Event
, Type
, 0L, FALSE
, OriginalIrql
, (PVOID
*)NULL
, 0);
52 memset(Event
, 0x55, sizeof *Event
);
53 KeInitializeEvent(Event
, Type
, TRUE
);
54 CheckEvent(Event
, Type
, 1L, FALSE
, OriginalIrql
, (PVOID
*)NULL
, 0);
56 Event
->Header
.SignalState
= 0x12345678L
;
57 CheckEvent(Event
, Type
, 0x12345678L
, FALSE
, OriginalIrql
, (PVOID
*)NULL
, 0);
59 State
= KePulseEvent(Event
, 0, FALSE
);
60 CheckEvent(Event
, Type
, 0L, FALSE
, OriginalIrql
, (PVOID
*)NULL
, 0);
61 ok_eq_long(State
, 0x12345678L
);
63 Event
->Header
.SignalState
= 0x12345678L
;
65 CheckEvent(Event
, Type
, 0L, FALSE
, OriginalIrql
, (PVOID
*)NULL
, 0);
67 State
= KeSetEvent(Event
, 0, FALSE
);
68 CheckEvent(Event
, Type
, 1L, FALSE
, OriginalIrql
, (PVOID
*)NULL
, 0);
69 ok_eq_long(State
, 0L);
71 State
= KeResetEvent(Event
);
72 CheckEvent(Event
, Type
, 0L, FALSE
, OriginalIrql
, (PVOID
*)NULL
, 0);
73 ok_eq_long(State
, 1L);
75 Event
->Header
.SignalState
= 0x23456789L
;
76 State
= KeSetEvent(Event
, 0, FALSE
);
77 CheckEvent(Event
, Type
, 1L, FALSE
, OriginalIrql
, (PVOID
*)NULL
, 0);
78 ok_eq_long(State
, 0x23456789L
);
80 Event
->Header
.SignalState
= 0x3456789AL
;
81 State
= KeResetEvent(Event
);
82 CheckEvent(Event
, Type
, 0L, FALSE
, OriginalIrql
, (PVOID
*)NULL
, 0);
83 ok_eq_long(State
, 0x3456789AL
);
85 /* Irql is raised to DISPATCH_LEVEL here, which kills checked build,
86 * a spinlock is acquired and never released, which kills MP build */
87 if ((OriginalIrql
<= DISPATCH_LEVEL
|| !KmtIsCheckedBuild
) &&
88 !KmtIsMultiProcessorBuild
)
90 Event
->Header
.SignalState
= 0x456789ABL
;
91 State
= KeSetEvent(Event
, 0, TRUE
);
92 CheckEvent(Event
, Type
, 1L, TRUE
, DISPATCH_LEVEL
, (PVOID
*)NULL
, 0);
93 ok_eq_long(State
, 0x456789ABL
);
94 ok_eq_uint(Thread
->WaitIrql
, OriginalIrql
);
95 /* repair the "damage" */
96 Thread
->WaitNext
= FALSE
;
97 KmtSetIrql(OriginalIrql
);
99 Event
->Header
.SignalState
= 0x56789ABCL
;
100 State
= KePulseEvent(Event
, 0, TRUE
);
101 CheckEvent(Event
, Type
, 0L, TRUE
, DISPATCH_LEVEL
, (PVOID
*)NULL
, 0);
102 ok_eq_long(State
, 0x56789ABCL
);
103 ok_eq_uint(Thread
->WaitIrql
, OriginalIrql
);
104 /* repair the "damage" */
105 Thread
->WaitNext
= FALSE
;
106 KmtSetIrql(OriginalIrql
);
109 ok_irql(OriginalIrql
);
110 KmtSetIrql(OriginalIrql
);
118 volatile BOOLEAN Signal
;
119 } THREAD_DATA
, *PTHREAD_DATA
;
125 IN OUT PVOID Context
)
128 PTHREAD_DATA ThreadData
= Context
;
130 ok_irql(PASSIVE_LEVEL
);
131 ThreadData
->Signal
= TRUE
;
132 Status
= KeWaitForSingleObject(ThreadData
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
133 ok_eq_hex(Status
, STATUS_SUCCESS
);
134 ok_irql(PASSIVE_LEVEL
);
137 typedef LONG (NTAPI
*PSET_EVENT_FUNCTION
)(PRKEVENT
, KPRIORITY
, BOOLEAN
);
144 IN KIRQL OriginalIrql
,
145 PSET_EVENT_FUNCTION SetEvent
,
146 KPRIORITY PriorityIncrement
,
148 BOOLEAN SatisfiesAll
)
151 THREAD_DATA Threads
[5];
152 const INT ThreadCount
= sizeof Threads
/ sizeof Threads
[0];
154 LARGE_INTEGER LongTimeout
, ShortTimeout
;
156 KWAIT_BLOCK WaitBlock
[MAXIMUM_WAIT_OBJECTS
];
157 PVOID ThreadObjects
[MAXIMUM_WAIT_OBJECTS
];
159 PKTHREAD Thread
= KeGetCurrentThread();
161 LongTimeout
.QuadPart
= -100 * MILLISECOND
;
162 ShortTimeout
.QuadPart
= -1 * MILLISECOND
;
164 KeInitializeEvent(Event
, Type
, FALSE
);
166 for (i
= 0; i
< ThreadCount
; ++i
)
168 Threads
[i
].Event
= Event
;
169 Threads
[i
].Signal
= FALSE
;
170 Status
= PsCreateSystemThread(&Threads
[i
].Handle
, GENERIC_ALL
, NULL
, NULL
, NULL
, WaitForEventThread
, &Threads
[i
]);
171 ok_eq_hex(Status
, STATUS_SUCCESS
);
172 Status
= ObReferenceObjectByHandle(Threads
[i
].Handle
, SYNCHRONIZE
, PsThreadType
, KernelMode
, (PVOID
*)&Threads
[i
].Thread
, NULL
);
173 ok_eq_hex(Status
, STATUS_SUCCESS
);
174 ThreadObjects
[i
] = Threads
[i
].Thread
;
175 Priority
= KeQueryPriorityThread(Threads
[i
].Thread
);
176 ok_eq_long(Priority
, 8L);
177 while (!Threads
[i
].Signal
)
179 Status
= KeDelayExecutionThread(KernelMode
, FALSE
, &ShortTimeout
);
180 ok_eq_hex(Status
, STATUS_SUCCESS
);
182 CheckEvent(Event
, Type
, 0L, FALSE
, OriginalIrql
, ThreadObjects
, i
+ 1);
185 /* the threads shouldn't wake up on their own */
186 Status
= KeDelayExecutionThread(KernelMode
, FALSE
, &ShortTimeout
);
187 ok_eq_hex(Status
, STATUS_SUCCESS
);
189 for (i
= 0; i
< ThreadCount
; ++i
)
191 CheckEvent(Event
, Type
, 0L, FALSE
, OriginalIrql
, ThreadObjects
+ i
, ThreadCount
- i
);
192 State
= SetEvent(Event
, PriorityIncrement
+ i
, FALSE
);
194 ok_eq_long(State
, 0L);
195 CheckEvent(Event
, Type
, ExpectedState
, FALSE
, OriginalIrql
, ThreadObjects
+ i
+ 1, SatisfiesAll
? 0 : ThreadCount
- i
- 1);
196 Status
= KeWaitForMultipleObjects(ThreadCount
, ThreadObjects
, SatisfiesAll
? WaitAll
: WaitAny
, Executive
, KernelMode
, FALSE
, &LongTimeout
, WaitBlock
);
197 ok_eq_hex(Status
, STATUS_WAIT_0
+ i
);
200 for (; i
< ThreadCount
; ++i
)
202 Priority
= KeQueryPriorityThread(Threads
[i
].Thread
);
203 ok_eq_long(Priority
, max(min(8L + PriorityIncrement
, 15L), 8L));
207 Priority
= KeQueryPriorityThread(Threads
[i
].Thread
);
208 ok_eq_long(Priority
, max(min(8L + PriorityIncrement
+ i
, 15L), 8L));
209 /* replace the thread with the current thread - which will never signal */
210 if (!skip((Status
& 0x3F) < ThreadCount
, "Index out of bounds"))
211 ThreadObjects
[Status
& 0x3F] = Thread
;
212 Status
= KeWaitForMultipleObjects(ThreadCount
, ThreadObjects
, WaitAny
, Executive
, KernelMode
, FALSE
, &ShortTimeout
, WaitBlock
);
213 ok_eq_hex(Status
, STATUS_TIMEOUT
);
216 for (i
= 0; i
< ThreadCount
; ++i
)
218 ObDereferenceObject(Threads
[i
].Thread
);
219 Status
= ZwClose(Threads
[i
].Handle
);
220 ok_eq_hex(Status
, STATUS_SUCCESS
);
228 KIRQL Irqls
[] = { PASSIVE_LEVEL
, APC_LEVEL
, DISPATCH_LEVEL
, HIGH_LEVEL
};
230 KPRIORITY PriorityIncrement
;
232 for (i
= 0; i
< sizeof Irqls
/ sizeof Irqls
[0]; ++i
)
234 /* DRIVER_IRQL_NOT_LESS_OR_EQUAL (TODO: on MP only?) */
235 if (Irqls
[i
] > DISPATCH_LEVEL
&& KmtIsCheckedBuild
)
237 KeRaiseIrql(Irqls
[i
], &Irql
);
238 TestEventFunctional(&Event
, NotificationEvent
, Irqls
[i
]);
239 TestEventFunctional(&Event
, SynchronizationEvent
, Irqls
[i
]);
243 for (i
= 0; i
< sizeof Irqls
/ sizeof Irqls
[0]; ++i
)
245 /* creating threads above DISPATCH_LEVEL... nope */
246 if (Irqls
[i
] >= DISPATCH_LEVEL
&& KmtIsCheckedBuild
)
248 KeRaiseIrql(Irqls
[i
], &Irql
);
249 trace("IRQL: %u\n", Irqls
[i
]);
250 for (PriorityIncrement
= -1; PriorityIncrement
<= 8; ++PriorityIncrement
)
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
);