mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
Rewrote APC Implementation.
TODO: KiSwapApcEnvironment, Honour SpecialApcDisable. Special thanks to Thomas and Filip. Fixed I/O Manager Bugs. APCs were not created with the right parameters in the right places, or had useless parameters being sent. Added mmdrv and midimap to bootcd. Fixed KTHREAD defintion. Fixed some thread alertability issue in thread creation. svn path=/trunk/; revision=11610
This commit is contained in:
parent
8b3a000e7b
commit
39a5847ee5
16 changed files with 530 additions and 523 deletions
|
@ -83,6 +83,8 @@ lib\kbduk\kbduk.dll 1
|
|||
lib\kbdus\kbdus.dll 1
|
||||
lib\kernel32\kernel32.dll 1
|
||||
lib\lzexpand\lz32.dll 1
|
||||
lib\midimap\midimap.dll 1
|
||||
lib\mmdrv\mmdrv.dll 1
|
||||
lib\mpr\mpr.dll 1
|
||||
lib\msafd\msafd.dll 1
|
||||
lib\msgina\msgina.dll 1
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Id: irql.c,v 1.19 2004/11/01 14:37:19 hbirr Exp $
|
||||
/* $Id: irql.c,v 1.20 2004/11/10 02:50:59 ion Exp $
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
|
@ -188,7 +188,7 @@ HalpLowerIrql(KIRQL NewIrql)
|
|||
if (KeGetCurrentThread() != NULL &&
|
||||
KeGetCurrentThread()->ApcState.KernelApcPending)
|
||||
{
|
||||
KiDeliverApc(0, 0, 0);
|
||||
KiDeliverApc(KernelMode, NULL, NULL);
|
||||
}
|
||||
KeGetCurrentKPCR()->Irql = PASSIVE_LEVEL;
|
||||
}
|
||||
|
|
|
@ -530,10 +530,6 @@ KfReleaseSpinLock (
|
|||
);
|
||||
|
||||
|
||||
VOID STDCALL KiDeliverApc(ULONG Unknown1,
|
||||
ULONG Unknown2,
|
||||
ULONG Unknown3);
|
||||
|
||||
VOID STDCALL KiDispatchInterrupt(VOID);
|
||||
|
||||
/* Stubs Start here */
|
||||
|
|
|
@ -36,7 +36,23 @@ typedef VOID STDCALL_FUNC
|
|||
|
||||
struct _DISPATCHER_HEADER;
|
||||
|
||||
|
||||
typedef enum _KERNEL_OBJECTS {
|
||||
KNotificationEvent = 0,
|
||||
KSynchronizationEvent = 1,
|
||||
KMutant = 2,
|
||||
KProcess = 3,
|
||||
KQueue = 4,
|
||||
KSemaphore = 5,
|
||||
KThread = 6,
|
||||
KNotificationTimer = 8,
|
||||
KSynchronizationTimer = 9,
|
||||
KApc = 18,
|
||||
KDpc = 19,
|
||||
KDeviceQueue = 20,
|
||||
KEventPair = 21,
|
||||
KInterrupt = 22,
|
||||
KProfile = 23
|
||||
} KERNEL_OBJECTS;
|
||||
|
||||
#include <pshpack1.h>
|
||||
|
||||
|
@ -84,7 +100,7 @@ typedef struct _KDEVICE_QUEUE
|
|||
} KDEVICE_QUEUE, *PKDEVICE_QUEUE;
|
||||
|
||||
|
||||
#include <pshpack1.h>
|
||||
#include <pshpack2.h>
|
||||
|
||||
typedef struct _KAPC
|
||||
{
|
||||
|
@ -101,7 +117,7 @@ typedef struct _KAPC
|
|||
PVOID SystemArgument2;
|
||||
CCHAR ApcStateIndex;
|
||||
KPROCESSOR_MODE ApcMode;
|
||||
USHORT Inserted;
|
||||
BOOLEAN Inserted;
|
||||
} KAPC, *PKAPC;
|
||||
|
||||
#include <poppack.h>
|
||||
|
|
|
@ -85,8 +85,20 @@ BOOLEAN KiTestAlert(VOID);
|
|||
VOID KeRemoveAllWaitsThread(struct _ETHREAD* Thread, NTSTATUS WaitStatus, BOOL Unblock);
|
||||
PULONG KeGetStackTopThread(struct _ETHREAD* Thread);
|
||||
VOID KeContextToTrapFrame(PCONTEXT Context, PKTRAP_FRAME TrapFrame);
|
||||
VOID
|
||||
KiDeliverNormalApc(VOID);
|
||||
VOID STDCALL KiDeliverApc(KPROCESSOR_MODE PreviousMode,
|
||||
PVOID Reserved,
|
||||
PKTRAP_FRAME TrapFrame);
|
||||
|
||||
VOID KiInitializeUserApc(IN PVOID Reserved,
|
||||
IN PKTRAP_FRAME TrapFrame,
|
||||
IN PKNORMAL_ROUTINE NormalRoutine,
|
||||
IN PVOID NormalContext,
|
||||
IN PVOID SystemArgument1,
|
||||
IN PVOID SystemArgument2);
|
||||
|
||||
BOOLEAN
|
||||
STDCALL
|
||||
KeTestAlertThread(IN KPROCESSOR_MODE AlertMode);
|
||||
|
||||
BOOLEAN STDCALL KeRemoveQueueApc (PKAPC Apc);
|
||||
PLIST_ENTRY STDCALL KeRundownQueue(IN PKQUEUE Queue);
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/* $Id: ps.h,v 1.72 2004/10/30 23:48:56 navaraf Exp $
|
||||
/* $Id: ps.h,v 1.73 2004/11/10 02:50:59 ion Exp $
|
||||
*
|
||||
* FILE: ntoskrnl/ke/kthread.c
|
||||
* PURPOSE: Process manager definitions
|
||||
|
@ -179,9 +179,11 @@ typedef struct
|
|||
typedef struct _ETHREAD
|
||||
{
|
||||
KTHREAD Tcb;
|
||||
TIME CreateTime;
|
||||
USHORT NestedFaultCount;
|
||||
UCHAR ApcNeeded;
|
||||
union {
|
||||
TIME CreateTime;
|
||||
UCHAR NestedFaultCount:2;
|
||||
UCHAR ApcNeeded:1;
|
||||
};
|
||||
TIME ExitTime;
|
||||
LIST_ENTRY LpcReplyChain;
|
||||
NTSTATUS ExitStatus;
|
||||
|
@ -476,6 +478,11 @@ NTSTATUS PsOpenTokenOfProcess(HANDLE ProcessHandle,
|
|||
NTSTATUS PsSuspendThread(PETHREAD Thread, PULONG PreviousCount);
|
||||
NTSTATUS PsResumeThread(PETHREAD Thread, PULONG PreviousCount);
|
||||
|
||||
VOID STDCALL PsExitSpecialApc(PKAPC Apc,
|
||||
PKNORMAL_ROUTINE *NormalRoutine,
|
||||
PVOID *NormalContext,
|
||||
PVOID *SystemArgument1,
|
||||
PVOID *SystemArgument2);
|
||||
|
||||
#define THREAD_STATE_INITIALIZED (0)
|
||||
#define THREAD_STATE_READY (1)
|
||||
|
|
|
@ -166,11 +166,14 @@ IoSecondStageCompletion(
|
|||
PDEVICE_OBJECT DeviceObject;
|
||||
PFILE_OBJECT OriginalFileObject;
|
||||
PIRP Irp;
|
||||
CCHAR PriorityBoost;
|
||||
|
||||
OriginalFileObject = (PFILE_OBJECT)(*NormalContext);
|
||||
Irp = (PIRP)(*SystemArgument1);
|
||||
PriorityBoost = (CCHAR)(LONG)(*SystemArgument2);
|
||||
if (Apc) DPRINT("IoSecondStageCompletition with APC: %x\n", Apc);
|
||||
|
||||
OriginalFileObject = (PFILE_OBJECT)(*SystemArgument1);
|
||||
DPRINT("OriginalFileObject: %x\n", OriginalFileObject);
|
||||
|
||||
Irp = CONTAINING_RECORD(Apc, IRP, Tail.Apc);
|
||||
DPRINT("Irp: %x\n", Irp);
|
||||
|
||||
/*
|
||||
* Note that we'll never see irp's flagged IRP_PAGING_IO (IRP_MOUNT_OPERATION)
|
||||
|
@ -190,11 +193,10 @@ IoSecondStageCompletion(
|
|||
InitializeListHead(&Irp->ThreadListEntry);
|
||||
}
|
||||
|
||||
DPRINT("Tail Value %x, Irp Value %x\n", Irp->Tail.Overlay.CurrentStackLocation - (PIO_STACK_LOCATION)(Irp+1), Irp->CurrentLocation);
|
||||
IoStack = (PIO_STACK_LOCATION)(Irp+1) + Irp->CurrentLocation;
|
||||
DeviceObject = IoStack->DeviceObject;
|
||||
|
||||
DPRINT("IoSecondStageCompletion(Irp %x, PriorityBoost %d)\n", Irp, PriorityBoost);
|
||||
DPRINT("IoSecondStageCompletion(Irp %x, PriorityBoost %d, MajorFunction %x)\n", Irp, PriorityBoost, IoStack->MajorFunction);
|
||||
|
||||
switch (IoStack->MajorFunction)
|
||||
{
|
||||
|
@ -240,7 +242,7 @@ IoSecondStageCompletion(
|
|||
|
||||
if (Irp->UserEvent)
|
||||
{
|
||||
KeSetEvent(Irp->UserEvent,PriorityBoost,FALSE);
|
||||
KeSetEvent(Irp->UserEvent,0,FALSE);
|
||||
}
|
||||
|
||||
//Windows NT File System Internals, page 169
|
||||
|
@ -248,11 +250,11 @@ IoSecondStageCompletion(
|
|||
{
|
||||
if (Irp->UserEvent == NULL)
|
||||
{
|
||||
KeSetEvent(&OriginalFileObject->Event,PriorityBoost,FALSE);
|
||||
KeSetEvent(&OriginalFileObject->Event,0,FALSE);
|
||||
}
|
||||
else if (OriginalFileObject->Flags & FO_SYNCHRONOUS_IO && Irp->UserEvent != &OriginalFileObject->Event)
|
||||
{
|
||||
KeSetEvent(&OriginalFileObject->Event,PriorityBoost,FALSE);
|
||||
KeSetEvent(&OriginalFileObject->Event,0,FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -290,7 +292,7 @@ IoSecondStageCompletion(
|
|||
KeInsertQueueApc( &Irp->Tail.Apc,
|
||||
Irp->UserIosb,
|
||||
NULL,
|
||||
PriorityBoost);
|
||||
2);
|
||||
|
||||
//NOTE: kernel (or rundown) routine frees the IRP
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Id: irp.c,v 1.69 2004/10/31 22:21:41 ion Exp $
|
||||
/* $Id: irp.c,v 1.70 2004/11/10 02:50:59 ion Exp $
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
|
@ -308,11 +308,8 @@ IofCompleteRequest(PIRP Irp,
|
|||
ASSERT(Irp->CancelRoutine == NULL);
|
||||
ASSERT(Irp->IoStatus.Status != STATUS_PENDING);
|
||||
|
||||
if (IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED)
|
||||
{
|
||||
Irp->PendingReturned = TRUE;
|
||||
}
|
||||
|
||||
Irp->PendingReturned = IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED;
|
||||
|
||||
/*
|
||||
* Run the completion routines.
|
||||
*/
|
||||
|
@ -455,6 +452,7 @@ IofCompleteRequest(PIRP Irp,
|
|||
BOOLEAN bStatus;
|
||||
|
||||
DPRINT("Dispatching APC\n");
|
||||
|
||||
KeInitializeApc( &Irp->Tail.Apc,
|
||||
&Irp->Tail.Overlay.Thread->Tcb,
|
||||
Irp->ApcEnvironment,
|
||||
|
@ -462,11 +460,11 @@ IofCompleteRequest(PIRP Irp,
|
|||
NULL,
|
||||
(PKNORMAL_ROUTINE) NULL,
|
||||
KernelMode,
|
||||
OriginalFileObject);
|
||||
NULL);
|
||||
|
||||
bStatus = KeInsertQueueApc(&Irp->Tail.Apc,
|
||||
(PVOID)Irp,
|
||||
(PVOID)(ULONG)PriorityBoost,
|
||||
(PVOID)OriginalFileObject,
|
||||
NULL, // This is used for REPARSE stuff
|
||||
PriorityBoost);
|
||||
|
||||
if (bStatus == FALSE)
|
||||
|
@ -480,7 +478,7 @@ IofCompleteRequest(PIRP Irp,
|
|||
{
|
||||
DPRINT("Calling IoSecondStageCompletion routine directly\n");
|
||||
KeRaiseIrql(APC_LEVEL, &oldIrql);
|
||||
IoSecondStageCompletion(NULL,NULL,(PVOID)&OriginalFileObject,(PVOID) &Irp,(PVOID) &PriorityBoost);
|
||||
IoSecondStageCompletion(&Irp->Tail.Apc,NULL,NULL,(PVOID)&OriginalFileObject, NULL);
|
||||
KeLowerIrql(oldIrql);
|
||||
DPRINT("Finished completition routine\n");
|
||||
}
|
||||
|
|
|
@ -41,267 +41,71 @@ VOID PsTerminateCurrentThread(NTSTATUS ExitStatus);
|
|||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
VOID
|
||||
STDCALL
|
||||
KeInitializeApc(
|
||||
IN PKAPC Apc,
|
||||
IN PKTHREAD Thread,
|
||||
IN KAPC_ENVIRONMENT TargetEnvironment,
|
||||
IN PKKERNEL_ROUTINE KernelRoutine,
|
||||
IN PKRUNDOWN_ROUTINE RundownRoutine OPTIONAL,
|
||||
IN PKNORMAL_ROUTINE NormalRoutine,
|
||||
IN KPROCESSOR_MODE Mode,
|
||||
IN PVOID Context)
|
||||
/*
|
||||
* FUNCTION: Initialize an APC object
|
||||
* ARGUMENTS:
|
||||
* Apc = Pointer to the APC object to initialized
|
||||
* Thread = Thread the APC is to be delivered to
|
||||
* TargetEnvironment = APC environment to use
|
||||
* KernelRoutine = Routine to be called for a kernel-mode APC
|
||||
* RundownRoutine = Routine to be called if the thread has exited with
|
||||
* the APC being executed
|
||||
* NormalRoutine = Routine to be called for a user-mode APC
|
||||
* Mode = APC mode
|
||||
* Context = Parameter to be passed to the APC routine
|
||||
*/
|
||||
{
|
||||
DPRINT ("KeInitializeApc(Apc %x, Thread %x, Environment %d, "
|
||||
"KernelRoutine %x, RundownRoutine %x, NormalRoutine %x, Mode %d, "
|
||||
"Context %x)\n",Apc,Thread,TargetEnvironment,KernelRoutine,RundownRoutine,
|
||||
NormalRoutine,Mode,Context);
|
||||
|
||||
/* Set up the basic APC Structure Data */
|
||||
RtlZeroMemory(Apc, sizeof(KAPC));
|
||||
Apc->Type = KApc;
|
||||
Apc->Size = sizeof(KAPC);
|
||||
|
||||
/* Set the Environment */
|
||||
if (TargetEnvironment == CurrentApcEnvironment) {
|
||||
Apc->ApcStateIndex = Thread->ApcStateIndex;
|
||||
} else {
|
||||
Apc->ApcStateIndex = TargetEnvironment;
|
||||
}
|
||||
|
||||
/* Set the Thread and Routines */
|
||||
Apc->Thread = Thread;
|
||||
Apc->KernelRoutine = KernelRoutine;
|
||||
Apc->RundownRoutine = RundownRoutine;
|
||||
Apc->NormalRoutine = NormalRoutine;
|
||||
|
||||
/* Check if this is a Special APC, in which case we use KernelMode and no Context */
|
||||
if (ARGUMENT_PRESENT(NormalRoutine)) {
|
||||
Apc->ApcMode = Mode;
|
||||
Apc->NormalContext = Context;
|
||||
} else {
|
||||
Apc->ApcMode = KernelMode;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
BOOLEAN
|
||||
STDCALL
|
||||
KeAreApcsDisabled(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return KeGetCurrentThread()->KernelApcDisable ? FALSE : TRUE;
|
||||
}
|
||||
|
||||
VOID KiRundownThread(VOID)
|
||||
/*
|
||||
* FUNCTION:
|
||||
*/
|
||||
{
|
||||
}
|
||||
|
||||
BOOLEAN KiTestAlert(VOID)
|
||||
/*
|
||||
* FUNCTION: Tests whether there are any pending APCs for the current thread
|
||||
* and if so the APCs will be delivered on exit from kernel mode
|
||||
*/
|
||||
{
|
||||
KIRQL oldIrql;
|
||||
|
||||
oldIrql = KeRaiseIrqlToDpcLevel();
|
||||
if (KeGetCurrentThread()->ApcState.UserApcPending == 0)
|
||||
{
|
||||
KeLowerIrql(oldIrql);
|
||||
return(FALSE);
|
||||
}
|
||||
KeGetCurrentThread()->Alerted[0] = 1;
|
||||
KeLowerIrql(oldIrql);
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
VOID
|
||||
KiDeliverNormalApc(VOID)
|
||||
{
|
||||
PETHREAD Thread = PsGetCurrentThread();
|
||||
PLIST_ENTRY current;
|
||||
PKAPC Apc;
|
||||
KIRQL oldlvl;
|
||||
PKNORMAL_ROUTINE NormalRoutine;
|
||||
PVOID NormalContext;
|
||||
PVOID SystemArgument1;
|
||||
PVOID SystemArgument2;
|
||||
|
||||
oldlvl = KeRaiseIrqlToDpcLevel();
|
||||
while(!IsListEmpty(&(Thread->Tcb.ApcState.ApcListHead[0])))
|
||||
{
|
||||
current = RemoveTailList(&Thread->Tcb.ApcState.ApcListHead[0]);
|
||||
Apc = CONTAINING_RECORD(current, KAPC, ApcListEntry);
|
||||
if (Apc->NormalRoutine == NULL)
|
||||
{
|
||||
DbgPrint("Exiting kernel with kernel APCs pending.\n");
|
||||
KEBUGCHECKEX(KERNEL_APC_PENDING_DURING_EXIT, (ULONG)Apc,
|
||||
Thread->Tcb.KernelApcDisable, oldlvl, 0);
|
||||
}
|
||||
Apc->Inserted = FALSE;
|
||||
Thread->Tcb.ApcState.KernelApcInProgress++;
|
||||
Thread->Tcb.ApcState.KernelApcPending--;
|
||||
|
||||
KeLowerIrql(oldlvl);
|
||||
|
||||
ASSERT(Apc->KernelRoutine);
|
||||
|
||||
NormalRoutine = Apc->NormalRoutine;
|
||||
NormalContext = Apc->NormalContext;
|
||||
SystemArgument1 = Apc->SystemArgument1;
|
||||
SystemArgument2 = Apc->SystemArgument2;
|
||||
Apc->KernelRoutine(Apc,
|
||||
&NormalRoutine,
|
||||
&NormalContext,
|
||||
&SystemArgument1,
|
||||
&SystemArgument2);
|
||||
NormalRoutine(NormalContext, SystemArgument1, SystemArgument2);
|
||||
|
||||
oldlvl = KeRaiseIrqlToDpcLevel();
|
||||
Thread->Tcb.ApcState.KernelApcInProgress--;
|
||||
}
|
||||
KeLowerIrql(oldlvl);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
KiDeliverUserApc(PKTRAP_FRAME TrapFrame)
|
||||
/*
|
||||
* FUNCTION: Tests whether there are any pending APCs for the current thread
|
||||
* and if so the APCs will be delivered on exit from kernel mode.
|
||||
* ARGUMENTS:
|
||||
* Thread = Thread to test for alerts
|
||||
* UserContext = The user context saved on entry to kernel mode
|
||||
*/
|
||||
{
|
||||
PLIST_ENTRY current_entry;
|
||||
PKAPC Apc;
|
||||
PULONG Esp;
|
||||
PCONTEXT Context;
|
||||
KIRQL oldlvl;
|
||||
PKTHREAD Thread;
|
||||
|
||||
DPRINT("KiDeliverUserApc(TrapFrame %x/%x)\n", TrapFrame,
|
||||
KeGetCurrentThread()->TrapFrame);
|
||||
Thread = KeGetCurrentThread();
|
||||
|
||||
/*
|
||||
* Check for thread termination
|
||||
*/
|
||||
|
||||
oldlvl = KeRaiseIrqlToDpcLevel();
|
||||
|
||||
current_entry = Thread->ApcState.ApcListHead[1].Flink;
|
||||
|
||||
/*
|
||||
* Shouldn't happen but check anyway.
|
||||
*/
|
||||
if (current_entry == &Thread->ApcState.ApcListHead[1])
|
||||
{
|
||||
KeLowerIrql(oldlvl);
|
||||
DbgPrint("KiDeliverUserApc called but no APC was pending\n");
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
while (!IsListEmpty(&Thread->ApcState.ApcListHead[1]))
|
||||
{
|
||||
current_entry = RemoveHeadList(&Thread->ApcState.ApcListHead[1]);
|
||||
Apc = CONTAINING_RECORD(current_entry, KAPC, ApcListEntry);
|
||||
Apc->Inserted = FALSE;
|
||||
|
||||
/*
|
||||
* We've dealt with one pending user-mode APC
|
||||
*/
|
||||
Thread->ApcState.UserApcPending--;
|
||||
KeLowerIrql(oldlvl);
|
||||
|
||||
/*
|
||||
* Save the thread's current context (in other words the registers
|
||||
* that will be restored when it returns to user mode) so the
|
||||
* APC dispatcher can restore them later
|
||||
*/
|
||||
Context = (PCONTEXT)(((PUCHAR)TrapFrame->Esp) - sizeof(CONTEXT));
|
||||
memset(Context, 0, sizeof(CONTEXT));
|
||||
Context->ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER |
|
||||
CONTEXT_SEGMENTS | CONTEXT_i386;
|
||||
Context->SegGs = TrapFrame->Gs;
|
||||
Context->SegFs = TrapFrame->Fs;
|
||||
Context->SegEs = TrapFrame->Es;
|
||||
Context->SegDs = TrapFrame->Ds;
|
||||
Context->Edi = TrapFrame->Edi;
|
||||
Context->Esi = TrapFrame->Esi;
|
||||
Context->Ebx = TrapFrame->Ebx;
|
||||
Context->Edx = TrapFrame->Edx;
|
||||
Context->Ecx = TrapFrame->Ecx;
|
||||
Context->Eax = TrapFrame->Eax;
|
||||
Context->Ebp = TrapFrame->Ebp;
|
||||
Context->Eip = TrapFrame->Eip;
|
||||
Context->SegCs = TrapFrame->Cs;
|
||||
Context->EFlags = TrapFrame->Eflags;
|
||||
Context->Esp = TrapFrame->Esp;
|
||||
Context->SegSs = TrapFrame->Ss;
|
||||
|
||||
/*
|
||||
* Setup the trap frame so the thread will start executing at the
|
||||
* APC Dispatcher when it returns to user-mode
|
||||
*/
|
||||
Esp = (PULONG)(((PUCHAR)TrapFrame->Esp) -
|
||||
(sizeof(CONTEXT) + (6 * sizeof(ULONG))));
|
||||
|
||||
Esp[0] = 0xdeadbeef;
|
||||
Esp[1] = (ULONG)Apc->NormalRoutine;
|
||||
Esp[2] = (ULONG)Apc->NormalContext;
|
||||
Esp[3] = (ULONG)Apc->SystemArgument1;
|
||||
Esp[4] = (ULONG)Apc->SystemArgument2;
|
||||
Esp[5] = (ULONG)Context;
|
||||
TrapFrame->Eip = (ULONG)LdrpGetSystemDllApcDispatcher();
|
||||
TrapFrame->Esp = (ULONG)Esp;
|
||||
|
||||
|
||||
/*
|
||||
* Now call for the kernel routine for the APC, which will free
|
||||
* the APC data structure, we can't do this ourselves because
|
||||
* the APC may be embedded in some larger structure e.g. an IRP
|
||||
* We also give the kernel routine a last chance to modify the
|
||||
* arguments to the user APC routine.
|
||||
*/
|
||||
ASSERT(Apc->KernelRoutine);
|
||||
Apc->KernelRoutine(Apc,
|
||||
(PKNORMAL_ROUTINE*)&Esp[1],
|
||||
(PVOID*)&Esp[2],
|
||||
(PVOID*)&Esp[3],
|
||||
(PVOID*)&Esp[4]);
|
||||
|
||||
oldlvl = KeRaiseIrqlToDpcLevel();
|
||||
}
|
||||
Thread->Alerted[0] = 0;
|
||||
KeLowerIrql(oldlvl);
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
VOID STDCALL
|
||||
KiDeliverApc(ULONG Unknown1,
|
||||
ULONG Unknown2,
|
||||
ULONG Unknown3)
|
||||
/*
|
||||
* FUNCTION: Deliver an APC to the current thread.
|
||||
* NOTES: This is called from the IRQL switching code if the current thread
|
||||
* is returning from an IRQL greater than or equal to APC_LEVEL to
|
||||
* PASSIVE_LEVEL and there are kernel-mode APCs pending. This means any
|
||||
* pending APCs will be delivered after a thread gets a new quantum and
|
||||
* after it wakes from a wait.
|
||||
*/
|
||||
{
|
||||
PETHREAD Thread = PsGetCurrentThread();
|
||||
PLIST_ENTRY current_entry;
|
||||
PKAPC Apc;
|
||||
KIRQL oldlvl;
|
||||
|
||||
DPRINT("KiDeliverApc()\n");
|
||||
oldlvl = KeRaiseIrqlToDpcLevel();
|
||||
current_entry = Thread->Tcb.ApcState.ApcListHead[0].Flink;
|
||||
while(current_entry != &Thread->Tcb.ApcState.ApcListHead[0])
|
||||
{
|
||||
Apc = CONTAINING_RECORD(current_entry, KAPC, ApcListEntry);
|
||||
if (Apc->NormalRoutine == NULL)
|
||||
{
|
||||
Apc->Inserted = FALSE;
|
||||
RemoveEntryList(&Apc->ApcListEntry);
|
||||
Thread->Tcb.ApcState.KernelApcInProgress++;
|
||||
Thread->Tcb.ApcState.KernelApcPending--;
|
||||
|
||||
KeLowerIrql(oldlvl);
|
||||
|
||||
ASSERT(Apc->KernelRoutine);
|
||||
Apc->KernelRoutine(Apc,
|
||||
&Apc->NormalRoutine,
|
||||
&Apc->NormalContext,
|
||||
&Apc->SystemArgument1,
|
||||
&Apc->SystemArgument2);
|
||||
|
||||
oldlvl = KeRaiseIrqlToDpcLevel();
|
||||
Thread->Tcb.ApcState.KernelApcInProgress--;
|
||||
current_entry = Thread->Tcb.ApcState.ApcListHead[0].Flink;
|
||||
}
|
||||
else
|
||||
{
|
||||
current_entry = current_entry->Flink;
|
||||
}
|
||||
}
|
||||
KeLowerIrql(oldlvl);
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
BOOLEAN STDCALL
|
||||
KeInsertQueueApc (PKAPC Apc,
|
||||
PVOID SystemArgument1,
|
||||
PVOID SystemArgument2,
|
||||
|
@ -310,124 +114,102 @@ KeInsertQueueApc (PKAPC Apc,
|
|||
* FUNCTION: Queues an APC for execution
|
||||
* ARGUMENTS:
|
||||
* Apc = APC to be queued
|
||||
* SystemArgument[1-2] = TBD
|
||||
* Mode = TBD
|
||||
* SystemArgument[1-2] = Arguments we ignore and simply pass on.
|
||||
* PriorityBoost = Priority Boost to give to the Thread
|
||||
*/
|
||||
{
|
||||
//FIXME: return FALSE if APC can't be queued to target thread (thread has ended)
|
||||
KIRQL oldlvl;
|
||||
PKTHREAD TargetThread;
|
||||
KIRQL OldIrql;
|
||||
PKTHREAD Thread;
|
||||
PLIST_ENTRY ApcListEntry;
|
||||
PKAPC QueuedApc;
|
||||
|
||||
DPRINT("KeInsertQueueApc(Apc %x, SystemArgument1 %x, "
|
||||
"SystemArgument2 %x)\n",Apc,SystemArgument1,
|
||||
SystemArgument2);
|
||||
DPRINT ("KeInsertQueueApc(Apc %x, SystemArgument1 %x, "
|
||||
"SystemArgument2 %x)\n",Apc,SystemArgument1,
|
||||
SystemArgument2);
|
||||
|
||||
Apc->SystemArgument1 = SystemArgument1;
|
||||
Apc->SystemArgument2 = SystemArgument2;
|
||||
|
||||
if (Apc->Inserted)
|
||||
{
|
||||
#if 0
|
||||
/* TMN: This code is in error */
|
||||
DbgPrint("KeInsertQueueApc(): multiple APC insertations\n");
|
||||
KEBUGCHECK(0);
|
||||
#else
|
||||
return FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
oldlvl = KeRaiseIrqlToDpcLevel();
|
||||
|
||||
TargetThread = Apc->Thread;
|
||||
|
||||
if (TargetThread->State == THREAD_STATE_TERMINATED_1 ||
|
||||
TargetThread->State == THREAD_STATE_TERMINATED_2)
|
||||
{
|
||||
KeLowerIrql(oldlvl);
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
if (Apc->ApcMode == KernelMode)
|
||||
{
|
||||
InsertTailList(&TargetThread->ApcStatePointer[(int) Apc->ApcStateIndex]->ApcListHead[0],
|
||||
&Apc->ApcListEntry);
|
||||
TargetThread->ApcStatePointer[(int) Apc->ApcStateIndex]->KernelApcPending++;
|
||||
}
|
||||
else
|
||||
{
|
||||
InsertTailList(&TargetThread->ApcStatePointer[(int) Apc->ApcStateIndex]->ApcListHead[1],
|
||||
&Apc->ApcListEntry);
|
||||
TargetThread->ApcStatePointer[(int) Apc->ApcStateIndex]->UserApcPending++;
|
||||
}
|
||||
Apc->Inserted = TRUE;
|
||||
|
||||
/*
|
||||
* If this is a kernel-mode APC for the current thread and we are not
|
||||
* inside a critical section or at APC level then call it, in fact we
|
||||
* rely on the side effects of dropping the IRQL level when we release
|
||||
* the spinlock
|
||||
*/
|
||||
if (Apc->ApcMode == KernelMode && TargetThread == KeGetCurrentThread() &&
|
||||
Apc->NormalRoutine == NULL)
|
||||
{
|
||||
HalRequestSoftwareInterrupt(APC_LEVEL);
|
||||
KeLowerIrql(oldlvl);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is a kernel-mode APC and it is waiting at PASSIVE_LEVEL and
|
||||
* not inside a critical section then wake it up. Otherwise it will
|
||||
* execute the APC as soon as it returns to PASSIVE_LEVEL.
|
||||
* FIXME: If the thread is running on another processor then send an
|
||||
* IPI.
|
||||
* FIXME: Check if the thread is terminating.
|
||||
*/
|
||||
if (Apc->ApcMode == KernelMode && TargetThread->WaitIrql < APC_LEVEL &&
|
||||
Apc->NormalRoutine == NULL)
|
||||
{
|
||||
KeRemoveAllWaitsThread(CONTAINING_RECORD(TargetThread, ETHREAD, Tcb),
|
||||
STATUS_KERNEL_APC, TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is a 'funny' user-mode APC then mark the thread as
|
||||
* alerted so it will execute the APC on exit from kernel mode. If it
|
||||
* is waiting alertably then wake it up so it can return to user mode.
|
||||
*/
|
||||
if (Apc->ApcMode == KernelMode && Apc->NormalRoutine != NULL)
|
||||
{
|
||||
TargetThread->Alerted[1] = 1;
|
||||
if (TargetThread->Alertable == TRUE &&
|
||||
TargetThread->WaitMode == UserMode)
|
||||
{
|
||||
PETHREAD Thread;
|
||||
|
||||
Thread = CONTAINING_RECORD(TargetThread, ETHREAD, Tcb);
|
||||
KeRemoveAllWaitsThread(Thread, STATUS_USER_APC, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the thread is waiting alertably then wake it up and it will
|
||||
* return to to user-mode executing the APC in the process. Otherwise the
|
||||
* thread will execute the APC next time it enters an alertable wait.
|
||||
*/
|
||||
if (Apc->ApcMode == UserMode && TargetThread->Alertable == TRUE &&
|
||||
TargetThread->WaitMode == UserMode)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
/* FIXME: Implement Dispatcher Lock */
|
||||
OldIrql = KeRaiseIrqlToDpcLevel();
|
||||
|
||||
DPRINT("Resuming thread for user APC\n");
|
||||
/* Get the Thread specified in the APC */
|
||||
Thread = Apc->Thread;
|
||||
|
||||
/* Make sure the thread allows APC Queues */
|
||||
if (Thread->ApcQueueable == FALSE) {
|
||||
DPRINT("Thread doesn't allow APC Queues\n");
|
||||
KeLowerIrql(OldIrql);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Status = STATUS_USER_APC;
|
||||
TargetThread->Alerted[0] = 1;
|
||||
KeRemoveAllWaitsThread(CONTAINING_RECORD(TargetThread, ETHREAD, Tcb),
|
||||
STATUS_USER_APC, TRUE);
|
||||
}
|
||||
HalRequestSoftwareInterrupt(APC_LEVEL);
|
||||
KeLowerIrql(oldlvl);
|
||||
return TRUE;
|
||||
/* Set the System Arguments */
|
||||
Apc->SystemArgument1 = SystemArgument1;
|
||||
Apc->SystemArgument2 = SystemArgument2;
|
||||
|
||||
/* Don't do anything if the APC is already inserted */
|
||||
if (Apc->Inserted) {
|
||||
KeLowerIrql(OldIrql);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Three scenarios:
|
||||
1) Kernel APC with Normal Routine or User APC = Put it at the end of the List
|
||||
2) User APC which is PsExitSpecialApc = Put it at the front of the List
|
||||
3) Kernel APC without Normal Routine = Put it at the end of the No-Normal Routine Kernel APC list
|
||||
*/
|
||||
if ((Apc->ApcMode != KernelMode) && (Apc->KernelRoutine == (PKKERNEL_ROUTINE)PsExitSpecialApc)) {
|
||||
DPRINT ("Inserting the Process Exit APC into the Queue\n");
|
||||
Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->UserApcPending = TRUE;
|
||||
InsertHeadList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode],
|
||||
&Apc->ApcListEntry);
|
||||
} else if (Apc->NormalRoutine == NULL) {
|
||||
DPRINT ("Inserting Special APC %x into the Queue\n", Apc);
|
||||
for (ApcListEntry = Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode].Flink;
|
||||
ApcListEntry != &Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode];
|
||||
ApcListEntry = ApcListEntry->Flink) {
|
||||
|
||||
QueuedApc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry);
|
||||
if (Apc->NormalRoutine != NULL) break;
|
||||
}
|
||||
|
||||
/* We found the first "Normal" APC, so write right before it */
|
||||
ApcListEntry = ApcListEntry->Blink;
|
||||
InsertHeadList(ApcListEntry, &Apc->ApcListEntry);
|
||||
} else {
|
||||
DPRINT ("Inserting Normal APC %x into the %x Queue\n", Apc, Apc->ApcMode);
|
||||
InsertTailList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode],
|
||||
&Apc->ApcListEntry);
|
||||
}
|
||||
|
||||
/* Confirm Insertion */
|
||||
Apc->Inserted = TRUE;
|
||||
|
||||
/* Three possibilites here again:
|
||||
1) Kernel APC, The thread is Running: Request an Interrupt
|
||||
2) Kernel APC, The Thread is Waiting at PASSIVE_LEVEL and APCs are enabled and not in progress: Unwait the Thread
|
||||
3) User APC, Unwait the Thread if it is alertable
|
||||
*/
|
||||
if (Apc->ApcMode == KernelMode) {
|
||||
Thread->ApcState.KernelApcPending = TRUE;
|
||||
if (Thread->State == THREAD_STATE_RUNNING) {
|
||||
/* FIXME: Use IPI */
|
||||
DPRINT ("Requesting APC Interrupt for Running Thread \n");
|
||||
HalRequestSoftwareInterrupt(APC_LEVEL);
|
||||
} else if ((Thread->WaitIrql < APC_LEVEL) && (Apc->NormalRoutine == NULL)) {
|
||||
DPRINT ("Waking up Thread for Kernel-Mode APC Delivery \n");
|
||||
KeRemoveAllWaitsThread(CONTAINING_RECORD(Thread, ETHREAD, Tcb),
|
||||
STATUS_KERNEL_APC,
|
||||
TRUE);
|
||||
}
|
||||
} else if ((Thread->WaitMode == UserMode) && (Thread->Alertable)) {
|
||||
DPRINT ("Waking up Thread for User-Mode APC Delivery \n");
|
||||
Thread->ApcState.UserApcPending = TRUE;
|
||||
KeRemoveAllWaitsThread(CONTAINING_RECORD(Thread, ETHREAD, Tcb),
|
||||
STATUS_USER_APC,
|
||||
TRUE);
|
||||
}
|
||||
|
||||
/* Return Sucess if we are here */
|
||||
KeLowerIrql(OldIrql);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOLEAN STDCALL
|
||||
|
@ -441,92 +223,292 @@ KeRemoveQueueApc (PKAPC Apc)
|
|||
* NOTE: This function is not exported.
|
||||
*/
|
||||
{
|
||||
KIRQL oldIrql;
|
||||
PKTHREAD TargetThread;
|
||||
KIRQL OldIrql;
|
||||
PKTHREAD Thread = Apc->Thread;
|
||||
|
||||
oldIrql = KeRaiseIrqlToDpcLevel();
|
||||
if (Apc->Inserted == FALSE)
|
||||
{
|
||||
KeLowerIrql(oldIrql);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
TargetThread = Apc->Thread;
|
||||
RemoveEntryList(&Apc->ApcListEntry);
|
||||
if (Apc->ApcMode == KernelMode)
|
||||
{
|
||||
TargetThread->ApcStatePointer[(int) Apc->ApcStateIndex]->KernelApcPending--;
|
||||
}
|
||||
else
|
||||
{
|
||||
TargetThread->ApcStatePointer[(int) Apc->ApcStateIndex]->UserApcPending--;
|
||||
}
|
||||
Apc->Inserted = FALSE;
|
||||
|
||||
KeLowerIrql(oldIrql);
|
||||
return(TRUE);
|
||||
DPRINT("KeRemoveQueueApc called for APC: %x \n", Apc);
|
||||
|
||||
/* FIXME: Implement Dispatcher Lock */
|
||||
OldIrql = KeRaiseIrqlToDpcLevel();
|
||||
KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql);
|
||||
|
||||
/* Remove it from the Queue if it's inserted */
|
||||
if (!Apc->Inserted == FALSE) {
|
||||
RemoveEntryList(&Apc->ApcListEntry);
|
||||
Apc->Inserted = FALSE;
|
||||
|
||||
/* If the Queue is completely empty, then no more APCs are pending */
|
||||
if (IsListEmpty(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode])) {
|
||||
if (Apc->ApcMode == KernelMode) {
|
||||
Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->KernelApcPending = FALSE;
|
||||
} else {
|
||||
Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->UserApcPending = FALSE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
|
||||
KeLowerIrql(OldIrql);
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
/* Restore IRQL and Return */
|
||||
KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
|
||||
KeLowerIrql(OldIrql);
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
STDCALL
|
||||
KeTestAlertThread(IN KPROCESSOR_MODE AlertMode)
|
||||
/*
|
||||
* FUNCTION: Tests whether there are any pending APCs for the current thread
|
||||
* and if so the APCs will be delivered on exit from kernel mode
|
||||
*/
|
||||
{
|
||||
KIRQL OldIrql;
|
||||
PKTHREAD Thread = KeGetCurrentThread();
|
||||
BOOLEAN OldState;
|
||||
|
||||
/* FIXME: Implement Dispatcher Lock */
|
||||
OldIrql = KeRaiseIrqlToDpcLevel();
|
||||
KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql);
|
||||
|
||||
OldState = Thread->Alerted[(int)AlertMode];
|
||||
|
||||
/* If the Thread is Alerted, Clear it */
|
||||
if (OldState) {
|
||||
Thread->Alerted[(int)AlertMode] = FALSE;
|
||||
} else if ((AlertMode == UserMode) && (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) {
|
||||
/* If the mode is User and the Queue isn't empty, set Pending */
|
||||
Thread->ApcState.UserApcPending = TRUE;
|
||||
}
|
||||
|
||||
/* FIXME: Implement Dispatcher Lock */
|
||||
KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
|
||||
KeLowerIrql(OldIrql);
|
||||
return OldState;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
VOID STDCALL
|
||||
KeInitializeApc(
|
||||
IN PKAPC Apc,
|
||||
IN PKTHREAD Thread,
|
||||
IN KAPC_ENVIRONMENT TargetEnvironment,
|
||||
IN PKKERNEL_ROUTINE KernelRoutine,
|
||||
IN PKRUNDOWN_ROUTINE RundownRoutine OPTIONAL,
|
||||
IN PKNORMAL_ROUTINE NormalRoutine,
|
||||
IN KPROCESSOR_MODE Mode,
|
||||
IN PVOID Context)
|
||||
VOID
|
||||
STDCALL
|
||||
KiDeliverApc(KPROCESSOR_MODE PreviousMode,
|
||||
PVOID Reserved,
|
||||
PKTRAP_FRAME TrapFrame)
|
||||
/*
|
||||
* FUNCTION: Initialize an APC object
|
||||
* ARGUMENTS:
|
||||
* Apc = Pointer to the APC object to initialized
|
||||
* Thread = Thread the APC is to be delivered to
|
||||
* StateIndex = KAPC_ENVIRONMENT
|
||||
* KernelRoutine = Routine to be called for a kernel-mode APC
|
||||
* RundownRoutine = Routine to be called if the thread has exited with
|
||||
* the APC being executed
|
||||
* NormalRoutine = Routine to be called for a user-mode APC
|
||||
* Mode = APC mode
|
||||
* Context = Parameter to be passed to the APC routine
|
||||
* FUNCTION: Deliver an APC to the current thread.
|
||||
* NOTES: This is called from the IRQL switching code if the current thread
|
||||
* is returning from an IRQL greater than or equal to APC_LEVEL to
|
||||
* PASSIVE_LEVEL and there are kernel-mode APCs pending. This means any
|
||||
* pending APCs will be delivered after a thread gets a new quantum and
|
||||
* after it wakes from a wait. Note that the TrapFrame is only valid if
|
||||
* the previous mode is User.
|
||||
*/
|
||||
{
|
||||
DPRINT("KeInitializeApc(Apc %x, Thread %x, Environment %d, "
|
||||
"KernelRoutine %x, RundownRoutine %x, NormalRoutine %x, Mode %d, "
|
||||
"Context %x)\n",Apc,Thread,TargetEnvironment,KernelRoutine,RundownRoutine,
|
||||
NormalRoutine,Mode,Context);
|
||||
PKTHREAD Thread = KeGetCurrentThread();
|
||||
PLIST_ENTRY ApcListEntry;
|
||||
PKAPC Apc;
|
||||
KIRQL OldIrql;
|
||||
PKKERNEL_ROUTINE KernelRoutine;
|
||||
PVOID NormalContext;
|
||||
PKNORMAL_ROUTINE NormalRoutine;
|
||||
PVOID SystemArgument1;
|
||||
PVOID SystemArgument2;
|
||||
|
||||
memset(Apc, 0, sizeof(KAPC));
|
||||
Apc->Thread = Thread;
|
||||
Apc->ApcListEntry.Flink = NULL;
|
||||
Apc->ApcListEntry.Blink = NULL;
|
||||
Apc->KernelRoutine = KernelRoutine;
|
||||
Apc->RundownRoutine = RundownRoutine;
|
||||
Apc->NormalRoutine = NormalRoutine;
|
||||
Apc->NormalContext = Context;
|
||||
Apc->Inserted = FALSE;
|
||||
/* Lock the APC Queue and Raise IRQL to Synch */
|
||||
KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql);
|
||||
|
||||
if (TargetEnvironment == CurrentApcEnvironment)
|
||||
{
|
||||
Apc->ApcStateIndex = Thread->ApcStateIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
Apc->ApcStateIndex = TargetEnvironment;
|
||||
}
|
||||
/* Clear APC Pending */
|
||||
Thread->ApcState.KernelApcPending = FALSE;
|
||||
|
||||
/* Do the Kernel APCs first */
|
||||
while (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) {
|
||||
|
||||
/* Get the next Entry */
|
||||
ApcListEntry = Thread->ApcState.ApcListHead[KernelMode].Flink;
|
||||
Apc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry);
|
||||
|
||||
/* Save Parameters so that it's safe to free the Object in Kernel Routine*/
|
||||
NormalRoutine = Apc->NormalRoutine;
|
||||
KernelRoutine = Apc->KernelRoutine;
|
||||
NormalContext = Apc->NormalContext;
|
||||
SystemArgument1 = Apc->SystemArgument1;
|
||||
SystemArgument2 = Apc->SystemArgument2;
|
||||
|
||||
/* Special APC */
|
||||
if (NormalRoutine == NULL) {
|
||||
/* Remove the APC from the list */
|
||||
Apc->Inserted = FALSE;
|
||||
RemoveEntryList(ApcListEntry);
|
||||
|
||||
/* Go back to APC_LEVEL */
|
||||
KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
|
||||
|
||||
/* Call the Special APC */
|
||||
DPRINT("Delivering a Special APC: %x\n", Apc);
|
||||
KernelRoutine(Apc,
|
||||
&NormalRoutine,
|
||||
&NormalContext,
|
||||
&SystemArgument1,
|
||||
&SystemArgument2);
|
||||
|
||||
if (Apc->NormalRoutine != NULL)
|
||||
{
|
||||
Apc->ApcMode = Mode;
|
||||
}
|
||||
else
|
||||
{
|
||||
Apc->ApcMode = KernelMode;
|
||||
}
|
||||
/* Raise IRQL and Lock again */
|
||||
KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql);
|
||||
} else {
|
||||
/* Normal Kernel APC */
|
||||
if (Thread->ApcState.KernelApcInProgress || Thread->KernelApcDisable) {
|
||||
KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Dequeue the APC */
|
||||
RemoveEntryList(ApcListEntry);
|
||||
Apc->Inserted = FALSE;
|
||||
|
||||
/* Go back to APC_LEVEL */
|
||||
KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
|
||||
|
||||
/* Call the Kernel APC */
|
||||
DPRINT("Delivering a Normal APC: %x\n", Apc);
|
||||
KernelRoutine(Apc,
|
||||
&NormalRoutine,
|
||||
&NormalContext,
|
||||
&SystemArgument1,
|
||||
&SystemArgument2);
|
||||
|
||||
/* If There still is a Normal Routine, then we need to call this at PASSIVE_LEVEL */
|
||||
if (NormalRoutine != NULL) {
|
||||
/* At Passive Level, this APC can be prempted by a Special APC */
|
||||
Thread->ApcState.KernelApcInProgress = TRUE;
|
||||
KeLowerIrql(PASSIVE_LEVEL);
|
||||
|
||||
/* Call and Raise IRQ back to APC_LEVEL */
|
||||
DPRINT("Calling the Normal Routine for a Normal APC: %x\n", Apc);
|
||||
NormalRoutine(&NormalContext, &SystemArgument1, &SystemArgument2);
|
||||
KeRaiseIrql(APC_LEVEL, &OldIrql);
|
||||
}
|
||||
|
||||
/* Raise IRQL and Lock again */
|
||||
KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql);
|
||||
Thread->ApcState.KernelApcInProgress = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we do the User APCs */
|
||||
if ((!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])) &&
|
||||
(PreviousMode == UserMode) &&
|
||||
(Thread->ApcState.UserApcPending == TRUE)) {
|
||||
|
||||
/* It's not pending anymore */
|
||||
Thread->ApcState.UserApcPending = FALSE;
|
||||
|
||||
/* Get the APC Object */
|
||||
ApcListEntry = Thread->ApcState.ApcListHead[UserMode].Flink;
|
||||
Apc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry);
|
||||
|
||||
/* Save Parameters so that it's safe to free the Object in Kernel Routine*/
|
||||
NormalRoutine = Apc->NormalRoutine;
|
||||
KernelRoutine = Apc->KernelRoutine;
|
||||
NormalContext = Apc->NormalContext;
|
||||
SystemArgument1 = Apc->SystemArgument1;
|
||||
SystemArgument2 = Apc->SystemArgument2;
|
||||
|
||||
/* Remove the APC from Queue, restore IRQL and call the APC */
|
||||
RemoveEntryList(ApcListEntry);
|
||||
KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
|
||||
DPRINT("Calling the Kernel Routine for for a User APC: %x\n", Apc);
|
||||
KernelRoutine(Apc,
|
||||
&NormalRoutine,
|
||||
&NormalContext,
|
||||
&SystemArgument1,
|
||||
&SystemArgument2);
|
||||
|
||||
if (NormalRoutine == NULL) {
|
||||
/* Check if more User APCs are Pending */
|
||||
KeTestAlertThread(UserMode);
|
||||
} else {
|
||||
/* Set up the Trap Frame and prepare for Execution in NTDLL.DLL */
|
||||
DPRINT("Delivering a User APC: %x\n", Apc);
|
||||
KiInitializeUserApc(Reserved,
|
||||
TrapFrame,
|
||||
NormalRoutine,
|
||||
NormalContext,
|
||||
SystemArgument1,
|
||||
SystemArgument2);
|
||||
}
|
||||
} else {
|
||||
/* Go back to APC_LEVEL */
|
||||
KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
|
||||
}
|
||||
}
|
||||
|
||||
VOID KiInitializeUserApc(IN PVOID Reserved,
|
||||
IN PKTRAP_FRAME TrapFrame,
|
||||
IN PKNORMAL_ROUTINE NormalRoutine,
|
||||
IN PVOID NormalContext,
|
||||
IN PVOID SystemArgument1,
|
||||
IN PVOID SystemArgument2)
|
||||
/*
|
||||
* FUNCTION: Prepares the Context for a user mode APC through ntdll.dll
|
||||
*/
|
||||
{
|
||||
PCONTEXT Context;
|
||||
PULONG Esp;
|
||||
|
||||
DPRINT("KiInitializeUserApc(TrapFrame %x/%x)\n", TrapFrame, KeGetCurrentThread()->TrapFrame);
|
||||
|
||||
/*
|
||||
* Save the thread's current context (in other words the registers
|
||||
* that will be restored when it returns to user mode) so the
|
||||
* APC dispatcher can restore them later
|
||||
*/
|
||||
Context = (PCONTEXT)(((PUCHAR)TrapFrame->Esp) - sizeof(CONTEXT));
|
||||
RtlZeroMemory(Context, sizeof(CONTEXT));
|
||||
Context->ContextFlags = CONTEXT_FULL;
|
||||
Context->SegGs = TrapFrame->Gs;
|
||||
Context->SegFs = TrapFrame->Fs;
|
||||
Context->SegEs = TrapFrame->Es;
|
||||
Context->SegDs = TrapFrame->Ds;
|
||||
Context->Edi = TrapFrame->Edi;
|
||||
Context->Esi = TrapFrame->Esi;
|
||||
Context->Ebx = TrapFrame->Ebx;
|
||||
Context->Edx = TrapFrame->Edx;
|
||||
Context->Ecx = TrapFrame->Ecx;
|
||||
Context->Eax = TrapFrame->Eax;
|
||||
Context->Ebp = TrapFrame->Ebp;
|
||||
Context->Eip = TrapFrame->Eip;
|
||||
Context->SegCs = TrapFrame->Cs;
|
||||
Context->EFlags = TrapFrame->Eflags;
|
||||
Context->Esp = TrapFrame->Esp;
|
||||
Context->SegSs = TrapFrame->Ss;
|
||||
|
||||
/*
|
||||
* Setup the trap frame so the thread will start executing at the
|
||||
* APC Dispatcher when it returns to user-mode
|
||||
*/
|
||||
Esp = (PULONG)(((PUCHAR)TrapFrame->Esp) - (sizeof(CONTEXT) + (6 * sizeof(ULONG))));
|
||||
Esp[0] = 0xdeadbeef;
|
||||
Esp[1] = (ULONG)NormalRoutine;
|
||||
Esp[2] = (ULONG)NormalContext;
|
||||
Esp[3] = (ULONG)SystemArgument1;
|
||||
Esp[4] = (ULONG)SystemArgument2;
|
||||
Esp[5] = (ULONG)Context;
|
||||
TrapFrame->Eip = (ULONG)LdrpGetSystemDllApcDispatcher();
|
||||
TrapFrame->Esp = (ULONG)Esp;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
BOOLEAN
|
||||
STDCALL
|
||||
KeAreApcsDisabled(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return KeGetCurrentThread()->KernelApcDisable ? FALSE : TRUE;
|
||||
}
|
||||
|
||||
VOID STDCALL
|
||||
|
@ -597,8 +579,11 @@ NtQueueApcThread(HANDLE ThreadHandle,
|
|||
|
||||
NTSTATUS STDCALL NtTestAlert(VOID)
|
||||
{
|
||||
KiTestAlert();
|
||||
return(STATUS_SUCCESS);
|
||||
if (KeTestAlertThread(KeGetPreviousMode())) {
|
||||
return STATUS_ALERTED;
|
||||
} else {
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
VOID INIT_FUNCTION
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/* $Id: irq.c,v 1.54 2004/11/07 22:55:38 navaraf Exp $
|
||||
/* $Id: irq.c,v 1.55 2004/11/10 02:51:00 ion Exp $
|
||||
*
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: ntoskrnl/ke/i386/irq.c
|
||||
|
@ -361,7 +361,7 @@ KiInterruptDispatch (ULONG vector, PKIRQ_TRAPFRAME Trapframe)
|
|||
CurrentThread->TrapFrame = &KernelTrapFrame;
|
||||
}
|
||||
|
||||
KiDeliverNormalApc();
|
||||
KiDeliverApc(KernelMode, NULL, NULL);
|
||||
|
||||
ASSERT(KeGetCurrentThread() == CurrentThread);
|
||||
if (CurrentThread->TrapFrame == &KernelTrapFrame)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Id: usercall.c,v 1.30 2004/10/22 20:32:49 ekohl Exp $
|
||||
/* $Id: usercall.c,v 1.31 2004/11/10 02:51:00 ion Exp $
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
|
@ -43,11 +43,11 @@ KiAfterSystemCallHook(PKTRAP_FRAME TrapFrame)
|
|||
{
|
||||
if (KeGetCurrentThread()->Alerted[1] != 0 && TrapFrame->Cs != KERNEL_CS)
|
||||
{
|
||||
KiDeliverNormalApc();
|
||||
KiDeliverApc(KernelMode, NULL, NULL);
|
||||
}
|
||||
if (KeGetCurrentThread()->Alerted[0] != 0 && TrapFrame->Cs != KERNEL_CS)
|
||||
{
|
||||
KiDeliverUserApc(TrapFrame);
|
||||
KiDeliverApc(UserMode, NULL, TrapFrame);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/* $Id: kthread.c,v 1.57 2004/11/07 22:55:38 navaraf Exp $
|
||||
/* $Id: kthread.c,v 1.58 2004/11/10 02:50:59 ion Exp $
|
||||
*
|
||||
* FILE: ntoskrnl/ke/kthread.c
|
||||
* PURPOSE: Microkernel thread support
|
||||
|
@ -249,27 +249,7 @@ KeInitializeThread(PKPROCESS Process, PKTHREAD Thread, BOOLEAN First)
|
|||
Thread->PriorityDecrement = 0;
|
||||
Thread->Quantum = Process->ThreadQuantum;
|
||||
memset(Thread->WaitBlock, 0, sizeof(KWAIT_BLOCK)*4);
|
||||
Thread->LegoData = 0;
|
||||
|
||||
/*
|
||||
* FIXME: Why this?
|
||||
*/
|
||||
// Thread->KernelApcDisable = 1;
|
||||
/*
|
||||
It may be correct to have regular kmode APC disabled
|
||||
until the thread has been fully created, BUT the problem is: they are
|
||||
currently never enabled again! So until somone figures out how
|
||||
this really work, I'm setting regular kmode APC's intially enabled.
|
||||
-Gunnar
|
||||
|
||||
UPDATE: After enabling regular kmode APC's I have experienced random
|
||||
crashes. I'm disabling it again, until we fix the APC implementation...
|
||||
-Gunnar
|
||||
*/
|
||||
|
||||
Thread->KernelApcDisable = -1;
|
||||
|
||||
|
||||
Thread->LegoData = 0;
|
||||
Thread->UserAffinity = Process->Affinity;
|
||||
Thread->SystemAffinityActive = 0;
|
||||
Thread->PowerState = 0;
|
||||
|
@ -298,15 +278,11 @@ crashes. I'm disabling it again, until we fix the APC implementation...
|
|||
Thread->KernelTime = 0;
|
||||
Thread->UserTime = 0;
|
||||
memset(&Thread->SavedApcState, 0, sizeof(KAPC_STATE));
|
||||
|
||||
/* FIXME: is this correct? */
|
||||
Thread->Alertable = 1;
|
||||
|
||||
|
||||
Thread->ApcStateIndex = OriginalApcEnvironment;
|
||||
|
||||
Thread->ApcQueueable = TRUE;
|
||||
|
||||
Thread->AutoAlignment = Process->AutoAlignment;
|
||||
|
||||
KeInitializeApc(&Thread->SuspendApc,
|
||||
Thread,
|
||||
OriginalApcEnvironment,
|
||||
|
@ -316,6 +292,7 @@ crashes. I'm disabling it again, until we fix the APC implementation...
|
|||
KernelMode,
|
||||
NULL);
|
||||
KeInitializeSemaphore(&Thread->SuspendSemaphore, 0, 128);
|
||||
|
||||
InsertTailList(&Process->ThreadListHead,
|
||||
&Thread->ThreadListEntry);
|
||||
Thread->FreezeCount = 0;
|
||||
|
|
|
@ -546,7 +546,7 @@ KeWaitForMultipleObjects(ULONG Count,
|
|||
* If we are going to wait alertably and a user apc is pending
|
||||
* then return
|
||||
*/
|
||||
if (Alertable && KiTestAlert())
|
||||
if (Alertable && KeTestAlertThread(KeGetPreviousMode()))
|
||||
{
|
||||
KeReleaseDispatcherDatabaseLock(OldIrql);
|
||||
return (STATUS_USER_APC);
|
||||
|
|
|
@ -65,10 +65,10 @@ NTSTATUS MmPageFault(ULONG Cs,
|
|||
}
|
||||
|
||||
if (KeGetCurrentThread() != NULL &&
|
||||
KeGetCurrentThread()->Alerted[1] != 0 &&
|
||||
Cs != KERNEL_CS)
|
||||
KeGetCurrentThread()->Alerted[UserMode] != 0 &&
|
||||
Cs != KERNEL_CS)
|
||||
{
|
||||
KiDeliverNormalApc();
|
||||
KiDeliverApc(KernelMode, NULL, NULL);
|
||||
}
|
||||
if (!NT_SUCCESS(Status) && (Mode == KernelMode) &&
|
||||
((*Eip) >= (ULONG)MmSafeCopyFromUserUnsafeStart) &&
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Id: create.c,v 1.84 2004/10/24 20:37:27 weiden Exp $
|
||||
/* $Id: create.c,v 1.85 2004/11/10 02:51:00 ion Exp $
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
|
@ -758,13 +758,15 @@ NtCreateThread(OUT PHANDLE ThreadHandle,
|
|||
LdrInitApcRundownRoutine, LdrpGetSystemDllEntryPoint(),
|
||||
UserMode, NULL);
|
||||
KeInsertQueueApc(LdrInitApc, NULL, NULL, IO_NO_INCREMENT);
|
||||
|
||||
/*
|
||||
* Start the thread running and force it to execute the APC(s) we just
|
||||
* queued before it runs anything else in user-mode.
|
||||
|
||||
/*
|
||||
* The thread is non-alertable, so the APC we added did not set UserApcPending to TRUE.
|
||||
* We must do this manually. Do NOT attempt to set the Thread to Alertable before the call,
|
||||
* doing so is a blatant and erronous hack.
|
||||
*/
|
||||
Thread->Tcb.Alertable = TRUE;
|
||||
Thread->Tcb.Alerted[0] = 1;
|
||||
Thread->Tcb.ApcState.UserApcPending = TRUE;
|
||||
Thread->Tcb.Alerted[KernelMode] = TRUE;
|
||||
|
||||
PsUnblockThread(Thread, NULL);
|
||||
|
||||
return(STATUS_SUCCESS);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Id: process.c,v 1.148 2004/10/31 21:22:06 navaraf Exp $
|
||||
/* $Id: process.c,v 1.149 2004/11/10 02:51:00 ion Exp $
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
|
@ -51,6 +51,16 @@ typedef struct
|
|||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
VOID
|
||||
STDCALL
|
||||
PsExitSpecialApc(PKAPC Apc,
|
||||
PKNORMAL_ROUTINE *NormalRoutine,
|
||||
PVOID *NormalContext,
|
||||
PVOID *SystemArgument1,
|
||||
PVOID *SystemArgument2)
|
||||
{
|
||||
}
|
||||
|
||||
PEPROCESS
|
||||
PsGetNextProcess(PEPROCESS OldProcess)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue