Fixed STDCALL issues in Ke functions
[reactos.git] / reactos / ntoskrnl / ke / apc.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ke/apc.c
5 * PURPOSE: Possible implementation of APCs
6 * PROGRAMMER: David Welch (welch@cwcom.net)
7 * UPDATE HISTORY:
8 * Created 22/05/98
9 * 12/11/99: Phillip Susi: Reworked the APC code
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <string.h>
16 #include <internal/string.h>
17 #include <internal/i386/segment.h>
18 #include <internal/ps.h>
19 #include <internal/ke.h>
20
21 #define NDEBUG
22 #include <internal/debug.h>
23
24 /* GLOBALS *******************************************************************/
25
26 static KSPIN_LOCK PiApcLock;
27
28 /* FUNCTIONS *****************************************************************/
29
30 VOID KeCallKernelRoutineApc(PKAPC Apc)
31 /*
32 * FUNCTION: Call the kernel routine for an APC
33 */
34 {
35 DPRINT("KeCallKernelRoutineApc(Apc %x)\n",Apc);
36
37 Apc->KernelRoutine(Apc,
38 &Apc->NormalRoutine,
39 &Apc->NormalContext,
40 &Apc->SystemArgument1,
41 &Apc->SystemArgument2);
42 DPRINT("Finished KeCallKernelRoutineApc()\n");
43 }
44
45 BOOLEAN KiTestAlert(PKTHREAD Thread,
46 PCONTEXT UserContext)
47 /*
48 * FUNCTION: Tests whether there are any pending APCs for the current thread
49 * and if so the APCs will be delivered on exit from kernel mode.
50 * ARGUMENTS:
51 * Thread = Thread to test for alerts
52 * UserContext = The user context saved on entry to kernel mode
53 */
54 {
55 PLIST_ENTRY current_entry;
56 PKAPC Apc;
57 PULONG Esp;
58 KIRQL oldlvl;
59 CONTEXT SavedContext;
60 ULONG Top;
61
62 DPRINT("KiTestAlert(Thread %x, UserContext %x)\n");
63 KeAcquireSpinLock(&PiApcLock, &oldlvl);
64 current_entry = Thread->ApcState.ApcListHead[1].Flink;
65
66 if (current_entry == &Thread->ApcState.ApcListHead[1])
67 {
68 KeReleaseSpinLock(&PiApcLock, oldlvl);
69 return(FALSE);
70 }
71
72 current_entry = RemoveHeadList(&Thread->ApcState.ApcListHead[1]);
73 Apc = CONTAINING_RECORD(current_entry, KAPC, ApcListEntry);
74
75 DPRINT("Esp %x\n", Esp);
76 DPRINT("Apc->NormalContext %x\n", Apc->NormalContext);
77 DPRINT("Apc->SystemArgument1 %x\n", Apc->SystemArgument1);
78 DPRINT("Apc->SystemArgument2 %x\n", Apc->SystemArgument2);
79 DPRINT("UserContext->Eip %x\n", UserContext->Eip);
80
81 Esp = (PULONG)UserContext->Esp;
82
83 memcpy(&SavedContext, UserContext, sizeof(CONTEXT));
84
85 /*
86 * Now call for the kernel routine for the APC, which will free
87 * the APC data structure
88 */
89 KeCallKernelRoutineApc(Apc);
90
91 Esp = Esp - (sizeof(CONTEXT) + (4 * sizeof(ULONG)));
92 memcpy(Esp, &SavedContext, sizeof(CONTEXT));
93 Top = sizeof(CONTEXT) / 4;
94 Esp[Top] = (ULONG)Apc->SystemArgument2;
95 Esp[Top + 1] = (ULONG)Apc->SystemArgument1;
96 Esp[Top + 2] = (ULONG)Apc->NormalContext;
97 Esp[Top + 3] = (ULONG)Apc->NormalRoutine;
98 UserContext->Eip = 0;
99
100 current_entry = current_entry->Flink;
101
102
103 return(TRUE);
104 }
105
106 VOID KeCallApcsThread(VOID)
107 {
108 PETHREAD Thread = PsGetCurrentThread();
109 PLIST_ENTRY current;
110 PKAPC Apc;
111 KIRQL oldlvl;
112
113 DPRINT("KeCallApcsThread()\n");
114 KeAcquireSpinLock(&PiApcLock, &oldlvl);
115 while(!IsListEmpty(&(Thread->Tcb.ApcState.ApcListHead[0])))
116 {
117 DPRINT("Delivering APC\n");
118 current = RemoveTailList(&(Thread->Tcb.ApcState.ApcListHead[0]));
119 Thread->Tcb.ApcState.KernelApcInProgress++;
120 Thread->Tcb.ApcState.KernelApcPending--;
121 KeReleaseSpinLock(&PiApcLock, oldlvl);
122
123 Apc = CONTAINING_RECORD(current, KAPC, ApcListEntry);
124 KeCallKernelRoutineApc(Apc);
125
126 KeAcquireSpinLock(&PiApcLock, &oldlvl);
127 DPRINT("Called kernel routine for APC\n");
128 // PsFreezeThread(Thread, NULL, FALSE, KernelMode);
129 DPRINT("Done frozen thread\n");
130 Thread->Tcb.ApcState.KernelApcInProgress--;
131 }
132 KeReleaseSpinLock(&PiApcLock, oldlvl);
133 // Thread->Tcb.WaitStatus = STATUS_KERNEL_APC;
134 }
135
136 VOID
137 STDCALL
138 KeInsertQueueApc (
139 PKAPC Apc,
140 PVOID SystemArgument1,
141 PVOID SystemArgument2,
142 UCHAR Mode
143 )
144 /*
145 * FUNCTION: Queues an APC for execution
146 * ARGUMENTS:
147 * Apc = APC to be queued
148 * SystemArgument[1-2] = TBD
149 * Mode = TBD
150 */
151 {
152 KIRQL oldlvl;
153 PKTHREAD TargetThread;
154
155 DPRINT("KeInsertQueueApc(Apc %x, SystemArgument1 %x, "
156 "SystemArgument2 %x, Mode %d)\n",Apc,SystemArgument1,
157 SystemArgument2,Mode);
158
159 KeAcquireSpinLock(&PiApcLock, &oldlvl);
160
161 Apc->SystemArgument1 = SystemArgument1;
162 Apc->SystemArgument2 = SystemArgument2;
163
164 if (Apc->Inserted)
165 {
166 DbgPrint("KeInsertQueueApc(): multiple APC insertations\n");
167 KeBugCheck(0);
168 }
169
170 TargetThread = Apc->Thread;
171 if (Apc->ApcMode == KernelMode)
172 {
173 InsertTailList(&TargetThread->ApcState.ApcListHead[0],
174 &Apc->ApcListEntry);
175 TargetThread->ApcState.KernelApcPending++;
176 }
177 else
178 {
179 InsertTailList(&TargetThread->ApcState.ApcListHead[1],
180 &Apc->ApcListEntry);
181 TargetThread->ApcState.KernelApcPending++;
182 TargetThread->ApcState.UserApcPending++;
183 }
184 Apc->Inserted = TRUE;
185
186 if (Apc->ApcMode == KernelMode && TargetThread->KernelApcDisable >= 1 &&
187 TargetThread->WaitIrql < APC_LEVEL)
188 {
189 KeRemoveAllWaitsThread(CONTAINING_RECORD(TargetThread, ETHREAD, Tcb),
190 STATUS_KERNEL_APC);
191 KeReleaseSpinLock(&PiApcLock, oldlvl);
192 }
193 if (Apc->ApcMode == UserMode && TargetThread->Alertable == TRUE &&
194 TargetThread->WaitMode == UserMode)
195 {
196 NTSTATUS Status;
197
198 DPRINT("Resuming thread for user APC\n");
199
200 Status = STATUS_USER_APC;
201 KeRemoveAllWaitsThread(CONTAINING_RECORD(TargetThread, ETHREAD, Tcb),
202 STATUS_USER_APC);
203 KeReleaseSpinLock(&PiApcLock, oldlvl);
204 }
205 }
206
207 VOID
208 STDCALL
209 KeInitializeApc (
210 PKAPC Apc,
211 PKTHREAD Thread,
212 UCHAR StateIndex,
213 PKKERNEL_ROUTINE KernelRoutine,
214 PKRUNDOWN_ROUTINE RundownRoutine,
215 PKNORMAL_ROUTINE NormalRoutine,
216 UCHAR Mode,
217 PVOID Context
218 )
219 /*
220 * FUNCTION: Initialize an APC object
221 * ARGUMENTS:
222 * Apc = Pointer to the APC object to initialized
223 * Thread = Thread the APC is to be delivered to
224 * StateIndex = TBD
225 * KernelRoutine = Routine to be called for a kernel-mode APC
226 * RundownRoutine = Routine to be called if the thread has exited with
227 * the APC being executed
228 * NormalRoutine = Routine to be called for a user-mode APC
229 * Mode = APC mode
230 * Context = Parameter to be passed to the APC routine
231 */
232 {
233 DPRINT("KeInitializeApc(Apc %x, Thread %x, StateIndex %d, "
234 "KernelRoutine %x, RundownRoutine %x, NormalRoutine %x, Mode %d, "
235 "Context %x)\n",Apc,Thread,StateIndex,KernelRoutine,RundownRoutine,
236 NormalRoutine,Mode,Context);
237 memset(Apc, 0, sizeof(KAPC));
238 Apc->Thread = Thread;
239 Apc->ApcListEntry.Flink = NULL;
240 Apc->ApcListEntry.Blink = NULL;
241 Apc->KernelRoutine = KernelRoutine;
242 Apc->RundownRoutine = RundownRoutine;
243 Apc->NormalRoutine = NormalRoutine;
244 Apc->NormalContext = Context;
245 Apc->Inserted = FALSE;
246 Apc->ApcStateIndex = StateIndex;
247 if (Apc->NormalRoutine != NULL)
248 {
249 Apc->ApcMode = Mode;
250 }
251 else
252 {
253 Apc->ApcMode = KernelMode;
254 }
255 }
256
257
258 NTSTATUS STDCALL NtQueueApcThread(HANDLE ThreadHandle,
259 PKNORMAL_ROUTINE ApcRoutine,
260 PVOID NormalContext,
261 PVOID SystemArgument1,
262 PVOID SystemArgument2)
263 {
264 PKAPC Apc;
265 PETHREAD Thread;
266 NTSTATUS Status;
267
268 Status = ObReferenceObjectByHandle(ThreadHandle,
269 THREAD_ALL_ACCESS, /* FIXME */
270 PsThreadType,
271 UserMode,
272 (PVOID*)&Thread,
273 NULL);
274 if (!NT_SUCCESS(Status))
275 {
276 return(Status);
277 }
278
279 Apc = ExAllocatePool(NonPagedPool, sizeof(KAPC));
280 if (Apc == NULL)
281 {
282 ObDereferenceObject(Thread);
283 return(STATUS_NO_MEMORY);
284 }
285
286 KeInitializeApc(Apc,
287 &Thread->Tcb,
288 0,
289 NULL,
290 NULL,
291 ApcRoutine,
292 UserMode,
293 NormalContext);
294 KeInsertQueueApc(Apc,
295 SystemArgument1,
296 SystemArgument2,
297 UserMode);
298
299 ObDereferenceObject(Thread);
300 return(STATUS_SUCCESS);
301 }
302
303
304 NTSTATUS STDCALL NtTestAlert(VOID)
305 {
306 KiTestAlert(KeGetCurrentThread(),NULL);
307 return(STATUS_SUCCESS);
308 }
309
310 VOID PiInitApcManagement(VOID)
311 {
312 KeInitializeSpinLock(&PiApcLock);
313 }
314