- apc.c: Fixed some bugs and used Dispatcher Lock. Simplified some functions and renamed/inlined others.
- wait.c: Fixed some assumptions about Dispatcher Lock and Waiting/Alertability
- process.c: Fully implemented KeStackAttachProcess and KeStackDetachProcess. Made all functions use PKPROCESS and not PEPROCESS.
Memory Manager: Fixed calls to KeAttachProcess/DetachProcess to typecast PKPROCESS
Process Manager: Removed call to empty function in apc.c

svn path=/trunk/; revision=11622
This commit is contained in:
Alex Ionescu 2004-11-11 22:23:52 +00:00
parent 0cc7d4d22d
commit a9c33470e5
11 changed files with 327 additions and 300 deletions

View file

@ -20,13 +20,14 @@ KeSaveFloatingPointState(
#define KeFlushIoBuffers(Mdl, ReadOperation, DmaOperation) #define KeFlushIoBuffers(Mdl, ReadOperation, DmaOperation)
#endif #endif
VOID STDCALL KeAttachProcess (struct _EPROCESS* Process); VOID STDCALL KeAttachProcess(struct _KPROCESS *Process);
VOID FASTCALL KiAcquireSpinLock(PKSPIN_LOCK SpinLock); VOID FASTCALL KiAcquireSpinLock(PKSPIN_LOCK SpinLock);
VOID FASTCALL KiReleaseSpinLock(PKSPIN_LOCK SpinLock); VOID FASTCALL KiReleaseSpinLock(PKSPIN_LOCK SpinLock);
VOID KeDrainApcQueue(VOID); VOID KeDrainApcQueue(VOID);
struct _KPROCESS* KeGetCurrentProcess(VOID); struct _KPROCESS* KeGetCurrentProcess(VOID);
/* /*

View file

@ -122,6 +122,24 @@ typedef struct _KAPC
#include <poppack.h> #include <poppack.h>
#ifndef __USE_W32API
#include <pshpack1.h>
typedef struct _KAPC_STATE
{
LIST_ENTRY ApcListHead[2];
struct _KPROCESS* Process;
UCHAR KernelApcInProgress;
UCHAR KernelApcPending;
UCHAR UserApcPending;
UCHAR Reserved;
} KAPC_STATE, *PKAPC_STATE, *__restrict PRKAPC_STATE;
#include <poppack.h>
#endif /* __USE_W32API */
typedef struct _KBUGCHECK_CALLBACK_RECORD typedef struct _KBUGCHECK_CALLBACK_RECORD
{ {
LIST_ENTRY Entry; LIST_ENTRY Entry;

View file

@ -96,6 +96,10 @@ VOID KiInitializeUserApc(IN PVOID Reserved,
IN PVOID SystemArgument1, IN PVOID SystemArgument1,
IN PVOID SystemArgument2); IN PVOID SystemArgument2);
VOID STDCALL KiAttachProcess(struct _KTHREAD *Thread, struct _KPROCESS *Process, KIRQL ApcLock, struct _KAPC_STATE *SavedApcState);
VOID STDCALL KiSwapProcess(struct _KPROCESS *NewProcess, struct _KPROCESS *OldProcess);
BOOLEAN BOOLEAN
STDCALL STDCALL
KeTestAlertThread(IN KPROCESSOR_MODE AlertMode); KeTestAlertThread(IN KPROCESSOR_MODE AlertMode);
@ -122,10 +126,10 @@ VOID KeInit2(VOID);
BOOLEAN KiDeliverUserApc(PKTRAP_FRAME TrapFrame); BOOLEAN KiDeliverUserApc(PKTRAP_FRAME TrapFrame);
VOID FASTCALL VOID
KiSwapApcEnvironment( STDCALL
struct _KTHREAD* Thread, KiMoveApcState (PKAPC_STATE OldState,
struct _KPROCESS* NewProcess); PKAPC_STATE NewState);
VOID VOID
KiAddProfileEvent(KPROFILE_SOURCE Source, ULONG Pc); KiAddProfileEvent(KPROFILE_SOURCE Source, ULONG Pc);

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
/* $Id: ps.h,v 1.73 2004/11/10 02:50:59 ion Exp $ /* $Id: ps.h,v 1.74 2004/11/11 22:23:52 ion Exp $
* *
* FILE: ntoskrnl/ke/kthread.c * FILE: ntoskrnl/ke/kthread.c
* PURPOSE: Process manager definitions * PURPOSE: Process manager definitions
@ -53,24 +53,6 @@ extern HANDLE SystemProcessHandle;
extern LCID PsDefaultThreadLocaleId; extern LCID PsDefaultThreadLocaleId;
extern LCID PsDefaultSystemLocaleId; extern LCID PsDefaultSystemLocaleId;
#ifndef __USE_W32API
#include <pshpack1.h>
typedef struct _KAPC_STATE
{
LIST_ENTRY ApcListHead[2];
struct _KPROCESS* Process;
UCHAR KernelApcInProgress;
UCHAR KernelApcPending;
UCHAR UserApcPending;
UCHAR Reserved;
} KAPC_STATE, *PKAPC_STATE, *__restrict PRKAPC_STATE;
#include <poppack.h>
#endif /* __USE_W32API */
#include <pshpack1.h> #include <pshpack1.h>
typedef struct _KTHREAD typedef struct _KTHREAD

View file

@ -123,12 +123,12 @@ KeInsertQueueApc (PKAPC Apc,
PLIST_ENTRY ApcListEntry; PLIST_ENTRY ApcListEntry;
PKAPC QueuedApc; PKAPC QueuedApc;
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
DPRINT ("KeInsertQueueApc(Apc %x, SystemArgument1 %x, " DPRINT ("KeInsertQueueApc(Apc %x, SystemArgument1 %x, "
"SystemArgument2 %x)\n",Apc,SystemArgument1, "SystemArgument2 %x)\n",Apc,SystemArgument1,
SystemArgument2); SystemArgument2);
/* FIXME: Implement Dispatcher Lock */ OldIrql = KeAcquireDispatcherDatabaseLock();
OldIrql = KeRaiseIrqlToDpcLevel();
/* Get the Thread specified in the APC */ /* Get the Thread specified in the APC */
Thread = Apc->Thread; Thread = Apc->Thread;
@ -136,7 +136,7 @@ KeInsertQueueApc (PKAPC Apc,
/* Make sure the thread allows APC Queues */ /* Make sure the thread allows APC Queues */
if (Thread->ApcQueueable == FALSE) { if (Thread->ApcQueueable == FALSE) {
DPRINT("Thread doesn't allow APC Queues\n"); DPRINT("Thread doesn't allow APC Queues\n");
KeLowerIrql(OldIrql); KeReleaseDispatcherDatabaseLock(OldIrql);
return FALSE; return FALSE;
} }
@ -146,7 +146,7 @@ KeInsertQueueApc (PKAPC Apc,
/* Don't do anything if the APC is already inserted */ /* Don't do anything if the APC is already inserted */
if (Apc->Inserted) { if (Apc->Inserted) {
KeLowerIrql(OldIrql); KeReleaseDispatcherDatabaseLock(OldIrql);
return FALSE; return FALSE;
} }
@ -208,7 +208,7 @@ KeInsertQueueApc (PKAPC Apc,
} }
/* Return Sucess if we are here */ /* Return Sucess if we are here */
KeLowerIrql(OldIrql); KeReleaseDispatcherDatabaseLock(OldIrql);
return TRUE; return TRUE;
} }
@ -226,10 +226,10 @@ KeRemoveQueueApc (PKAPC Apc)
KIRQL OldIrql; KIRQL OldIrql;
PKTHREAD Thread = Apc->Thread; PKTHREAD Thread = Apc->Thread;
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
DPRINT("KeRemoveQueueApc called for APC: %x \n", Apc); DPRINT("KeRemoveQueueApc called for APC: %x \n", Apc);
/* FIXME: Implement Dispatcher Lock */ OldIrql = KeAcquireDispatcherDatabaseLock();
OldIrql = KeRaiseIrqlToDpcLevel();
KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql); KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql);
/* Remove it from the Queue if it's inserted */ /* Remove it from the Queue if it's inserted */
@ -247,13 +247,13 @@ KeRemoveQueueApc (PKAPC Apc)
} }
} else { } else {
KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
KeLowerIrql(OldIrql); KeReleaseDispatcherDatabaseLock(OldIrql);
return(FALSE); return(FALSE);
} }
/* Restore IRQL and Return */ /* Restore IRQL and Return */
KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
KeLowerIrql(OldIrql); KeReleaseDispatcherDatabaseLock(OldIrql);
return(TRUE); return(TRUE);
} }
@ -269,9 +269,10 @@ KeTestAlertThread(IN KPROCESSOR_MODE AlertMode)
PKTHREAD Thread = KeGetCurrentThread(); PKTHREAD Thread = KeGetCurrentThread();
BOOLEAN OldState; BOOLEAN OldState;
/* FIXME: Implement Dispatcher Lock */ ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
OldIrql = KeRaiseIrqlToDpcLevel();
KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql); OldIrql = KeAcquireDispatcherDatabaseLock();
KiAcquireSpinLock(&Thread->ApcQueueLock);
OldState = Thread->Alerted[(int)AlertMode]; OldState = Thread->Alerted[(int)AlertMode];
@ -283,9 +284,8 @@ KeTestAlertThread(IN KPROCESSOR_MODE AlertMode)
Thread->ApcState.UserApcPending = TRUE; Thread->ApcState.UserApcPending = TRUE;
} }
/* FIXME: Implement Dispatcher Lock */ KiReleaseSpinLock(&Thread->ApcQueueLock);
KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); KeReleaseDispatcherDatabaseLock(OldIrql);
KeLowerIrql(OldIrql);
return OldState; return OldState;
} }
@ -444,12 +444,25 @@ KiDeliverApc(KPROCESSOR_MODE PreviousMode,
} }
} }
VOID KiInitializeUserApc(IN PVOID Reserved, VOID
IN PKTRAP_FRAME TrapFrame, STDCALL
IN PKNORMAL_ROUTINE NormalRoutine, KiFreeApcRoutine(PKAPC Apc,
IN PVOID NormalContext, PKNORMAL_ROUTINE* NormalRoutine,
IN PVOID SystemArgument1, PVOID* NormalContext,
IN PVOID SystemArgument2) PVOID* SystemArgument1,
PVOID* SystemArgument2)
{
/* Free the APC and do nothing else */
ExFreePool(Apc);
}
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 * FUNCTION: Prepares the Context for a user mode APC through ntdll.dll
*/ */
@ -508,77 +521,87 @@ KeAreApcsDisabled(
VOID VOID
) )
{ {
return KeGetCurrentThread()->KernelApcDisable ? FALSE : TRUE; return KeGetCurrentThread()->KernelApcDisable ? TRUE : FALSE;
} }
VOID STDCALL NTSTATUS
NtQueueApcRundownRoutine(PKAPC Apc) STDCALL
{
ExFreePool(Apc);
}
VOID STDCALL
NtQueueApcKernelRoutine(PKAPC Apc,
PKNORMAL_ROUTINE* NormalRoutine,
PVOID* NormalContext,
PVOID* SystemArgument1,
PVOID* SystemArgument2)
{
ExFreePool(Apc);
}
NTSTATUS STDCALL
NtQueueApcThread(HANDLE ThreadHandle, NtQueueApcThread(HANDLE ThreadHandle,
PKNORMAL_ROUTINE ApcRoutine, PKNORMAL_ROUTINE ApcRoutine,
PVOID NormalContext, PVOID NormalContext,
PVOID SystemArgument1, PVOID SystemArgument1,
PVOID SystemArgument2) PVOID SystemArgument2)
/*
* FUNCTION:
* This function is used to queue an APC from user-mode for the specified thread.
* The thread must enter an alertable wait before the APC will be delivered.
*
* ARGUMENTS:
* Thread Handle - Handle to the Thread. This handle must have THREAD_SET_CONTEXT privileges.
* ApcRoutine - Pointer to the APC Routine to call when the APC executes.
* NormalContext - User-defined value to pass to the APC Routine
* SystemArgument1 - User-defined value to pass to the APC Routine
* SystemArgument2 - User-defined value to pass to the APC Routine
*
* RETURNS: NTSTATUS SUCCESS or Failure Code from included calls.
*/
{ {
PKAPC Apc;
PETHREAD Thread;
NTSTATUS Status;
PVOID ThreadVar;
ThreadVar = &Thread; PKAPC Apc;
PETHREAD Thread;
NTSTATUS Status;
/* Get ETHREAD from Handle */
Status = ObReferenceObjectByHandle(ThreadHandle,
THREAD_SET_CONTEXT,
PsThreadType,
KeGetPreviousMode(),
(PVOID)&Thread,
NULL);
/* Fail if the Handle is invalid for some reason */
if (!NT_SUCCESS(Status)) {
return(Status);
}
/* If this is a Kernel or System Thread, then fail */
if (Thread->Tcb.Teb == NULL) {
ObDereferenceObject(Thread);
return STATUS_INVALID_HANDLE;
}
Status = ObReferenceObjectByHandle(ThreadHandle, /* Allocate an APC */
THREAD_ALL_ACCESS, /* FIXME */ Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG_KAPC);
PsThreadType, if (Apc == NULL) {
UserMode, ObDereferenceObject(Thread);
&ThreadVar, return(STATUS_NO_MEMORY);
NULL); }
if (!NT_SUCCESS(Status))
{
return(Status);
}
Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG_KAPC); /* Initialize and Queue */
if (Apc == NULL) KeInitializeApc(Apc,
{ &Thread->Tcb,
OriginalApcEnvironment,
KiFreeApcRoutine,
NULL,
ApcRoutine,
UserMode,
NormalContext);
if (!KeInsertQueueApc(Apc, SystemArgument1, SystemArgument2, IO_NO_INCREMENT)) {
Status = STATUS_UNSUCCESSFUL;
} else {
Status = STATUS_SUCCESS;
}
/* Dereference Thread and Return */
ObDereferenceObject(Thread); ObDereferenceObject(Thread);
return(STATUS_NO_MEMORY); return Status;
}
KeInitializeApc(Apc,
&Thread->Tcb,
OriginalApcEnvironment,
NtQueueApcKernelRoutine,
NtQueueApcRundownRoutine,
ApcRoutine,
UserMode,
NormalContext);
KeInsertQueueApc(Apc,
SystemArgument1,
SystemArgument2,
IO_NO_INCREMENT);
ObDereferenceObject(Thread);
return(STATUS_SUCCESS);
} }
NTSTATUS
NTSTATUS STDCALL NtTestAlert(VOID) STDCALL
NtTestAlert(VOID)
{ {
/* Check and Alert Thread if needed */
if (KeTestAlertThread(KeGetPreviousMode())) { if (KeTestAlertThread(KeGetPreviousMode())) {
return STATUS_ALERTED; return STATUS_ALERTED;
} else { } else {
@ -586,103 +609,31 @@ NTSTATUS STDCALL NtTestAlert(VOID)
} }
} }
VOID INIT_FUNCTION static inline VOID RepairList(PLIST_ENTRY Original,
PiInitApcManagement(VOID) PLIST_ENTRY Copy,
KPROCESSOR_MODE Mode)
{ {
/* Copy Source to Desination */
if (IsListEmpty(&Original[(int)Mode])) {
InitializeListHead(&Copy[(int)Mode]);
} else {
Copy[(int)Mode].Flink = Original[(int)Mode].Flink;
Copy[(int)Mode].Blink = Original[(int)Mode].Blink;
Original[(int)Mode].Flink->Blink = &Copy[(int)Mode];
Original[(int)Mode].Blink->Flink = &Copy[(int)Mode];
}
} }
static VOID FASTCALL VOID
RepairList(PLIST_ENTRY Original, PLIST_ENTRY Copy, int Mode) STDCALL
KiMoveApcState (PKAPC_STATE OldState,
PKAPC_STATE NewState)
{ {
if (IsListEmpty(&Original[Mode])) /* Restore backup of Original Environment */
{ *NewState = *OldState;
InitializeListHead(&Copy[Mode]);
}
else
{
Copy[Mode].Flink->Blink = &Copy[Mode];
Copy[Mode].Blink->Flink = &Copy[Mode];
}
}
VOID FASTCALL
KiSwapApcEnvironment(
PKTHREAD Thread,
PKPROCESS NewProcess)
{
if (Thread->ApcStateIndex == AttachedApcEnvironment)
{
/* NewProcess must be the same as in the original-environment */
ASSERT(NewProcess == Thread->ApcStatePointer[OriginalApcEnvironment]->Process);
/*
FIXME: Deliver any pending apc's queued to the attached environment before
switching back to the original environment.
This is not crucial thou, since i don't think we'll ever target apc's
to attached environments (or?)...
Remove the following asserts if implementing this.
-Gunnar
*/
/* we don't support targeting apc's at attached-environments (yet)... */
ASSERT(IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]));
ASSERT(IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]));
ASSERT(Thread->ApcState.KernelApcInProgress == FALSE);
ASSERT(Thread->ApcState.KernelApcPending == FALSE);
ASSERT(Thread->ApcState.UserApcPending == FALSE);
/* restore backup of original environment */ /* Repair Lists */
Thread->ApcState = Thread->SavedApcState; RepairList(NewState->ApcListHead, OldState->ApcListHead, KernelMode);
/* repair lists */ RepairList(NewState->ApcListHead, OldState->ApcListHead, UserMode);
RepairList(Thread->SavedApcState.ApcListHead, Thread->ApcState.ApcListHead,
KernelMode);
RepairList(Thread->SavedApcState.ApcListHead, Thread->ApcState.ApcListHead,
UserMode);
/* update environment pointers */
Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState;
Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState;
/* update current-environment index */
Thread->ApcStateIndex = OriginalApcEnvironment;
}
else if (Thread->ApcStateIndex == OriginalApcEnvironment)
{
/* backup original environment */
Thread->SavedApcState = Thread->ApcState;
/* repair lists */
RepairList(Thread->ApcState.ApcListHead, Thread->SavedApcState.ApcListHead,
KernelMode);
RepairList(Thread->ApcState.ApcListHead, Thread->SavedApcState.ApcListHead,
UserMode);
/*
FIXME: Is it possible to target an apc to an attached environment even if the
thread is not currently attached???? If so, then this is bougus since it
reinitializes the attached apc environment then located in SavedApcState.
-Gunnar
*/
/* setup a fresh new attached environment */
InitializeListHead(&Thread->ApcState.ApcListHead[KernelMode]);
InitializeListHead(&Thread->ApcState.ApcListHead[UserMode]);
Thread->ApcState.Process = NewProcess;
Thread->ApcState.KernelApcInProgress = FALSE;
Thread->ApcState.KernelApcPending = FALSE;
Thread->ApcState.UserApcPending = FALSE;
/* update environment pointers */
Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->SavedApcState;
Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->ApcState;
/* update current-environment index */
Thread->ApcStateIndex = AttachedApcEnvironment;
}
else
{
/* FIXME: Is this the correct bug code? */
KEBUGCHECK(APC_INDEX_MISMATCH);
}
} }

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
/* $Id: process.c,v 1.30 2004/10/17 03:43:26 ion Exp $ /* $Id: process.c,v 1.31 2004/11/11 22:23:52 ion Exp $
* *
* PROJECT: ReactOS kernel * PROJECT: ReactOS kernel
* FILE: ntoskrnl/ke/process.c * FILE: ntoskrnl/ke/process.c
@ -38,79 +38,95 @@
/* /*
* @implemented * @implemented
*/ */
VOID STDCALL VOID
KeAttachProcess (PEPROCESS Process) STDCALL
KeAttachProcess(PKPROCESS Process)
{ {
KIRQL oldlvl; KIRQL OldIrql;
PETHREAD CurrentThread; PKTHREAD Thread = KeGetCurrentThread();
ULONG PageDir;
DPRINT("KeAttachProcess: %x\n", Process);
DPRINT("KeAttachProcess(Process %x)\n",Process);
/* Lock Dispatcher */
CurrentThread = PsGetCurrentThread(); OldIrql = KeAcquireDispatcherDatabaseLock();
if (&CurrentThread->ThreadsProcess->Pcb != CurrentThread->Tcb.ApcState.Process) /* Crash system if DPC is being executed! */
{ if (KeIsExecutingDpc()) {
DPRINT1("Invalid attach (thread is already attached)\n"); DPRINT1("Invalid attach (Thread is executing a DPC!)\n");
KEBUGCHECK(INVALID_PROCESS_ATTACH_ATTEMPT); KEBUGCHECK(INVALID_PROCESS_ATTACH_ATTEMPT);
} }
if (&Process->Pcb == CurrentThread->Tcb.ApcState.Process)
{ /* Check if the Target Process is already attached */
DPRINT1("Invalid attach (process is the same)\n"); if (Thread->ApcState.Process == Process || Thread->ApcStateIndex != OriginalApcEnvironment) {
KEBUGCHECK(INVALID_PROCESS_ATTACH_ATTEMPT); DPRINT("Process already Attached. Exitting\n");
} KeReleaseDispatcherDatabaseLock(OldIrql);
} else {
KiAttachProcess(Thread, Process, OldIrql, &Thread->SavedApcState);
/* The stack and the thread structure of the current process may be }
located in a page which is not present in the page directory of
the process we're attaching to. That would lead to a page fault
when this function returns. However, since the processor can't
call the page fault handler 'cause it can't push EIP on the stack,
this will show up as a stack fault which will crash the entire system.
To prevent this, make sure the page directory of the process we're
attaching to is up-to-date. */
MmUpdatePageDir(Process, (PVOID)CurrentThread->Tcb.StackLimit, MM_STACK_SIZE);
MmUpdatePageDir(Process, (PVOID)CurrentThread, sizeof(ETHREAD));
KeRaiseIrql(DISPATCH_LEVEL, &oldlvl);
KiSwapApcEnvironment(&CurrentThread->Tcb, &Process->Pcb);
CurrentThread->Tcb.ApcState.Process = &Process->Pcb;
PageDir = Process->Pcb.DirectoryTableBase.u.LowPart;
DPRINT("Switching process context to %x\n",PageDir);
Ke386SetPageTableDirectory(PageDir);
KeLowerIrql(oldlvl);
} }
/* VOID
* @implemented STDCALL
*/ KiAttachProcess(PKTHREAD Thread, PKPROCESS Process, KIRQL ApcLock, PRKAPC_STATE SavedApcState)
VOID STDCALL
KeDetachProcess (VOID)
{ {
KIRQL oldlvl;
PETHREAD CurrentThread; DPRINT("KiAttachProcess(Thread: %x, Process: %x, SavedApcState: %x\n", Thread, Process, SavedApcState);
ULONG PageDir;
DPRINT("KeDetachProcess()\n"); /* The stack and the thread structure of the current process may be
located in a page which is not present in the page directory of
CurrentThread = PsGetCurrentThread(); the process we're attaching to. That would lead to a page fault
when this function returns. However, since the processor can't
call the page fault handler 'cause it can't push EIP on the stack,
this will show up as a stack fault which will crash the entire system.
To prevent this, make sure the page directory of the process we're
attaching to is up-to-date. */
MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread->StackLimit, MM_STACK_SIZE);
MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread, sizeof(ETHREAD));
/* Increase Stack Count */
Process->StackCount++;
/* Swap the APC Environment */
KiMoveApcState(&Thread->ApcState, SavedApcState);
/* Reinitialize Apc State */
InitializeListHead(&Thread->ApcState.ApcListHead[KernelMode]);
InitializeListHead(&Thread->ApcState.ApcListHead[UserMode]);
Thread->ApcState.Process = Process;
Thread->ApcState.KernelApcInProgress = FALSE;
Thread->ApcState.KernelApcPending = FALSE;
Thread->ApcState.UserApcPending = FALSE;
/* Update Environment Pointers if needed*/
if (SavedApcState == &Thread->SavedApcState) {
Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->SavedApcState;
Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->ApcState;
Thread->ApcStateIndex = AttachedApcEnvironment;
}
/* Swap the Processes */
KiSwapProcess(Process, SavedApcState->Process);
/* Return to old IRQL*/
KeReleaseDispatcherDatabaseLock(ApcLock);
DPRINT("KiAttachProcess Completed Sucesfully\n");
}
if (&CurrentThread->ThreadsProcess->Pcb == CurrentThread->Tcb.ApcState.Process) VOID
{ STDCALL
DPRINT1("Invalid detach (thread was not attached)\n"); KiSwapProcess(PKPROCESS NewProcess, PKPROCESS OldProcess)
KEBUGCHECK(INVALID_PROCESS_DETACH_ATTEMPT); {
} //PKPCR Pcr = KeGetCurrentKpcr();
KeRaiseIrql(DISPATCH_LEVEL, &oldlvl);
KiSwapApcEnvironment(&CurrentThread->Tcb, CurrentThread->Tcb.SavedApcState.Process); /* Do they have an LDT? */
PageDir = CurrentThread->Tcb.ApcState.Process->DirectoryTableBase.u.LowPart; if ((NewProcess->LdtDescriptor) || (OldProcess->LdtDescriptor)) {
Ke386SetPageTableDirectory(PageDir); /* FIXME : SWitch GDT/IDT */
}
KeLowerIrql(oldlvl); DPRINT("Switching CR3 to: %x\n", NewProcess->DirectoryTableBase.u.LowPart);
Ke386SetPageTableDirectory(NewProcess->DirectoryTableBase.u.LowPart);
/* FIXME: Set IopmOffset in TSS */
} }
/* /*
@ -136,10 +152,9 @@ KeStackAttachProcess (
) )
{ {
KIRQL OldIrql; KIRQL OldIrql;
PKTHREAD Thread; PKTHREAD Thread = KeGetCurrentThread();
OldIrql = KeAcquireDispatcherDatabaseLock(); OldIrql = KeAcquireDispatcherDatabaseLock();
Thread = KeGetCurrentThread();
/* Crash system if DPC is being executed! */ /* Crash system if DPC is being executed! */
if (KeIsExecutingDpc()) { if (KeIsExecutingDpc()) {
@ -151,16 +166,53 @@ KeStackAttachProcess (
if (Thread->ApcState.Process == Process) { if (Thread->ApcState.Process == Process) {
ApcState->Process = (PKPROCESS)1; /* Meaning already attached to the same Process */ ApcState->Process = (PKPROCESS)1; /* Meaning already attached to the same Process */
} else { } else {
/* Check if the Current Thread is already attached */ /* Check if the Current Thread is already attached and call the Internal Function*/
if (Thread->ApcStateIndex != 0) { if (Thread->ApcStateIndex != OriginalApcEnvironment) {
KeAttachProcess((PEPROCESS)Process); /* FIXME: Re-write function to support stackability and fix it not to use EPROCESS */ KiAttachProcess(Thread, Process, OldIrql, ApcState);
} else { } else {
KeAttachProcess((PEPROCESS)Process); KiAttachProcess(Thread, Process, OldIrql, &Thread->SavedApcState);
ApcState->Process = NULL; /* FIXME: Re-write function to support stackability and fix it not to use EPROCESS */ ApcState->Process = NULL;
} }
} }
}
/*
* @implemented
*/
VOID STDCALL
KeDetachProcess (VOID)
{
PKTHREAD Thread;
KIRQL OldIrql;
DPRINT("KeDetachProcess()\n");
/* Get Current Thread and Lock */
Thread = KeGetCurrentThread();
OldIrql = KeAcquireDispatcherDatabaseLock();
/* Return to old IRQL*/ /* Check if it's attached */
DPRINT("Current ApcStateIndex: %x\n", Thread->ApcStateIndex);
if (Thread->ApcStateIndex == OriginalApcEnvironment) {
DPRINT1("Invalid detach (thread was not attached)\n");
KEBUGCHECK(INVALID_PROCESS_DETACH_ATTEMPT);
}
/* Decrease Stack Count */
Thread->ApcState.Process->StackCount--;
/* Restore the APC State */
KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState);
Thread->SavedApcState.Process = NULL;
Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState;
Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState;
Thread->ApcStateIndex = OriginalApcEnvironment;
/* Swap Processes */
KiSwapProcess(Thread->ApcState.Process, Thread->ApcState.Process);
/* Unlock Dispatcher */
KeReleaseDispatcherDatabaseLock(OldIrql); KeReleaseDispatcherDatabaseLock(OldIrql);
} }
@ -175,7 +227,6 @@ KeUnstackDetachProcess (
{ {
KIRQL OldIrql; KIRQL OldIrql;
PKTHREAD Thread; PKTHREAD Thread;
ULONG PageDir;
/* If the special "We tried to attach to the process already being attached to" flag is there, don't do anything */ /* If the special "We tried to attach to the process already being attached to" flag is there, don't do anything */
if (ApcState->Process == (PKPROCESS)1) return; if (ApcState->Process == (PKPROCESS)1) return;
@ -184,7 +235,7 @@ KeUnstackDetachProcess (
OldIrql = KeAcquireDispatcherDatabaseLock(); OldIrql = KeAcquireDispatcherDatabaseLock();
/* Sorry Buddy, can't help you if you've got APCs or just aren't attached */ /* Sorry Buddy, can't help you if you've got APCs or just aren't attached */
if ((Thread->ApcStateIndex == 0) || (Thread->ApcState.KernelApcInProgress)) { if ((Thread->ApcStateIndex == OriginalApcEnvironment) || (Thread->ApcState.KernelApcInProgress)) {
DPRINT1("Invalid detach (Thread not Attached, or Kernel APC in Progress!)\n"); DPRINT1("Invalid detach (Thread not Attached, or Kernel APC in Progress!)\n");
KEBUGCHECK(INVALID_PROCESS_DETACH_ATTEMPT); KEBUGCHECK(INVALID_PROCESS_DETACH_ATTEMPT);
} }
@ -196,15 +247,16 @@ KeUnstackDetachProcess (
/* The ApcState parameter is useless, so use the saved data and reset it */ /* The ApcState parameter is useless, so use the saved data and reset it */
RtlMoveMemory(&Thread->SavedApcState, &Thread->ApcState, sizeof(KAPC_STATE)); RtlMoveMemory(&Thread->SavedApcState, &Thread->ApcState, sizeof(KAPC_STATE));
Thread->SavedApcState.Process = NULL; Thread->SavedApcState.Process = NULL;
Thread->ApcStateIndex = 0; Thread->ApcStateIndex = OriginalApcEnvironment;
Thread->ApcStatePointer[0] = &Thread->ApcState; Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState;
Thread->ApcStatePointer[1] = &Thread->SavedApcState; Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState;
} }
/* Do the Actual Swap */ /* Restore the APC State */
KiSwapApcEnvironment(Thread, Thread->SavedApcState.Process); KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState);
PageDir = Thread->ApcState.Process->DirectoryTableBase.u.LowPart;
Ke386SetPageTableDirectory(PageDir); /* Swap Processes */
KiSwapProcess(Thread->ApcState.Process, Thread->ApcState.Process);
/* Return to old IRQL*/ /* Return to old IRQL*/
KeReleaseDispatcherDatabaseLock(OldIrql); KeReleaseDispatcherDatabaseLock(OldIrql);

View file

@ -197,9 +197,6 @@ VOID KeRemoveAllWaitsThread(PETHREAD Thread, NTSTATUS WaitStatus, BOOL Unblock)
{ {
PKWAIT_BLOCK WaitBlock, PrevWaitBlock; PKWAIT_BLOCK WaitBlock, PrevWaitBlock;
BOOLEAN WasWaiting = FALSE; BOOLEAN WasWaiting = FALSE;
KIRQL OldIrql;
OldIrql = KeAcquireDispatcherDatabaseLock ();
WaitBlock = (PKWAIT_BLOCK)Thread->Tcb.WaitBlockList; WaitBlock = (PKWAIT_BLOCK)Thread->Tcb.WaitBlockList;
if (WaitBlock != NULL) if (WaitBlock != NULL)
@ -223,8 +220,6 @@ VOID KeRemoveAllWaitsThread(PETHREAD Thread, NTSTATUS WaitStatus, BOOL Unblock)
{ {
PsUnblockThread(Thread, &WaitStatus); PsUnblockThread(Thread, &WaitStatus);
} }
KeReleaseDispatcherDatabaseLock (OldIrql);
} }
static BOOLEAN static BOOLEAN
@ -542,15 +537,40 @@ KeWaitForMultipleObjects(ULONG Count,
OldIrql = KeAcquireDispatcherDatabaseLock (); OldIrql = KeAcquireDispatcherDatabaseLock ();
} }
/* /* Alertability 101
* If we are going to wait alertably and a user apc is pending * ----------------
* then return * A Wait can either be Alertable, or Non-Alertable.
* An Alertable Wait means that APCs can "Wake" the Thread, also called UnWaiting
* If an APC is Pending however, we must refuse an Alertable Wait. Such a wait would
* be pointless since an APC is just about to be delivered.
*
* There are many ways to check if it's safe to be alertable, and these are the ones
* that I could think of:
* - The Thread is already Alerted. So someone beat us to the punch and we bail out.
* - The Thread is Waiting in User-Mode, the APC Queue is not-empty.
* It's defintely clear that we have incoming APCs, so we need to bail out and let the system
* know that there are Pending User APCs (so they can be Delivered and maybe we can try again)
*
* Furthermore, wether or not we want to be Alertable, if the Thread is waiting in User-Mode, and there
* are Pending User APCs, we should bail out, since APCs will be delivered any second.
*/ */
if (Alertable && KeTestAlertThread(KeGetPreviousMode())) if (Alertable) {
{ if (CurrentThread->Alerted[(int)WaitMode]) {
KeReleaseDispatcherDatabaseLock(OldIrql); CurrentThread->Alerted[(int)WaitMode] = FALSE;
return (STATUS_USER_APC); DPRINT("Alertability failed\n");
} KeReleaseDispatcherDatabaseLock(OldIrql);
return (STATUS_ALERTED);
} else if ((!IsListEmpty(&CurrentThread->ApcState.ApcListHead[UserMode])) && (WaitMode == UserMode)) {
DPRINT1("Alertability failed\n");
CurrentThread->ApcState.UserApcPending = TRUE;
KeReleaseDispatcherDatabaseLock(OldIrql);
return (STATUS_USER_APC);
}
} else if ((CurrentThread->ApcState.UserApcPending) && (WaitMode != KernelMode)) {
DPRINT1("Alertability failed\n");
KeReleaseDispatcherDatabaseLock(OldIrql);
return (STATUS_USER_APC);
}
/* /*
* Check if the wait is (already) satisfied * Check if the wait is (already) satisfied

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
/* $Id: page.c,v 1.75 2004/10/05 18:53:28 hbirr Exp $ /* $Id: page.c,v 1.76 2004/11/11 22:23:52 ion Exp $
* *
* PROJECT: ReactOS kernel * PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/i386/page.c * FILE: ntoskrnl/mm/i386/page.c
@ -375,7 +375,7 @@ VOID MmDeletePageTable(PEPROCESS Process, PVOID Address)
if (Process != NULL && Process != CurrentProcess) if (Process != NULL && Process != CurrentProcess)
{ {
KeAttachProcess(Process); KeAttachProcess(&Process->Pcb);
} }
if (Ke386Pae) if (Ke386Pae)
@ -408,7 +408,7 @@ VOID MmFreePageTable(PEPROCESS Process, PVOID Address)
DPRINT("ProcessId %d, Address %x\n", Process->UniqueProcessId, Address); DPRINT("ProcessId %d, Address %x\n", Process->UniqueProcessId, Address);
if (Process != NULL && Process != CurrentProcess) if (Process != NULL && Process != CurrentProcess)
{ {
KeAttachProcess(Process); KeAttachProcess(&Process->Pcb);
} }
if (Ke386Pae) if (Ke386Pae)
{ {

View file

@ -453,7 +453,7 @@ MmFreeMemoryArea(PMADDRESS_SPACE AddressSpace,
if (AddressSpace->Process != NULL && if (AddressSpace->Process != NULL &&
AddressSpace->Process != CurrentProcess) AddressSpace->Process != CurrentProcess)
{ {
KeAttachProcess(AddressSpace->Process); KeAttachProcess((PKPROCESS)AddressSpace->Process);
} }
EndAddress = (char*)MemoryArea->BaseAddress + PAGE_ROUND_UP(MemoryArea->Length); EndAddress = (char*)MemoryArea->BaseAddress + PAGE_ROUND_UP(MemoryArea->Length);
for (Address = MemoryArea->BaseAddress; Address < EndAddress; Address += PAGE_SIZE) for (Address = MemoryArea->BaseAddress; Address < EndAddress; Address += PAGE_SIZE)

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
/* $Id: virtual.c,v 1.83 2004/10/29 16:48:10 chorns Exp $ /* $Id: virtual.c,v 1.84 2004/11/11 22:23:52 ion Exp $
* *
* PROJECT: ReactOS kernel * PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/virtual.c * FILE: ntoskrnl/mm/virtual.c
@ -425,7 +425,7 @@ NtReadVirtualMemory(IN HANDLE ProcessHandle,
UserMode, UserMode,
IoWriteAccess); IoWriteAccess);
KeAttachProcess(Process); KeAttachProcess((PKPROCESS)Process);
SystemAddress = MmGetSystemAddressForMdl(Mdl); SystemAddress = MmGetSystemAddressForMdl(Mdl);
memcpy(SystemAddress, BaseAddress, NumberOfBytesToRead); memcpy(SystemAddress, BaseAddress, NumberOfBytesToRead);
@ -553,7 +553,7 @@ NtWriteVirtualMemory(IN HANDLE ProcessHandle,
ObDereferenceObject(Process); ObDereferenceObject(Process);
return(STATUS_NO_MEMORY); return(STATUS_NO_MEMORY);
} }
KeAttachProcess(Process); KeAttachProcess((PKPROCESS)Process);
SystemAddress = MmGetSystemAddressForMdl(Mdl); SystemAddress = MmGetSystemAddressForMdl(Mdl);
memcpy(BaseAddress, SystemAddress, NumberOfBytesToWrite); memcpy(BaseAddress, SystemAddress, NumberOfBytesToWrite);

View file

@ -1,4 +1,4 @@
/* $Id: psmgr.c,v 1.23 2004/09/28 15:02:29 weiden Exp $ /* $Id: psmgr.c,v 1.24 2004/11/11 22:23:52 ion Exp $
* *
* COPYRIGHT: See COPYING in the top level directory * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel * PROJECT: ReactOS kernel
@ -32,7 +32,6 @@ PiInitProcessManager(VOID)
PsInitProcessManagment(); PsInitProcessManagment();
PsInitThreadManagment(); PsInitThreadManagment();
PsInitIdleThread(); PsInitIdleThread();
PiInitApcManagement();
PsInitialiseSuspendImplementation(); PsInitialiseSuspendImplementation();
PsInitialiseW32Call(); PsInitialiseW32Call();
} }