From b4d0d3aaf0058f2e5fcce6ef197ea8b9bb56516b Mon Sep 17 00:00:00 2001 From: Gunnar Dalsnes Date: Thu, 27 Nov 2003 01:13:05 +0000 Subject: [PATCH] apc work svn path=/trunk/; revision=6807 --- reactos/include/ddk/kefuncs.h | 4 +- reactos/ntoskrnl/include/internal/ke.h | 6 ++ reactos/ntoskrnl/include/internal/ps.h | 4 +- reactos/ntoskrnl/ke/apc.c | 89 +++++++++++++++++++++++--- reactos/ntoskrnl/ke/kthread.c | 29 +++++++-- reactos/ntoskrnl/ke/process.c | 7 +- 6 files changed, 118 insertions(+), 21 deletions(-) diff --git a/reactos/include/ddk/kefuncs.h b/reactos/include/ddk/kefuncs.h index c4d8d408ff7..548856c2f39 100644 --- a/reactos/include/ddk/kefuncs.h +++ b/reactos/include/ddk/kefuncs.h @@ -103,11 +103,11 @@ struct _KTHREAD* STDCALL KeGetCurrentThread (VOID); VOID STDCALL KeInitializeApc (IN PKAPC Apc, IN PKTHREAD Thread, - IN UCHAR StateIndex, + IN KAPC_ENVIRONMENT TargetEnvironment, IN PKKERNEL_ROUTINE KernelRoutine, IN PKRUNDOWN_ROUTINE RundownRoutine, IN PKNORMAL_ROUTINE NormalRoutine, - IN UCHAR Mode, + IN KPROCESSOR_MODE Mode, IN PVOID Context); diff --git a/reactos/ntoskrnl/include/internal/ke.h b/reactos/ntoskrnl/include/internal/ke.h index c5d08dcee97..ff2a3b9a64e 100644 --- a/reactos/ntoskrnl/include/internal/ke.h +++ b/reactos/ntoskrnl/include/internal/ke.h @@ -88,6 +88,12 @@ VOID KeInit1(VOID); VOID KeInit2(VOID); BOOLEAN KiDeliverUserApc(PKTRAP_FRAME TrapFrame); + +VOID FASTCALL +KiSwapApcEnvironment( + struct _KTHREAD* Thread, + struct _KPROCESS* NewProcess); + VOID KiAddProfileEvent(KPROFILE_SOURCE Source, ULONG Pc); VOID diff --git a/reactos/ntoskrnl/include/internal/ps.h b/reactos/ntoskrnl/include/internal/ps.h index 6d3f13f797e..9cca3b45d38 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.53 2003/10/15 17:04:39 navaraf Exp $ +/* $Id: ps.h,v 1.54 2003/11/27 01:06:48 gdalsnes Exp $ * * FILE: ntoskrnl/ke/kthread.c * PURPOSE: Process manager definitions @@ -125,7 +125,7 @@ typedef struct _KTHREAD PVOID CallbackStack; /* 120 */ BOOL Win32Thread; /* 124 */ struct _KTRAP_FRAME* TrapFrame; /* 128 */ - PVOID ApcStatePointer[2]; /* 12C */ + PKAPC_STATE ApcStatePointer[2]; /* 12C */ UCHAR EnableStackSwap; /* 134 */ UCHAR LargeStack; /* 135 */ UCHAR ResourceIndex; /* 136 */ diff --git a/reactos/ntoskrnl/ke/apc.c b/reactos/ntoskrnl/ke/apc.c index b2beec63fd5..f98404cce4e 100644 --- a/reactos/ntoskrnl/ke/apc.c +++ b/reactos/ntoskrnl/ke/apc.c @@ -461,11 +461,11 @@ VOID STDCALL KeInitializeApc( IN PKAPC Apc, IN PKTHREAD Thread, - IN UCHAR StateIndex, + IN KAPC_ENVIRONMENT TargetEnvironment, IN PKKERNEL_ROUTINE KernelRoutine, - IN PKRUNDOWN_ROUTINE RundownRoutine, + IN PKRUNDOWN_ROUTINE RundownRoutine OPTIONAL, IN PKNORMAL_ROUTINE NormalRoutine, - IN UCHAR Mode, + IN KPROCESSOR_MODE Mode, IN PVOID Context) /* * FUNCTION: Initialize an APC object @@ -481,11 +481,9 @@ KeInitializeApc( * Context = Parameter to be passed to the APC routine */ { - KAPC_ENVIRONMENT Environment = (KAPC_ENVIRONMENT) StateIndex; - DPRINT("KeInitializeApc(Apc %x, Thread %x, Environment %d, " "KernelRoutine %x, RundownRoutine %x, NormalRoutine %x, Mode %d, " - "Context %x)\n",Apc,Thread,Environment,KernelRoutine,RundownRoutine, + "Context %x)\n",Apc,Thread,TargetEnvironment,KernelRoutine,RundownRoutine, NormalRoutine,Mode,Context); memset(Apc, 0, sizeof(KAPC)); @@ -498,18 +496,18 @@ KeInitializeApc( Apc->NormalContext = Context; Apc->Inserted = FALSE; - if (Environment == CurrentApcEnvironment) + if (TargetEnvironment == CurrentApcEnvironment) { Apc->ApcStateIndex = Thread->ApcStateIndex; } else { - Apc->ApcStateIndex = Environment; + Apc->ApcStateIndex = TargetEnvironment; } if (Apc->NormalRoutine != NULL) { - Apc->ApcMode = (KPROCESSOR_MODE) Mode; + Apc->ApcMode = Mode; } else { @@ -592,3 +590,76 @@ PiInitApcManagement(VOID) KeInitializeSpinLock(&PiApcLock); } + +VOID FASTCALL +KiSwapApcEnvironment( + PKTHREAD Thread, + PKPROCESS NewProcess) +{ + /* FIXME: Grab the process apc lock or the PiApcLock? And why does both exist? */ + + 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 */ + Thread->ApcState = Thread->SavedApcState; + + /* 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; + + /* + 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 + { + KEBUGCHECK(0); + } + +} + diff --git a/reactos/ntoskrnl/ke/kthread.c b/reactos/ntoskrnl/ke/kthread.c index 56154434590..b95a7ea776b 100644 --- a/reactos/ntoskrnl/ke/kthread.c +++ b/reactos/ntoskrnl/ke/kthread.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: kthread.c,v 1.42 2003/07/21 21:53:51 royce Exp $ +/* $Id: kthread.c,v 1.43 2003/11/27 01:02:23 gdalsnes Exp $ * * FILE: ntoskrnl/ke/kthread.c * PURPOSE: Microkernel thread support @@ -180,10 +180,21 @@ KeInitializeThread(PKPROCESS Process, PKTHREAD Thread, BOOLEAN First) Thread->Quantum = 0; memset(Thread->WaitBlock, 0, sizeof(KWAIT_BLOCK)*4); Thread->LegoData = 0; + /* * FIXME: Why this? */ - Thread->KernelApcDisable = 1; +// 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 +*/ + + Thread->KernelApcDisable = 0; + Thread->UserAffinity = Process->Affinity; Thread->SystemAffinityActive = 0; Thread->PowerState = 0; @@ -202,8 +213,8 @@ KeInitializeThread(PKPROCESS Process, PKTHREAD Thread, BOOLEAN First) Thread->CallbackStack = NULL; Thread->Win32Thread = 0; Thread->TrapFrame = NULL; - Thread->ApcStatePointer[0] = NULL; - Thread->ApcStatePointer[1] = NULL; + Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState; + Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState; Thread->EnableStackSwap = 0; Thread->LargeStack = 0; Thread->ResourceIndex = 0; @@ -211,9 +222,15 @@ KeInitializeThread(PKPROCESS Process, PKTHREAD Thread, BOOLEAN First) Thread->KernelTime = 0; Thread->UserTime = 0; memset(&Thread->SavedApcState, 0, sizeof(KAPC_STATE)); + + /* FIXME: is this correct? */ Thread->Alertable = 1; - Thread->ApcStateIndex = 0; - Thread->ApcQueueable = 0; + + Thread->ApcStateIndex = OriginalApcEnvironment; + + /* FIXME: not all thread are ApcQueueable! */ + Thread->ApcQueueable = TRUE; + Thread->AutoAlignment = 0; KeInitializeApc(&Thread->SuspendApc, Thread, diff --git a/reactos/ntoskrnl/ke/process.c b/reactos/ntoskrnl/ke/process.c index a95230ff08f..5f3bb42edec 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.16 2003/07/21 21:53:51 royce Exp $ +/* $Id: process.c,v 1.17 2003/11/27 01:09:10 gdalsnes Exp $ * * PROJECT: ReactOS kernel * FILE: ntoskrnl/ke/process.c @@ -62,6 +62,8 @@ KeAttachProcess (PEPROCESS Process) KeRaiseIrql(DISPATCH_LEVEL, &oldlvl); + KiSwapApcEnvironment(&CurrentThread->Tcb, &Process->Pcb); + /* The stack 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, @@ -83,7 +85,6 @@ KeAttachProcess (PEPROCESS Process) : /* no outputs */ : "r" (PageDir)); - KeLowerIrql(oldlvl); } @@ -108,6 +109,8 @@ KeDetachProcess (VOID) } KeRaiseIrql(DISPATCH_LEVEL, &oldlvl); + + KiSwapApcEnvironment(&CurrentThread->Tcb, &CurrentThread->OldProcess->Pcb); CurrentThread->ThreadsProcess = CurrentThread->OldProcess; CurrentThread->OldProcess = NULL;