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 <thomas.faber@reactos.org>
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
DpcHandler(IN PRKDPC Dpc,IN PVOID DeferredContext,IN PVOID SystemArgument1,IN PVOID SystemArgument2)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
START_TEST(KeDpc)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 }
182