new APC code ready for prime time

svn path=/trunk/; revision=865
This commit is contained in:
Phillip Susi 1999-12-12 03:56:53 +00:00
parent 53b1677997
commit 9a22766e36
4 changed files with 99 additions and 126 deletions

View file

@ -6,6 +6,7 @@
* PROGRAMMER: David Welch (welch@cwcom.net) * PROGRAMMER: David Welch (welch@cwcom.net)
* UPDATE HISTORY: * UPDATE HISTORY:
* Created 22/05/98 * Created 22/05/98
* 12/11/99: Phillip Susi: Reworked the APC code
*/ */
/* INCLUDES *****************************************************************/ /* INCLUDES *****************************************************************/
@ -20,7 +21,7 @@
#include <internal/debug.h> #include <internal/debug.h>
extern VOID KeApcProlog(VOID); extern VOID KeApcProlog(VOID);
extern KSPIN_LOCK PiThreadListLock; static KSPIN_LOCK PiApcLock;
/* PROTOTYPES ****************************************************************/ /* PROTOTYPES ****************************************************************/
@ -41,13 +42,15 @@ BOOLEAN KiTestAlert(PKTHREAD Thread,
PLIST_ENTRY current_entry; PLIST_ENTRY current_entry;
PKAPC Apc; PKAPC Apc;
PULONG Esp = (PULONG)UserContext->Esp; PULONG Esp = (PULONG)UserContext->Esp;
KIRQL oldlvl;
DPRINT("KiTestAlert(Thread %x, UserContext %x)\n"); DPRINT("KiTestAlert(Thread %x, UserContext %x)\n");
KeAcquireSpinLock( &PiApcLock, &oldlvl );
current_entry = Thread->ApcState.ApcListHead[1].Flink; current_entry = Thread->ApcState.ApcListHead[1].Flink;
if (current_entry == &Thread->ApcState.ApcListHead[1]) if (current_entry == &Thread->ApcState.ApcListHead[1])
{ {
KeReleaseSpinLock( &PiApcLock, oldlvl );
return(FALSE); return(FALSE);
} }
@ -81,19 +84,28 @@ BOOLEAN KiTestAlert(PKTHREAD Thread,
return(TRUE); return(TRUE);
} }
VOID KeApcProlog2(PKAPC Apc) VOID KeApcProlog2()
{ {
PKTHREAD Thread; PETHREAD Thread = PsGetCurrentThread();
PLIST_ENTRY current;
DPRINT("KeApcProlog2(Apc %x)\n", Apc); PKAPC Apc;
KIRQL oldlvl;
Thread = Apc->Thread;
KeLowerIrql(PASSIVE_LEVEL); DPRINT( "KeApcProlog2()\n" );
KeApcProlog3(Apc); KeLowerIrql( APC_LEVEL );
PsSuspendThread(CONTAINING_RECORD(Thread,ETHREAD,Tcb), KeAcquireSpinLock( &PiApcLock, &oldlvl );
NULL, while( !IsListEmpty( &(Thread->Tcb.ApcState.ApcListHead[0]) ) )
Thread->Alertable, {
Thread->WaitMode); DPRINT( "Delivering APC\n" );
current = RemoveTailList( &(Thread->Tcb.ApcState.ApcListHead[0]) );
KeReleaseSpinLock( &PiApcLock, oldlvl );
Apc = CONTAINING_RECORD(current, KAPC, ApcListEntry);
KeApcProlog3(Apc);
KeAcquireSpinLock( &PiApcLock, &oldlvl );
}
KeReleaseSpinLock( &PiApcLock, oldlvl );
Thread->Tcb.WaitStatus = STATUS_ALERTED;
KeLowerIrql( PASSIVE_LEVEL );
} }
VOID KeApcProlog3(PKAPC Apc) VOID KeApcProlog3(PKAPC Apc)
@ -101,72 +113,43 @@ VOID KeApcProlog3(PKAPC Apc)
* FUNCTION: This is called from the prolog proper (in assembly) to deliver * FUNCTION: This is called from the prolog proper (in assembly) to deliver
* a kernel APC * a kernel APC
*/ */
{ {
PKTHREAD Thread; PKTHREAD Thread = KeGetCurrentThread();
DPRINT("KeApcProlog3(Apc %x)\n",Apc);
InterlockedIncrement( &(Thread->ApcState.KernelApcInProgress) );
InterlockedDecrement( &(Thread->ApcState.KernelApcPending) );
DPRINT("KeApcProlog2(Apc %x)\n",Apc);
KeEnterCriticalRegion();
Apc->Thread->ApcState.KernelApcInProgress++;
Apc->Thread->ApcState.KernelApcPending--;
RemoveEntryList(&Apc->ApcListEntry);
Thread = Apc->Thread;
Apc->KernelRoutine(Apc, Apc->KernelRoutine(Apc,
&Apc->NormalRoutine, &Apc->NormalRoutine,
&Apc->NormalContext, &Apc->NormalContext,
&Apc->SystemArgument1, &Apc->SystemArgument1,
&Apc->SystemArgument2); &Apc->SystemArgument2);
Thread->ApcState.KernelApcInProgress--; InterlockedDecrement( &(Thread->ApcState.KernelApcInProgress) );
KeLeaveCriticalRegion();
} }
VOID KeDeliverKernelApc(PKAPC Apc) VOID KeDeliverKernelApc( PKTHREAD TargetThread )
/* /*
* FUNCTION: Simulates an interrupt on the target thread which will transfer * FUNCTION: Simulates an interrupt on the target thread which will transfer
* control to a kernel mode routine * control to a kernel mode routine
* Must be called while holding the PiApcLock
*/ */
{ {
PKTHREAD TargetThread;
PULONG Stack; PULONG Stack;
DPRINT("KeDeliverKernelApc(Apc %x)\n", Apc); DPRINT( "KeDeliverKernelApc( TargetThread %x)\n", TargetThread );
TargetThread = Apc->Thread;
if (TargetThread == KeGetCurrentThread()) if (TargetThread == KeGetCurrentThread())
{ {
KeApcProlog3(Apc); KeApcProlog2();
return; return;
} }
if (TargetThread->Context.cs == KERNEL_CS) TargetThread->Context.esp = TargetThread->Context.esp - 12;
{
TargetThread->Context.esp = TargetThread->Context.esp - 16;
Stack = (PULONG)TargetThread->Context.esp; Stack = (PULONG)TargetThread->Context.esp;
Stack[0] = TargetThread->Context.eax; Stack[0] = TargetThread->Context.eip;
Stack[1] = TargetThread->Context.eip; Stack[1] = TargetThread->Context.cs;
Stack[2] = TargetThread->Context.cs; Stack[2] = TargetThread->Context.eflags;
Stack[3] = TargetThread->Context.eflags;
TargetThread->Context.eip = (ULONG)KeApcProlog; TargetThread->Context.eip = (ULONG)KeApcProlog;
TargetThread->Context.eax = (ULONG)Apc;
}
else
{
TargetThread->Context.esp = TargetThread->Context.esp - 40;
Stack = (PULONG)TargetThread->Context.esp;
Stack[9] = TargetThread->Context.gs;
Stack[8] = TargetThread->Context.fs;
Stack[7] = TargetThread->Context.ds;
Stack[6] = TargetThread->Context.es;
Stack[5] = TargetThread->Context.ss;
Stack[4] = TargetThread->Context.esp;
Stack[3] = TargetThread->Context.eflags;
Stack[2] = TargetThread->Context.cs;
Stack[1] = TargetThread->Context.eip;
Stack[0] = TargetThread->Context.eax;
TargetThread->Context.eip = (ULONG)KeApcProlog;
TargetThread->Context.eax = (ULONG)Apc;
}
PsResumeThread(CONTAINING_RECORD(TargetThread,ETHREAD,Tcb), PsResumeThread(CONTAINING_RECORD(TargetThread,ETHREAD,Tcb),
NULL); NULL);
} }
@ -190,7 +173,7 @@ VOID KeInsertQueueApc(PKAPC Apc,
"SystemArgument2 %x, Mode %d)\n",Apc,SystemArgument1, "SystemArgument2 %x, Mode %d)\n",Apc,SystemArgument1,
SystemArgument2,Mode); SystemArgument2,Mode);
KeRaiseIrql(DISPATCH_LEVEL, &oldlvl); KeAcquireSpinLock( &PiApcLock, &oldlvl );
Apc->SystemArgument1 = SystemArgument1; Apc->SystemArgument1 = SystemArgument1;
Apc->SystemArgument2 = SystemArgument2; Apc->SystemArgument2 = SystemArgument2;
@ -220,10 +203,19 @@ VOID KeInsertQueueApc(PKAPC Apc,
DPRINT("TargetThread->KernelApcDisable %d\n", DPRINT("TargetThread->KernelApcDisable %d\n",
TargetThread->KernelApcDisable); TargetThread->KernelApcDisable);
DPRINT("Apc->KernelRoutine %x\n", Apc->KernelRoutine); DPRINT("Apc->KernelRoutine %x\n", Apc->KernelRoutine);
if (Apc->ApcMode == KernelMode && TargetThread->KernelApcDisable >= 1) DPRINT( "TargetThread->Altertable = %x, TargetThread->WaitIrql = %d\n", TargetThread->Alertable, TargetThread->WaitIrql );
{ if (Apc->ApcMode == KernelMode && TargetThread->KernelApcDisable >= 1 )
KeDeliverKernelApc(Apc); if( TargetThread != PsGetCurrentThread() )
{
PsSuspendThread( CONTAINING_RECORD( TargetThread, ETHREAD, Tcb ), NULL, TRUE, KernelMode );
KeReleaseSpinLock( &PiApcLock, oldlvl );
if( TargetThread->WaitIrql < APC_LEVEL )
KeDeliverKernelApc( TargetThread );
} }
else {
if( TargetThread->WaitIrql < APC_LEVEL )
KeDeliverKernelApc( TargetThread );
}
else else
{ {
DPRINT("Queuing APC for later delivery\n"); DPRINT("Queuing APC for later delivery\n");
@ -239,7 +231,6 @@ VOID KeInsertQueueApc(PKAPC Apc,
PsResumeThread((PETHREAD)TargetThread, PsResumeThread((PETHREAD)TargetThread,
&Status); &Status);
} }
KeLowerIrql(oldlvl);
} }
VOID KeInitializeApc(PKAPC Apc, VOID KeInitializeApc(PKAPC Apc,
@ -340,3 +331,9 @@ NTSTATUS STDCALL NtTestAlert(VOID)
KiTestAlert(KeGetCurrentThread(),NULL); KiTestAlert(KeGetCurrentThread(),NULL);
return(STATUS_SUCCESS); return(STATUS_SUCCESS);
} }
VOID PiInitApcManagement()
{
KeInitializeSpinLock( &PiApcLock );
}

View file

@ -3,10 +3,7 @@ void KeApcProlog(void);
__asm__("\n\t.global _KeApcProlog\n\t" __asm__("\n\t.global _KeApcProlog\n\t"
"_KeApcProlog:\n\t" "_KeApcProlog:\n\t"
"pusha\n\t" "pusha\n\t"
"pushl %eax\n\t"
"call _KeApcProlog2\n\t" "call _KeApcProlog2\n\t"
"popl %eax\n\t"
"popa\n\t" "popa\n\t"
"popl %eax\n\t"
"iret\n\t"); "iret\n\t");

View file

@ -27,5 +27,5 @@ VOID PiInitProcessManager(VOID)
PsInitProcessManagment(); PsInitProcessManagment();
PsInitThreadManagment(); PsInitThreadManagment();
PsInitIdleThread(); PsInitIdleThread();
// PiInitApcManagement(); PiInitApcManagement();
} }

View file

@ -1,4 +1,4 @@
/* $Id: thread.c,v 1.38 1999/12/12 00:59:39 dwelch Exp $ /* $Id: thread.c,v 1.39 1999/12/12 03:56:53 phreak Exp $
* *
* COPYRIGHT: See COPYING in the top level directory * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel * PROJECT: ReactOS kernel
@ -46,7 +46,7 @@ KSPIN_LOCK PiThreadListLock;
/* /*
* PURPOSE: List of threads associated with each priority level * PURPOSE: List of threads associated with each priority level
*/ */
static LIST_ENTRY PiThreadListHead; static LIST_ENTRY PiThreadListHead = { &PiThreadListHead, &PiThreadListHead };
static LIST_ENTRY PriorityListHead[NR_THREAD_PRIORITY_LEVELS]; static LIST_ENTRY PriorityListHead[NR_THREAD_PRIORITY_LEVELS];
static BOOLEAN DoneInitYet = FALSE; static BOOLEAN DoneInitYet = FALSE;
ULONG PiNrThreads = 0; ULONG PiNrThreads = 0;
@ -122,11 +122,6 @@ VOID PsDumpThreads(VOID)
PLIST_ENTRY current_entry; PLIST_ENTRY current_entry;
PETHREAD current; PETHREAD current;
if (!DoneInitYet)
{
return;
}
current_entry = PiThreadListHead.Flink; current_entry = PiThreadListHead.Flink;
while (current_entry != &PiThreadListHead) while (current_entry != &PiThreadListHead)
@ -153,8 +148,6 @@ VOID PsReapThreads(VOID)
// DPRINT1("PsReapThreads()\n"); // DPRINT1("PsReapThreads()\n");
KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
current_entry = PiThreadListHead.Flink; current_entry = PiThreadListHead.Flink;
while (current_entry != &PiThreadListHead) while (current_entry != &PiThreadListHead)
@ -171,8 +164,6 @@ VOID PsReapThreads(VOID)
ObDereferenceObject(current); ObDereferenceObject(current);
} }
} }
KeReleaseSpinLock(&PiThreadListLock, oldIrql);
} }
static PETHREAD PsScanThreadList (KPRIORITY Priority) static PETHREAD PsScanThreadList (KPRIORITY Priority)
@ -222,7 +213,6 @@ static VOID PsDispatchThreadNoLock (ULONG NewThreadStatus)
Candidate = PsScanThreadList(CurrentPriority); Candidate = PsScanThreadList(CurrentPriority);
if (Candidate == CurrentThread) if (Candidate == CurrentThread)
{ {
KeReleaseSpinLockFromDpcLevel(&PiThreadListLock);
return; return;
} }
if (Candidate != NULL) if (Candidate != NULL)
@ -233,9 +223,12 @@ static VOID PsDispatchThreadNoLock (ULONG NewThreadStatus)
CurrentThread = Candidate; CurrentThread = Candidate;
KeReleaseSpinLockFromDpcLevel(&PiThreadListLock); KeReleaseSpinLockFromDpcLevel( &PiThreadListLock );
HalTaskSwitch(&CurrentThread->Tcb); HalTaskSwitch(&CurrentThread->Tcb);
KeAcquireSpinLockAtDpcLevel( &PiThreadListLock );
DPRINT( "Woken up, grabbed lock\n" );
PsReapThreads(); PsReapThreads();
DPRINT( "Reaped\n" );
return; return;
} }
} }
@ -258,23 +251,16 @@ VOID PsDispatchThread(ULONG NewThreadStatus)
KeAcquireSpinLock(&PiThreadListLock, &oldIrql); KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
CurrentThread->Tcb.WaitIrql = oldIrql; // save wait Irql CurrentThread->Tcb.WaitIrql = oldIrql; // save wait Irql
PsDispatchThreadNoLock(NewThreadStatus); PsDispatchThreadNoLock(NewThreadStatus);
// KeReleaseSpinLock(&PiThreadListLock, oldIrql); KeReleaseSpinLock(&PiThreadListLock, oldIrql);
KeLowerIrql(oldIrql); KeLowerIrql(oldIrql);
// DPRINT("oldIrql %d\n",oldIrql); // DPRINT("oldIrql %d\n",oldIrql);
} }
static VOID PiTimeoutThread(struct _KDPC *dpc, static VOID PiTimeoutThread( struct _KDPC *dpc, PVOID Context, PVOID arg1, PVOID arg2 )
PVOID Context,
PVOID arg1,
PVOID arg2 )
{ {
/* // wake up the thread, and tell it it timed out
* wake up the thread, and tell it it timed out NTSTATUS Status = STATUS_TIMEOUT;
*/ PsResumeThread( (ETHREAD *)Context, &Status );
NTSTATUS Status = STATUS_TIMEOUT;
DPRINT("PiTimeoutThread()\n");
PsResumeThread((ETHREAD *)Context, &Status);
} }
NTSTATUS PsInitializeThread(HANDLE ProcessHandle, NTSTATUS PsInitializeThread(HANDLE ProcessHandle,
@ -347,21 +333,24 @@ NTSTATUS PsInitializeThread(HANDLE ProcessHandle,
} }
// Suspend and resume may only be called to suspend the current thread, except by apc.c
ULONG PsResumeThread(PETHREAD Thread, ULONG PsResumeThread(PETHREAD Thread,
PNTSTATUS WaitStatus) PNTSTATUS WaitStatus)
{ {
ULONG r;
KIRQL oldIrql; KIRQL oldIrql;
ULONG r;
DPRINT("PsResumeThread(Thread %x) CurrentThread %x \n",Thread, DPRINT("PsResumeThread(Thread %x) CurrentThread %x \n",Thread,
PsGetCurrentThread()); PsGetCurrentThread());
DPRINT("Thread->Tcb.SuspendCount %d\n",Thread->Tcb.SuspendCount); DPRINT("Thread->Tcb.SuspendCount %d\n",Thread->Tcb.SuspendCount);
KeAcquireSpinLock(&PiThreadListLock, &oldIrql); KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
r = InterlockedDecrement(&Thread->Tcb.SuspendCount); DPRINT("Thread->Tcb.SuspendCount %d\n",Thread->Tcb.SuspendCount);
DPRINT("r %d Thread->Tcb.SuspendCount %d\n",r,Thread->Tcb.SuspendCount); r = Thread->Tcb.SuspendCount;
if (r <= 0) if ( Thread->Tcb.SuspendCount == TRUE )
{ {
// DPRINT("Marking thread %x as runnable\n",Thread); // DPRINT("Marking thread %x as runnable\n",Thread);
Thread->Tcb.SuspendCount = FALSE;
Thread->Tcb.State = THREAD_STATE_RUNNABLE; Thread->Tcb.State = THREAD_STATE_RUNNABLE;
if (WaitStatus != NULL) if (WaitStatus != NULL)
{ {
@ -373,7 +362,7 @@ ULONG PsResumeThread(PETHREAD Thread,
DPRINT("About release ThreadListLock = %x\n", &PiThreadListLock); DPRINT("About release ThreadListLock = %x\n", &PiThreadListLock);
KeReleaseSpinLock(&PiThreadListLock, oldIrql); KeReleaseSpinLock(&PiThreadListLock, oldIrql);
DPRINT("Finished PsResumeThread()\n"); DPRINT("Finished PsResumeThread()\n");
return(r); return r;
} }
@ -382,32 +371,26 @@ ULONG PsSuspendThread(PETHREAD Thread,
UCHAR Alertable, UCHAR Alertable,
ULONG WaitMode) ULONG WaitMode)
{ {
ULONG r;
KIRQL oldIrql; KIRQL oldIrql;
ULONG r;
assert_irql(PASSIVE_LEVEL);
DPRINT("PsSuspendThread(Thread %x)\n",Thread); DPRINT("PsSuspendThread(Thread %x)\n",Thread);
DPRINT("Thread->Tcb.BasePriority %d\n", Thread->Tcb.BasePriority); DPRINT("Thread->Tcb.BasePriority %d\n", Thread->Tcb.BasePriority);
DPRINT("Thread->Tcb.SuspendCount %d\n",Thread->Tcb.SuspendCount); DPRINT("Thread->Tcb.SuspendCount %d\n",Thread->Tcb.SuspendCount);
KeAcquireSpinLock(&PiThreadListLock, &oldIrql); KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
r = InterlockedIncrement(&Thread->Tcb.SuspendCount); r = Thread->Tcb.SuspendCount;
DPRINT("r %d Thread->Tcb.SuspendCount %d\n",r,Thread->Tcb.SuspendCount); if ( Thread->Tcb.SuspendCount == FALSE )
{
if (r > 0) Thread->Tcb.SuspendCount = TRUE;
{ if (Thread != PsGetCurrentThread())
if (Thread != PsGetCurrentThread()) {
{ if (Thread->Tcb.State == THREAD_STATE_RUNNABLE)
if (Thread->Tcb.State == THREAD_STATE_RUNNABLE) RemoveEntryList(&Thread->Tcb.QueueListEntry);
{ Thread->Tcb.State = THREAD_STATE_SUSPENDED;
RemoveEntryList(&Thread->Tcb.QueueListEntry); Thread->Tcb.Alertable = Alertable;
} Thread->Tcb.WaitMode = WaitMode;
Thread->Tcb.State = THREAD_STATE_SUSPENDED; PiNrRunnableThreads--;
Thread->Tcb.Alertable = Alertable; }
Thread->Tcb.WaitMode = WaitMode;
PiNrRunnableThreads--;
KeReleaseSpinLock(&PiThreadListLock, oldIrql);
}
else else
{ {
DPRINT("Suspending current thread\n"); DPRINT("Suspending current thread\n");
@ -416,20 +399,16 @@ ULONG PsSuspendThread(PETHREAD Thread,
PiNrRunnableThreads--; PiNrRunnableThreads--;
Thread->Tcb.WaitIrql = oldIrql; // save wait IRQL Thread->Tcb.WaitIrql = oldIrql; // save wait IRQL
PsDispatchThreadNoLock(THREAD_STATE_SUSPENDED); PsDispatchThreadNoLock(THREAD_STATE_SUSPENDED);
KeLowerIrql(oldIrql);
if (WaitStatus != NULL) if (WaitStatus != NULL)
{ {
*WaitStatus = PsGetCurrentThread()->Tcb.WaitStatus; *WaitStatus = PsGetCurrentThread()->Tcb.WaitStatus;
} }
} }
} }
else
{
DPRINT("About to release ThreadListLock = %x\n", &PiThreadListLock); DPRINT("About to release ThreadListLock = %x\n", &PiThreadListLock);
KeReleaseSpinLock(&PiThreadListLock, oldIrql); KeReleaseSpinLock(&PiThreadListLock, oldIrql);
} DPRINT("PsSuspendThread() finished\n");
DPRINT("PsSuspendThread() finished\n"); return r;
return(r);
} }