2b00e3a8874a7f5636e7e1abc3f885bd1fa2c11d
[reactos.git] / kmtests / ntos_ke / KeEvent.c
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 <thfabba@gmx.de>
6 */
7
8 #include <kmt_test.h>
9
10 /* TODO: more thread testing, exports vs macros */
11
12 #define CheckEvent(Event, ExpectedType, State, ExpectedWaitNext, Irql) do \
13 { \
14 ok_eq_uint((Event)->Header.Type, ExpectedType); \
15 ok_eq_uint((Event)->Header.Hand, sizeof *(Event) / sizeof(ULONG)); \
16 ok_eq_long((Event)->Header.Lock & 0xFF00FF00L, 0x55005500L); \
17 ok_eq_long((Event)->Header.SignalState, State); \
18 ok_eq_pointer((Event)->Header.WaitListHead.Flink, \
19 &(Event)->Header.WaitListHead); \
20 ok_eq_pointer((Event)->Header.WaitListHead.Blink, \
21 &(Event)->Header.WaitListHead); \
22 ok_eq_long(KeReadStateEvent(Event), State); \
23 ok_eq_bool(Thread->WaitNext, ExpectedWaitNext); \
24 ok_irql(Irql); \
25 } while (0)
26
27 static
28 VOID
29 TestEventFunctional(
30 IN PKEVENT Event,
31 IN EVENT_TYPE Type,
32 IN KIRQL OriginalIrql)
33 {
34 LONG State;
35 PKTHREAD Thread = KeGetCurrentThread();
36
37 memset(Event, 0x55, sizeof *Event);
38 KeInitializeEvent(Event, Type, FALSE);
39 CheckEvent(Event, Type, 0L, FALSE, OriginalIrql);
40
41 memset(Event, 0x55, sizeof *Event);
42 KeInitializeEvent(Event, Type, TRUE);
43 CheckEvent(Event, Type, 1L, FALSE, OriginalIrql);
44
45 Event->Header.SignalState = 0x12345678L;
46 CheckEvent(Event, Type, 0x12345678L, FALSE, OriginalIrql);
47
48 State = KePulseEvent(Event, 0, FALSE);
49 CheckEvent(Event, Type, 0L, FALSE, OriginalIrql);
50 ok_eq_long(State, 0x12345678L);
51
52 Event->Header.SignalState = 0x12345678L;
53 KeClearEvent(Event);
54 CheckEvent(Event, Type, 0L, FALSE, OriginalIrql);
55
56 State = KeSetEvent(Event, 0, FALSE);
57 CheckEvent(Event, Type, 1L, FALSE, OriginalIrql);
58 ok_eq_long(State, 0L);
59
60 State = KeResetEvent(Event);
61 CheckEvent(Event, Type, 0L, FALSE, OriginalIrql);
62 ok_eq_long(State, 1L);
63
64 Event->Header.SignalState = 0x23456789L;
65 State = KeSetEvent(Event, 0, FALSE);
66 CheckEvent(Event, Type, 1L, FALSE, OriginalIrql);
67 ok_eq_long(State, 0x23456789L);
68
69 Event->Header.SignalState = 0x3456789AL;
70 State = KeResetEvent(Event);
71 CheckEvent(Event, Type, 0L, FALSE, OriginalIrql);
72 ok_eq_long(State, 0x3456789AL);
73
74 if (OriginalIrql <= DISPATCH_LEVEL || !KmtIsCheckedBuild)
75 {
76 Event->Header.SignalState = 0x456789ABL;
77 State = KeSetEvent(Event, 0, TRUE);
78 CheckEvent(Event, Type, 1L, TRUE, DISPATCH_LEVEL);
79 ok_eq_long(State, 0x456789ABL);
80 ok_eq_uint(Thread->WaitIrql, OriginalIrql);
81 /* repair the "damage" */
82 Thread->WaitNext = FALSE;
83 KmtSetIrql(OriginalIrql);
84
85 Event->Header.SignalState = 0x56789ABCL;
86 State = KePulseEvent(Event, 0, TRUE);
87 CheckEvent(Event, Type, 0L, TRUE, DISPATCH_LEVEL);
88 ok_eq_long(State, 0x56789ABCL);
89 ok_eq_uint(Thread->WaitIrql, OriginalIrql);
90 /* repair the "damage" */
91 Thread->WaitNext = FALSE;
92 KmtSetIrql(OriginalIrql);
93 }
94
95 ok_irql(OriginalIrql);
96 KmtSetIrql(OriginalIrql);
97 }
98
99 typedef struct
100 {
101 HANDLE Handle;
102 PKTHREAD Thread;
103 PKEVENT Event1;
104 PKEVENT Event2;
105 volatile BOOLEAN Signal;
106 } THREAD_DATA, *PTHREAD_DATA;
107
108 static
109 VOID
110 NTAPI
111 WaitForEventThread(
112 IN OUT PVOID Context)
113 {
114 NTSTATUS Status;
115 PTHREAD_DATA ThreadData = Context;
116
117 ok_irql(PASSIVE_LEVEL);
118 ThreadData->Signal = TRUE;
119 Status = KeWaitForSingleObject(ThreadData->Event1, Executive, KernelMode, FALSE, NULL);
120 ok_irql(PASSIVE_LEVEL);
121 ok_eq_hex(Status, STATUS_SUCCESS);
122 ThreadData->Signal = TRUE;
123 Status = KeWaitForSingleObject(ThreadData->Event2, Executive, KernelMode, FALSE, NULL);
124 ok_irql(PASSIVE_LEVEL);
125 ok_eq_hex(Status, STATUS_SUCCESS);
126 ok_irql(PASSIVE_LEVEL);
127 }
128
129 static
130 VOID
131 TestEventThreads(
132 IN PKEVENT Event,
133 IN EVENT_TYPE Type,
134 IN KIRQL OriginalIrql)
135 {
136 NTSTATUS Status;
137 THREAD_DATA Threads[5];
138 LARGE_INTEGER Timeout;
139 KPRIORITY Priority;
140 KEVENT WaitEvent;
141 KEVENT TerminateEvent;
142 int i;
143 Timeout.QuadPart = -1000 * 10;
144
145 KeInitializeEvent(Event, Type, FALSE);
146 KeInitializeEvent(&WaitEvent, NotificationEvent, FALSE);
147 KeInitializeEvent(&TerminateEvent, SynchronizationEvent, FALSE);
148
149 for (i = 0; i < sizeof Threads / sizeof Threads[0]; ++i)
150 {
151 Threads[i].Event1 = Event;
152 Threads[i].Event2 = &TerminateEvent;
153 Threads[i].Signal = FALSE;
154 Status = PsCreateSystemThread(&Threads[i].Handle, GENERIC_ALL, NULL, NULL, NULL, WaitForEventThread, &Threads[i]);
155 ok_eq_hex(Status, STATUS_SUCCESS);
156 Status = ObReferenceObjectByHandle(Threads[i].Handle, SYNCHRONIZE, PsThreadType, KernelMode, (PVOID *)&Threads[i].Thread, NULL);
157 ok_eq_hex(Status, STATUS_SUCCESS);
158 Priority = KeQueryPriorityThread(Threads[i].Thread);
159 ok_eq_long(Priority, 8L);
160 while (!Threads[i].Signal)
161 {
162 Status = KeWaitForSingleObject(&WaitEvent, Executive, KernelMode, FALSE, &Timeout);
163 ok_eq_hex(Status, STATUS_TIMEOUT);
164 }
165 Threads[i].Signal = FALSE;
166 }
167
168 for (i = 0; i < sizeof Threads / sizeof Threads[0]; ++i)
169 {
170 KeSetEvent(Event, 1, FALSE);
171 while (!Threads[i].Signal)
172 {
173 Status = KeWaitForSingleObject(&WaitEvent, Executive, KernelMode, FALSE, &Timeout);
174 ok_eq_hex(Status, STATUS_TIMEOUT);
175 }
176 Priority = KeQueryPriorityThread(Threads[i].Thread);
177 ok_eq_long(Priority, 9L);
178 KeSetEvent(&TerminateEvent, 0, FALSE);
179 Status = KeWaitForSingleObject(Threads[i].Thread, Executive, KernelMode, FALSE, NULL);
180 ok_eq_hex(Status, STATUS_SUCCESS);
181
182 ObDereferenceObject(Threads[i].Thread);
183 Status = ZwClose(Threads[i].Handle);
184 ok_eq_hex(Status, STATUS_SUCCESS);
185 }
186 }
187
188 START_TEST(KeEvent)
189 {
190 KEVENT Event;
191 KIRQL Irql;
192 KIRQL Irqls[] = { PASSIVE_LEVEL, APC_LEVEL, DISPATCH_LEVEL, HIGH_LEVEL };
193 int i;
194
195 for (i = 0; i < sizeof Irqls / sizeof Irqls[0]; ++i)
196 {
197 KeRaiseIrql(Irqls[i], &Irql);
198 TestEventFunctional(&Event, NotificationEvent, Irqls[i]);
199 TestEventFunctional(&Event, SynchronizationEvent, Irqls[i]);
200 KeLowerIrql(Irql);
201 }
202
203 TestEventThreads(&Event, NotificationEvent, PASSIVE_LEVEL);
204
205 ok_irql(PASSIVE_LEVEL);
206 KmtSetIrql(PASSIVE_LEVEL);
207 }