diff --git a/reactos/include/ddk/kefuncs.h b/reactos/include/ddk/kefuncs.h index 98c3fe105ff..e3f30005eaa 100644 --- a/reactos/include/ddk/kefuncs.h +++ b/reactos/include/ddk/kefuncs.h @@ -20,13 +20,14 @@ KeSaveFloatingPointState( #define KeFlushIoBuffers(Mdl, ReadOperation, DmaOperation) #endif -VOID STDCALL KeAttachProcess (struct _EPROCESS* Process); +VOID STDCALL KeAttachProcess(struct _KPROCESS *Process); VOID FASTCALL KiAcquireSpinLock(PKSPIN_LOCK SpinLock); VOID FASTCALL KiReleaseSpinLock(PKSPIN_LOCK SpinLock); VOID KeDrainApcQueue(VOID); + struct _KPROCESS* KeGetCurrentProcess(VOID); /* diff --git a/reactos/include/ddk/ketypes.h b/reactos/include/ddk/ketypes.h index c50b501fdda..b4e897d238c 100644 --- a/reactos/include/ddk/ketypes.h +++ b/reactos/include/ddk/ketypes.h @@ -122,6 +122,24 @@ typedef struct _KAPC #include +#ifndef __USE_W32API + +#include + +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 + +#endif /* __USE_W32API */ + typedef struct _KBUGCHECK_CALLBACK_RECORD { LIST_ENTRY Entry; diff --git a/reactos/ntoskrnl/include/internal/ke.h b/reactos/ntoskrnl/include/internal/ke.h index 99b68718ce3..a4401777848 100644 --- a/reactos/ntoskrnl/include/internal/ke.h +++ b/reactos/ntoskrnl/include/internal/ke.h @@ -96,6 +96,10 @@ VOID KiInitializeUserApc(IN PVOID Reserved, IN PVOID SystemArgument1, 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 STDCALL KeTestAlertThread(IN KPROCESSOR_MODE AlertMode); @@ -122,10 +126,10 @@ VOID KeInit2(VOID); BOOLEAN KiDeliverUserApc(PKTRAP_FRAME TrapFrame); -VOID FASTCALL -KiSwapApcEnvironment( - struct _KTHREAD* Thread, - struct _KPROCESS* NewProcess); +VOID +STDCALL +KiMoveApcState (PKAPC_STATE OldState, + PKAPC_STATE NewState); VOID KiAddProfileEvent(KPROFILE_SOURCE Source, ULONG Pc); diff --git a/reactos/ntoskrnl/include/internal/ps.h b/reactos/ntoskrnl/include/internal/ps.h index b927292fd86..564b95e9fca 100644 --- a/reactos/ntoskrnl/include/internal/ps.h +++ b/reactos/ntoskrnl/include/internal/ps.h @@ -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.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 * PURPOSE: Process manager definitions @@ -53,24 +53,6 @@ extern HANDLE SystemProcessHandle; extern LCID PsDefaultThreadLocaleId; extern LCID PsDefaultSystemLocaleId; -#ifndef __USE_W32API - -#include - -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 - -#endif /* __USE_W32API */ - #include typedef struct _KTHREAD diff --git a/reactos/ntoskrnl/ke/apc.c b/reactos/ntoskrnl/ke/apc.c index eecdfeaad7a..882aada2001 100644 --- a/reactos/ntoskrnl/ke/apc.c +++ b/reactos/ntoskrnl/ke/apc.c @@ -123,12 +123,12 @@ KeInsertQueueApc (PKAPC Apc, PLIST_ENTRY ApcListEntry; PKAPC QueuedApc; + ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); DPRINT ("KeInsertQueueApc(Apc %x, SystemArgument1 %x, " "SystemArgument2 %x)\n",Apc,SystemArgument1, SystemArgument2); - /* FIXME: Implement Dispatcher Lock */ - OldIrql = KeRaiseIrqlToDpcLevel(); + OldIrql = KeAcquireDispatcherDatabaseLock(); /* Get the Thread specified in the APC */ Thread = Apc->Thread; @@ -136,7 +136,7 @@ KeInsertQueueApc (PKAPC Apc, /* Make sure the thread allows APC Queues */ if (Thread->ApcQueueable == FALSE) { DPRINT("Thread doesn't allow APC Queues\n"); - KeLowerIrql(OldIrql); + KeReleaseDispatcherDatabaseLock(OldIrql); return FALSE; } @@ -146,7 +146,7 @@ KeInsertQueueApc (PKAPC Apc, /* Don't do anything if the APC is already inserted */ if (Apc->Inserted) { - KeLowerIrql(OldIrql); + KeReleaseDispatcherDatabaseLock(OldIrql); return FALSE; } @@ -208,7 +208,7 @@ KeInsertQueueApc (PKAPC Apc, } /* Return Sucess if we are here */ - KeLowerIrql(OldIrql); + KeReleaseDispatcherDatabaseLock(OldIrql); return TRUE; } @@ -226,10 +226,10 @@ KeRemoveQueueApc (PKAPC Apc) KIRQL OldIrql; PKTHREAD Thread = Apc->Thread; + ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); DPRINT("KeRemoveQueueApc called for APC: %x \n", Apc); - /* FIXME: Implement Dispatcher Lock */ - OldIrql = KeRaiseIrqlToDpcLevel(); + OldIrql = KeAcquireDispatcherDatabaseLock(); KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql); /* Remove it from the Queue if it's inserted */ @@ -247,13 +247,13 @@ KeRemoveQueueApc (PKAPC Apc) } } else { KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); - KeLowerIrql(OldIrql); + KeReleaseDispatcherDatabaseLock(OldIrql); return(FALSE); } /* Restore IRQL and Return */ KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); - KeLowerIrql(OldIrql); + KeReleaseDispatcherDatabaseLock(OldIrql); return(TRUE); } @@ -269,9 +269,10 @@ KeTestAlertThread(IN KPROCESSOR_MODE AlertMode) PKTHREAD Thread = KeGetCurrentThread(); BOOLEAN OldState; - /* FIXME: Implement Dispatcher Lock */ - OldIrql = KeRaiseIrqlToDpcLevel(); - KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql); + ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); + + OldIrql = KeAcquireDispatcherDatabaseLock(); + KiAcquireSpinLock(&Thread->ApcQueueLock); OldState = Thread->Alerted[(int)AlertMode]; @@ -283,9 +284,8 @@ KeTestAlertThread(IN KPROCESSOR_MODE AlertMode) Thread->ApcState.UserApcPending = TRUE; } - /* FIXME: Implement Dispatcher Lock */ - KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); - KeLowerIrql(OldIrql); + KiReleaseSpinLock(&Thread->ApcQueueLock); + KeReleaseDispatcherDatabaseLock(OldIrql); return OldState; } @@ -444,12 +444,25 @@ KiDeliverApc(KPROCESSOR_MODE PreviousMode, } } -VOID KiInitializeUserApc(IN PVOID Reserved, - IN PKTRAP_FRAME TrapFrame, - IN PKNORMAL_ROUTINE NormalRoutine, - IN PVOID NormalContext, - IN PVOID SystemArgument1, - IN PVOID SystemArgument2) +VOID +STDCALL +KiFreeApcRoutine(PKAPC Apc, + PKNORMAL_ROUTINE* NormalRoutine, + PVOID* NormalContext, + 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 */ @@ -508,77 +521,87 @@ KeAreApcsDisabled( VOID ) { - return KeGetCurrentThread()->KernelApcDisable ? FALSE : TRUE; + return KeGetCurrentThread()->KernelApcDisable ? TRUE : FALSE; } -VOID STDCALL -NtQueueApcRundownRoutine(PKAPC Apc) -{ - ExFreePool(Apc); -} - -VOID STDCALL -NtQueueApcKernelRoutine(PKAPC Apc, - PKNORMAL_ROUTINE* NormalRoutine, - PVOID* NormalContext, - PVOID* SystemArgument1, - PVOID* SystemArgument2) -{ - ExFreePool(Apc); -} - -NTSTATUS STDCALL +NTSTATUS +STDCALL NtQueueApcThread(HANDLE ThreadHandle, PKNORMAL_ROUTINE ApcRoutine, PVOID NormalContext, PVOID SystemArgument1, 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, - THREAD_ALL_ACCESS, /* FIXME */ - PsThreadType, - UserMode, - &ThreadVar, - NULL); - if (!NT_SUCCESS(Status)) - { - return(Status); - } + /* Allocate an APC */ + Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG_KAPC); + if (Apc == NULL) { + ObDereferenceObject(Thread); + return(STATUS_NO_MEMORY); + } - Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG_KAPC); - if (Apc == NULL) - { + /* Initialize and Queue */ + 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); - return(STATUS_NO_MEMORY); - } - - KeInitializeApc(Apc, - &Thread->Tcb, - OriginalApcEnvironment, - NtQueueApcKernelRoutine, - NtQueueApcRundownRoutine, - ApcRoutine, - UserMode, - NormalContext); - KeInsertQueueApc(Apc, - SystemArgument1, - SystemArgument2, - IO_NO_INCREMENT); - - ObDereferenceObject(Thread); - return(STATUS_SUCCESS); + return Status; } - -NTSTATUS STDCALL NtTestAlert(VOID) +NTSTATUS +STDCALL +NtTestAlert(VOID) { + /* Check and Alert Thread if needed */ if (KeTestAlertThread(KeGetPreviousMode())) { return STATUS_ALERTED; } else { @@ -586,103 +609,31 @@ NTSTATUS STDCALL NtTestAlert(VOID) } } -VOID INIT_FUNCTION -PiInitApcManagement(VOID) +static inline VOID RepairList(PLIST_ENTRY Original, + 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 -RepairList(PLIST_ENTRY Original, PLIST_ENTRY Copy, int Mode) +VOID +STDCALL +KiMoveApcState (PKAPC_STATE OldState, + PKAPC_STATE NewState) { - if (IsListEmpty(&Original[Mode])) - { - 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 */ + *NewState = *OldState; - /* restore backup of original environment */ - Thread->ApcState = Thread->SavedApcState; - /* repair lists */ - 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); - } + /* Repair Lists */ + RepairList(NewState->ApcListHead, OldState->ApcListHead, KernelMode); + RepairList(NewState->ApcListHead, OldState->ApcListHead, UserMode); } diff --git a/reactos/ntoskrnl/ke/process.c b/reactos/ntoskrnl/ke/process.c index fbd28bcc13b..e6d3fe04813 100644 --- a/reactos/ntoskrnl/ke/process.c +++ b/reactos/ntoskrnl/ke/process.c @@ -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: 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 * FILE: ntoskrnl/ke/process.c @@ -38,79 +38,95 @@ /* * @implemented */ -VOID STDCALL -KeAttachProcess (PEPROCESS Process) +VOID +STDCALL +KeAttachProcess(PKPROCESS Process) { - KIRQL oldlvl; - PETHREAD CurrentThread; - ULONG PageDir; - - DPRINT("KeAttachProcess(Process %x)\n",Process); - - CurrentThread = PsGetCurrentThread(); - - if (&CurrentThread->ThreadsProcess->Pcb != CurrentThread->Tcb.ApcState.Process) - { - DPRINT1("Invalid attach (thread is already attached)\n"); - KEBUGCHECK(INVALID_PROCESS_ATTACH_ATTEMPT); - } - if (&Process->Pcb == CurrentThread->Tcb.ApcState.Process) - { - DPRINT1("Invalid attach (process is the same)\n"); - KEBUGCHECK(INVALID_PROCESS_ATTACH_ATTEMPT); - } - - - /* 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); + KIRQL OldIrql; + PKTHREAD Thread = KeGetCurrentThread(); + + DPRINT("KeAttachProcess: %x\n", Process); + + /* Lock Dispatcher */ + OldIrql = KeAcquireDispatcherDatabaseLock(); + + /* Crash system if DPC is being executed! */ + if (KeIsExecutingDpc()) { + DPRINT1("Invalid attach (Thread is executing a DPC!)\n"); + KEBUGCHECK(INVALID_PROCESS_ATTACH_ATTEMPT); + } + + /* Check if the Target Process is already attached */ + if (Thread->ApcState.Process == Process || Thread->ApcStateIndex != OriginalApcEnvironment) { + DPRINT("Process already Attached. Exitting\n"); + KeReleaseDispatcherDatabaseLock(OldIrql); + } else { + KiAttachProcess(Thread, Process, OldIrql, &Thread->SavedApcState); + } } -/* - * @implemented - */ -VOID STDCALL -KeDetachProcess (VOID) +VOID +STDCALL +KiAttachProcess(PKTHREAD Thread, PKPROCESS Process, KIRQL ApcLock, PRKAPC_STATE SavedApcState) { - KIRQL oldlvl; - PETHREAD CurrentThread; - ULONG PageDir; + + DPRINT("KiAttachProcess(Thread: %x, Process: %x, SavedApcState: %x\n", Thread, Process, SavedApcState); - DPRINT("KeDetachProcess()\n"); - - CurrentThread = PsGetCurrentThread(); + /* 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((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) - { - DPRINT1("Invalid detach (thread was not attached)\n"); - KEBUGCHECK(INVALID_PROCESS_DETACH_ATTEMPT); - } - - KeRaiseIrql(DISPATCH_LEVEL, &oldlvl); +VOID +STDCALL +KiSwapProcess(PKPROCESS NewProcess, PKPROCESS OldProcess) +{ + //PKPCR Pcr = KeGetCurrentKpcr(); - KiSwapApcEnvironment(&CurrentThread->Tcb, CurrentThread->Tcb.SavedApcState.Process); - PageDir = CurrentThread->Tcb.ApcState.Process->DirectoryTableBase.u.LowPart; - Ke386SetPageTableDirectory(PageDir); - - KeLowerIrql(oldlvl); + /* Do they have an LDT? */ + if ((NewProcess->LdtDescriptor) || (OldProcess->LdtDescriptor)) { + /* FIXME : SWitch GDT/IDT */ + } + 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; - PKTHREAD Thread; + PKTHREAD Thread = KeGetCurrentThread(); OldIrql = KeAcquireDispatcherDatabaseLock(); - Thread = KeGetCurrentThread(); /* Crash system if DPC is being executed! */ if (KeIsExecutingDpc()) { @@ -151,16 +166,53 @@ KeStackAttachProcess ( if (Thread->ApcState.Process == Process) { ApcState->Process = (PKPROCESS)1; /* Meaning already attached to the same Process */ } else { - /* Check if the Current Thread is already attached */ - if (Thread->ApcStateIndex != 0) { - KeAttachProcess((PEPROCESS)Process); /* FIXME: Re-write function to support stackability and fix it not to use EPROCESS */ + /* Check if the Current Thread is already attached and call the Internal Function*/ + if (Thread->ApcStateIndex != OriginalApcEnvironment) { + KiAttachProcess(Thread, Process, OldIrql, ApcState); } else { - KeAttachProcess((PEPROCESS)Process); - ApcState->Process = NULL; /* FIXME: Re-write function to support stackability and fix it not to use EPROCESS */ + KiAttachProcess(Thread, Process, OldIrql, &Thread->SavedApcState); + 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); } @@ -175,7 +227,6 @@ KeUnstackDetachProcess ( { KIRQL OldIrql; 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 (ApcState->Process == (PKPROCESS)1) return; @@ -184,7 +235,7 @@ KeUnstackDetachProcess ( OldIrql = KeAcquireDispatcherDatabaseLock(); /* 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"); KEBUGCHECK(INVALID_PROCESS_DETACH_ATTEMPT); } @@ -196,15 +247,16 @@ KeUnstackDetachProcess ( /* The ApcState parameter is useless, so use the saved data and reset it */ RtlMoveMemory(&Thread->SavedApcState, &Thread->ApcState, sizeof(KAPC_STATE)); Thread->SavedApcState.Process = NULL; - Thread->ApcStateIndex = 0; - Thread->ApcStatePointer[0] = &Thread->ApcState; - Thread->ApcStatePointer[1] = &Thread->SavedApcState; + Thread->ApcStateIndex = OriginalApcEnvironment; + Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState; + Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState; } - /* Do the Actual Swap */ - KiSwapApcEnvironment(Thread, Thread->SavedApcState.Process); - PageDir = Thread->ApcState.Process->DirectoryTableBase.u.LowPart; - Ke386SetPageTableDirectory(PageDir); + /* Restore the APC State */ + KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState); + + /* Swap Processes */ + KiSwapProcess(Thread->ApcState.Process, Thread->ApcState.Process); /* Return to old IRQL*/ KeReleaseDispatcherDatabaseLock(OldIrql); diff --git a/reactos/ntoskrnl/ke/wait.c b/reactos/ntoskrnl/ke/wait.c index 7d0bae8f220..770bd960091 100644 --- a/reactos/ntoskrnl/ke/wait.c +++ b/reactos/ntoskrnl/ke/wait.c @@ -197,9 +197,6 @@ VOID KeRemoveAllWaitsThread(PETHREAD Thread, NTSTATUS WaitStatus, BOOL Unblock) { PKWAIT_BLOCK WaitBlock, PrevWaitBlock; BOOLEAN WasWaiting = FALSE; - KIRQL OldIrql; - - OldIrql = KeAcquireDispatcherDatabaseLock (); WaitBlock = (PKWAIT_BLOCK)Thread->Tcb.WaitBlockList; if (WaitBlock != NULL) @@ -223,8 +220,6 @@ VOID KeRemoveAllWaitsThread(PETHREAD Thread, NTSTATUS WaitStatus, BOOL Unblock) { PsUnblockThread(Thread, &WaitStatus); } - - KeReleaseDispatcherDatabaseLock (OldIrql); } static BOOLEAN @@ -542,15 +537,40 @@ KeWaitForMultipleObjects(ULONG Count, OldIrql = KeAcquireDispatcherDatabaseLock (); } - /* - * If we are going to wait alertably and a user apc is pending - * then return + /* Alertability 101 + * ---------------- + * 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())) - { - KeReleaseDispatcherDatabaseLock(OldIrql); - return (STATUS_USER_APC); - } + if (Alertable) { + if (CurrentThread->Alerted[(int)WaitMode]) { + CurrentThread->Alerted[(int)WaitMode] = FALSE; + 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 diff --git a/reactos/ntoskrnl/mm/i386/page.c b/reactos/ntoskrnl/mm/i386/page.c index 73a2806a68a..156df05e36e 100644 --- a/reactos/ntoskrnl/mm/i386/page.c +++ b/reactos/ntoskrnl/mm/i386/page.c @@ -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: 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 * FILE: ntoskrnl/mm/i386/page.c @@ -375,7 +375,7 @@ VOID MmDeletePageTable(PEPROCESS Process, PVOID Address) if (Process != NULL && Process != CurrentProcess) { - KeAttachProcess(Process); + KeAttachProcess(&Process->Pcb); } if (Ke386Pae) @@ -408,7 +408,7 @@ VOID MmFreePageTable(PEPROCESS Process, PVOID Address) DPRINT("ProcessId %d, Address %x\n", Process->UniqueProcessId, Address); if (Process != NULL && Process != CurrentProcess) { - KeAttachProcess(Process); + KeAttachProcess(&Process->Pcb); } if (Ke386Pae) { diff --git a/reactos/ntoskrnl/mm/marea.c b/reactos/ntoskrnl/mm/marea.c index 57f8c231650..96b2e181ed4 100644 --- a/reactos/ntoskrnl/mm/marea.c +++ b/reactos/ntoskrnl/mm/marea.c @@ -453,7 +453,7 @@ MmFreeMemoryArea(PMADDRESS_SPACE AddressSpace, if (AddressSpace->Process != NULL && AddressSpace->Process != CurrentProcess) { - KeAttachProcess(AddressSpace->Process); + KeAttachProcess((PKPROCESS)AddressSpace->Process); } EndAddress = (char*)MemoryArea->BaseAddress + PAGE_ROUND_UP(MemoryArea->Length); for (Address = MemoryArea->BaseAddress; Address < EndAddress; Address += PAGE_SIZE) diff --git a/reactos/ntoskrnl/mm/virtual.c b/reactos/ntoskrnl/mm/virtual.c index 443bddc773d..810d41ac642 100644 --- a/reactos/ntoskrnl/mm/virtual.c +++ b/reactos/ntoskrnl/mm/virtual.c @@ -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: 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 * FILE: ntoskrnl/mm/virtual.c @@ -425,7 +425,7 @@ NtReadVirtualMemory(IN HANDLE ProcessHandle, UserMode, IoWriteAccess); - KeAttachProcess(Process); + KeAttachProcess((PKPROCESS)Process); SystemAddress = MmGetSystemAddressForMdl(Mdl); memcpy(SystemAddress, BaseAddress, NumberOfBytesToRead); @@ -553,7 +553,7 @@ NtWriteVirtualMemory(IN HANDLE ProcessHandle, ObDereferenceObject(Process); return(STATUS_NO_MEMORY); } - KeAttachProcess(Process); + KeAttachProcess((PKPROCESS)Process); SystemAddress = MmGetSystemAddressForMdl(Mdl); memcpy(BaseAddress, SystemAddress, NumberOfBytesToWrite); diff --git a/reactos/ntoskrnl/ps/psmgr.c b/reactos/ntoskrnl/ps/psmgr.c index 565be8bbd8c..aec122f2e7f 100644 --- a/reactos/ntoskrnl/ps/psmgr.c +++ b/reactos/ntoskrnl/ps/psmgr.c @@ -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 * PROJECT: ReactOS kernel @@ -32,7 +32,6 @@ PiInitProcessManager(VOID) PsInitProcessManagment(); PsInitThreadManagment(); PsInitIdleThread(); - PiInitApcManagement(); PsInitialiseSuspendImplementation(); PsInitialiseW32Call(); }