[ROSTESTS]
[reactos.git] / rostests / kmtests / ntos_ke / KeDpc.c
1 /*
2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Kernel-Mode Test Suite Deferred Procedure Call test
5 * PROGRAMMER: Thomas Faber <thfabba@gmx.de>
6 */
7
8 #include <kmt_test.h>
9
10 //#define NDEBUG
11 #include <debug.h>
12
13 /* TODO: DPC importance */
14
15 static volatile LONG DpcCount;
16 static volatile UCHAR DpcImportance;
17
18 static KDEFERRED_ROUTINE DpcHandler;
19
20 static
21 VOID
22 NTAPI
23 DpcHandler(
24 IN PRKDPC Dpc,
25 IN PVOID DeferredContext,
26 IN PVOID SystemArgument1,
27 IN PVOID SystemArgument2)
28 {
29 PKPRCB Prcb = KeGetCurrentPrcb();
30
31 ok_irql(DISPATCH_LEVEL);
32 InterlockedIncrement(&DpcCount);
33 ok(DeferredContext == Dpc, "DeferredContext = %p, Dpc = %p, expected equal\n", DeferredContext, Dpc);
34 ok_eq_pointer(SystemArgument1, (PVOID)0xabc123);
35 ok_eq_pointer(SystemArgument2, (PVOID)0x5678);
36
37 /* KDPC object contents */
38 ok_eq_uint(Dpc->Type, DpcObject);
39 ok_eq_uint(Dpc->Importance, DpcImportance);
40 ok_eq_uint(Dpc->Number, 0);
41 ok(Dpc->DpcListEntry.Blink != NULL, "\n");
42 ok(Dpc->DpcListEntry.Blink != &Dpc->DpcListEntry, "\n");
43 if (!skip(Dpc->DpcListEntry.Blink != NULL, "DpcListEntry.Blink == NULL\n"))
44 ok_eq_pointer(Dpc->DpcListEntry.Flink, Dpc->DpcListEntry.Blink->Flink);
45
46 ok(Dpc->DpcListEntry.Flink != NULL, "\n");
47 ok(Dpc->DpcListEntry.Flink != &Dpc->DpcListEntry, "\n");
48 if (!skip(Dpc->DpcListEntry.Flink != NULL, "DpcListEntry.Flink == NULL\n"))
49 ok_eq_pointer(Dpc->DpcListEntry.Blink, Dpc->DpcListEntry.Flink->Blink);
50
51 ok_eq_pointer(Dpc->DeferredRoutine, DpcHandler);
52 ok_eq_pointer(Dpc->DeferredContext, DeferredContext);
53 ok_eq_pointer(Dpc->SystemArgument1, SystemArgument1);
54 ok_eq_pointer(Dpc->SystemArgument2, SystemArgument2);
55 ok_eq_pointer(Dpc->DpcData, NULL);
56
57 ok_eq_uint(Prcb->DpcRoutineActive, 1);
58 /* this DPC is not in the list anymore, but it was at the head! */
59 ok_eq_pointer(Prcb->DpcData[DPC_NORMAL].DpcListHead.Flink, Dpc->DpcListEntry.Flink);
60 ok_eq_pointer(Prcb->DpcData[DPC_NORMAL].DpcListHead.Blink, Dpc->DpcListEntry.Blink);
61 }
62
63 START_TEST(KeDpc)
64 {
65 NTSTATUS Status = STATUS_SUCCESS;
66 KDPC Dpc;
67 KIRQL Irql, Irql2, Irql3;
68 LONG ExpectedDpcCount = 0;
69 BOOLEAN Ret;
70 int i;
71
72 DpcCount = 0;
73 DpcImportance = MediumImportance;
74
75 #define ok_dpccount() ok(DpcCount == ExpectedDpcCount, "DpcCount = %ld, expected %ld\n", DpcCount, ExpectedDpcCount);
76 trace("Dpc = %p\n", &Dpc);
77 memset(&Dpc, 0x55, sizeof Dpc);
78 KeInitializeDpc(&Dpc, DpcHandler, &Dpc);
79 /* check the Dpc object's fields */
80 ok_eq_uint(Dpc.Type, DpcObject);
81 ok_eq_uint(Dpc.Importance, DpcImportance);
82 ok_eq_uint(Dpc.Number, 0);
83 ok_eq_pointer(Dpc.DpcListEntry.Flink, (LIST_ENTRY *)0x5555555555555555LL);
84 ok_eq_pointer(Dpc.DpcListEntry.Blink, (LIST_ENTRY *)0x5555555555555555LL);
85 ok_eq_pointer(Dpc.DeferredRoutine, DpcHandler);
86 ok_eq_pointer(Dpc.DeferredContext, &Dpc);
87 ok_eq_pointer(Dpc.SystemArgument1, (PVOID)0x5555555555555555LL);
88 ok_eq_pointer(Dpc.SystemArgument2, (PVOID)0x5555555555555555LL);
89 ok_eq_pointer(Dpc.DpcData, NULL);
90
91 /* simply run the Dpc a few times */
92 for (i = 0; i < 5; ++i)
93 {
94 ok_dpccount();
95 Ret = KeInsertQueueDpc(&Dpc, (PVOID)0xabc123, (PVOID)0x5678);
96 ok_bool_true(Ret, "KeInsertQueueDpc returned");
97 ++ExpectedDpcCount;
98 ok_dpccount();
99 }
100
101 /* insert into queue at high irql
102 * -> should only run when lowered to APC_LEVEL,
103 * inserting a second time should fail
104 */
105 KeRaiseIrql(APC_LEVEL, &Irql);
106 for (i = 0; i < 5; ++i)
107 {
108 KeRaiseIrql(DISPATCH_LEVEL, &Irql2);
109 ok_dpccount();
110 Ret = KeInsertQueueDpc(&Dpc, (PVOID)0xabc123, (PVOID)0x5678);
111 ok_bool_true(Ret, "KeInsertQueueDpc returned");
112 Ret = KeInsertQueueDpc(&Dpc, (PVOID)0xdef, (PVOID)0x123);
113 ok_bool_false(Ret, "KeInsertQueueDpc returned");
114 ok_dpccount();
115 KeRaiseIrql(HIGH_LEVEL, &Irql3);
116 ok_dpccount();
117 KeLowerIrql(Irql3);
118 ok_dpccount();
119 KeLowerIrql(Irql2);
120 ++ExpectedDpcCount;
121 ok_dpccount();
122 }
123 KeLowerIrql(Irql);
124
125 /* now test removing from the queue */
126 KeRaiseIrql(APC_LEVEL, &Irql);
127 for (i = 0; i < 5; ++i)
128 {
129 KeRaiseIrql(DISPATCH_LEVEL, &Irql2);
130 ok_dpccount();
131 Ret = KeRemoveQueueDpc(&Dpc);
132 ok_bool_false(Ret, "KeRemoveQueueDpc returned");
133 Ret = KeInsertQueueDpc(&Dpc, (PVOID)0xabc123, (PVOID)0x5678);
134 ok_bool_true(Ret, "KeInsertQueueDpc returned");
135 ok_dpccount();
136 KeRaiseIrql(HIGH_LEVEL, &Irql3);
137 ok_dpccount();
138 KeLowerIrql(Irql3);
139 ok_dpccount();
140 Ret = KeRemoveQueueDpc(&Dpc);
141 ok_bool_true(Ret, "KeRemoveQueueDpc returned");
142 KeLowerIrql(Irql2);
143 ok_dpccount();
144 }
145 KeLowerIrql(Irql);
146
147 /* parameter checks */
148 Status = STATUS_SUCCESS;
149 _SEH2_TRY {
150 KeInitializeDpc(&Dpc, NULL, NULL);
151 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
152 Status = _SEH2_GetExceptionCode();
153 } _SEH2_END;
154 ok_eq_hex(Status, STATUS_SUCCESS);
155
156 if (!skip(Status == STATUS_SUCCESS, "KeInitializeDpc failed\n"))
157 {
158 KeRaiseIrql(HIGH_LEVEL, &Irql);
159 Ret = KeInsertQueueDpc(&Dpc, NULL, NULL);
160 ok_bool_true(Ret, "KeInsertQueueDpc returned");
161 Ret = KeRemoveQueueDpc(&Dpc);
162 ok_bool_true(Ret, "KeRemoveQueueDpc returned");
163 KeLowerIrql(Irql);
164 }
165
166 Status = STATUS_SUCCESS;
167 _SEH2_TRY {
168 KeInitializeDpc(NULL, NULL, NULL);
169 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
170 Status = _SEH2_GetExceptionCode();
171 } _SEH2_END;
172 ok_eq_hex(Status, STATUS_ACCESS_VIOLATION);
173
174 /* These result in IRQL_NOT_LESS_OR_EQUAL on 2k3 -- IRQLs 0x1f and 0xff (?)
175 Ret = KeInsertQueueDpc(NULL, NULL, NULL);
176 Ret = KeRemoveQueueDpc(NULL);*/
177
178 ok_dpccount();
179 ok_irql(PASSIVE_LEVEL);
180 trace("Final Dpc count: %ld, expected %ld\n", DpcCount, ExpectedDpcCount);
181 }