diff --git a/reactos/ntoskrnl/ke/apc.c b/reactos/ntoskrnl/ke/apc.c index 9520d47d476..61a1902bc42 100644 --- a/reactos/ntoskrnl/ke/apc.c +++ b/reactos/ntoskrnl/ke/apc.c @@ -6,6 +6,7 @@ * PROGRAMMER: David Welch (welch@cwcom.net) * UPDATE HISTORY: * Created 22/05/98 + * 12/11/99: Phillip Susi: Reworked the APC code */ /* INCLUDES *****************************************************************/ @@ -20,7 +21,7 @@ #include extern VOID KeApcProlog(VOID); -extern KSPIN_LOCK PiThreadListLock; +static KSPIN_LOCK PiApcLock; /* PROTOTYPES ****************************************************************/ @@ -41,13 +42,15 @@ BOOLEAN KiTestAlert(PKTHREAD Thread, PLIST_ENTRY current_entry; PKAPC Apc; PULONG Esp = (PULONG)UserContext->Esp; + KIRQL oldlvl; DPRINT("KiTestAlert(Thread %x, UserContext %x)\n"); - + KeAcquireSpinLock( &PiApcLock, &oldlvl ); current_entry = Thread->ApcState.ApcListHead[1].Flink; if (current_entry == &Thread->ApcState.ApcListHead[1]) { + KeReleaseSpinLock( &PiApcLock, oldlvl ); return(FALSE); } @@ -81,19 +84,28 @@ BOOLEAN KiTestAlert(PKTHREAD Thread, return(TRUE); } -VOID KeApcProlog2(PKAPC Apc) +VOID KeApcProlog2() { - PKTHREAD Thread; - - DPRINT("KeApcProlog2(Apc %x)\n", Apc); - - Thread = Apc->Thread; - KeLowerIrql(PASSIVE_LEVEL); - KeApcProlog3(Apc); - PsSuspendThread(CONTAINING_RECORD(Thread,ETHREAD,Tcb), - NULL, - Thread->Alertable, - Thread->WaitMode); + PETHREAD Thread = PsGetCurrentThread(); + PLIST_ENTRY current; + PKAPC Apc; + KIRQL oldlvl; + + DPRINT( "KeApcProlog2()\n" ); + KeLowerIrql( APC_LEVEL ); + KeAcquireSpinLock( &PiApcLock, &oldlvl ); + while( !IsListEmpty( &(Thread->Tcb.ApcState.ApcListHead[0]) ) ) + { + 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) @@ -101,72 +113,43 @@ VOID KeApcProlog3(PKAPC Apc) * FUNCTION: This is called from the prolog proper (in assembly) to deliver * 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->NormalRoutine, &Apc->NormalContext, &Apc->SystemArgument1, &Apc->SystemArgument2); - Thread->ApcState.KernelApcInProgress--; - KeLeaveCriticalRegion(); + InterlockedDecrement( &(Thread->ApcState.KernelApcInProgress) ); } -VOID KeDeliverKernelApc(PKAPC Apc) +VOID KeDeliverKernelApc( PKTHREAD TargetThread ) /* * FUNCTION: Simulates an interrupt on the target thread which will transfer * control to a kernel mode routine + * Must be called while holding the PiApcLock */ { - PKTHREAD TargetThread; PULONG Stack; - DPRINT("KeDeliverKernelApc(Apc %x)\n", Apc); - - TargetThread = Apc->Thread; - + DPRINT( "KeDeliverKernelApc( TargetThread %x)\n", TargetThread ); if (TargetThread == KeGetCurrentThread()) { - KeApcProlog3(Apc); + KeApcProlog2(); return; } - if (TargetThread->Context.cs == KERNEL_CS) - { - TargetThread->Context.esp = TargetThread->Context.esp - 16; + TargetThread->Context.esp = TargetThread->Context.esp - 12; Stack = (PULONG)TargetThread->Context.esp; - Stack[0] = TargetThread->Context.eax; - Stack[1] = TargetThread->Context.eip; - Stack[2] = TargetThread->Context.cs; - Stack[3] = TargetThread->Context.eflags; + Stack[0] = TargetThread->Context.eip; + Stack[1] = TargetThread->Context.cs; + Stack[2] = TargetThread->Context.eflags; 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), NULL); } @@ -190,7 +173,7 @@ VOID KeInsertQueueApc(PKAPC Apc, "SystemArgument2 %x, Mode %d)\n",Apc,SystemArgument1, SystemArgument2,Mode); - KeRaiseIrql(DISPATCH_LEVEL, &oldlvl); + KeAcquireSpinLock( &PiApcLock, &oldlvl ); Apc->SystemArgument1 = SystemArgument1; Apc->SystemArgument2 = SystemArgument2; @@ -220,10 +203,19 @@ VOID KeInsertQueueApc(PKAPC Apc, DPRINT("TargetThread->KernelApcDisable %d\n", TargetThread->KernelApcDisable); DPRINT("Apc->KernelRoutine %x\n", Apc->KernelRoutine); - if (Apc->ApcMode == KernelMode && TargetThread->KernelApcDisable >= 1) - { - KeDeliverKernelApc(Apc); + DPRINT( "TargetThread->Altertable = %x, TargetThread->WaitIrql = %d\n", TargetThread->Alertable, TargetThread->WaitIrql ); + if (Apc->ApcMode == KernelMode && TargetThread->KernelApcDisable >= 1 ) + 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 { DPRINT("Queuing APC for later delivery\n"); @@ -239,7 +231,6 @@ VOID KeInsertQueueApc(PKAPC Apc, PsResumeThread((PETHREAD)TargetThread, &Status); } - KeLowerIrql(oldlvl); } VOID KeInitializeApc(PKAPC Apc, @@ -340,3 +331,9 @@ NTSTATUS STDCALL NtTestAlert(VOID) KiTestAlert(KeGetCurrentThread(),NULL); return(STATUS_SUCCESS); } + +VOID PiInitApcManagement() +{ + KeInitializeSpinLock( &PiApcLock ); +} + diff --git a/reactos/ntoskrnl/ke/apchelp.c b/reactos/ntoskrnl/ke/apchelp.c index 8787a828b61..49afda2e128 100644 --- a/reactos/ntoskrnl/ke/apchelp.c +++ b/reactos/ntoskrnl/ke/apchelp.c @@ -3,10 +3,7 @@ void KeApcProlog(void); __asm__("\n\t.global _KeApcProlog\n\t" "_KeApcProlog:\n\t" "pusha\n\t" - "pushl %eax\n\t" "call _KeApcProlog2\n\t" - "popl %eax\n\t" "popa\n\t" - "popl %eax\n\t" "iret\n\t"); diff --git a/reactos/ntoskrnl/ps/psmgr.c b/reactos/ntoskrnl/ps/psmgr.c index 88fae138df7..e9fe4d4b867 100644 --- a/reactos/ntoskrnl/ps/psmgr.c +++ b/reactos/ntoskrnl/ps/psmgr.c @@ -27,5 +27,5 @@ VOID PiInitProcessManager(VOID) PsInitProcessManagment(); PsInitThreadManagment(); PsInitIdleThread(); -// PiInitApcManagement(); + PiInitApcManagement(); } diff --git a/reactos/ntoskrnl/ps/thread.c b/reactos/ntoskrnl/ps/thread.c index cbc59bc4ceb..e12ad921273 100644 --- a/reactos/ntoskrnl/ps/thread.c +++ b/reactos/ntoskrnl/ps/thread.c @@ -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 * PROJECT: ReactOS kernel @@ -46,7 +46,7 @@ KSPIN_LOCK PiThreadListLock; /* * 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 BOOLEAN DoneInitYet = FALSE; ULONG PiNrThreads = 0; @@ -122,11 +122,6 @@ VOID PsDumpThreads(VOID) PLIST_ENTRY current_entry; PETHREAD current; - if (!DoneInitYet) - { - return; - } - current_entry = PiThreadListHead.Flink; while (current_entry != &PiThreadListHead) @@ -153,8 +148,6 @@ VOID PsReapThreads(VOID) // DPRINT1("PsReapThreads()\n"); - KeAcquireSpinLock(&PiThreadListLock, &oldIrql); - current_entry = PiThreadListHead.Flink; while (current_entry != &PiThreadListHead) @@ -171,8 +164,6 @@ VOID PsReapThreads(VOID) ObDereferenceObject(current); } } - - KeReleaseSpinLock(&PiThreadListLock, oldIrql); } static PETHREAD PsScanThreadList (KPRIORITY Priority) @@ -222,7 +213,6 @@ static VOID PsDispatchThreadNoLock (ULONG NewThreadStatus) Candidate = PsScanThreadList(CurrentPriority); if (Candidate == CurrentThread) { - KeReleaseSpinLockFromDpcLevel(&PiThreadListLock); return; } if (Candidate != NULL) @@ -233,9 +223,12 @@ static VOID PsDispatchThreadNoLock (ULONG NewThreadStatus) CurrentThread = Candidate; - KeReleaseSpinLockFromDpcLevel(&PiThreadListLock); - HalTaskSwitch(&CurrentThread->Tcb); + KeReleaseSpinLockFromDpcLevel( &PiThreadListLock ); + HalTaskSwitch(&CurrentThread->Tcb); + KeAcquireSpinLockAtDpcLevel( &PiThreadListLock ); + DPRINT( "Woken up, grabbed lock\n" ); PsReapThreads(); + DPRINT( "Reaped\n" ); return; } } @@ -258,23 +251,16 @@ VOID PsDispatchThread(ULONG NewThreadStatus) KeAcquireSpinLock(&PiThreadListLock, &oldIrql); CurrentThread->Tcb.WaitIrql = oldIrql; // save wait Irql PsDispatchThreadNoLock(NewThreadStatus); -// KeReleaseSpinLock(&PiThreadListLock, oldIrql); + KeReleaseSpinLock(&PiThreadListLock, oldIrql); KeLowerIrql(oldIrql); // DPRINT("oldIrql %d\n",oldIrql); } -static VOID PiTimeoutThread(struct _KDPC *dpc, - PVOID Context, - PVOID arg1, - PVOID arg2 ) +static VOID PiTimeoutThread( struct _KDPC *dpc, PVOID Context, PVOID arg1, PVOID arg2 ) { - /* - * wake up the thread, and tell it it timed out - */ - NTSTATUS Status = STATUS_TIMEOUT; - - DPRINT("PiTimeoutThread()\n"); - PsResumeThread((ETHREAD *)Context, &Status); + // wake up the thread, and tell it it timed out + NTSTATUS Status = STATUS_TIMEOUT; + PsResumeThread( (ETHREAD *)Context, &Status ); } 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, PNTSTATUS WaitStatus) { - ULONG r; KIRQL oldIrql; - + ULONG r; + DPRINT("PsResumeThread(Thread %x) CurrentThread %x \n",Thread, PsGetCurrentThread()); DPRINT("Thread->Tcb.SuspendCount %d\n",Thread->Tcb.SuspendCount); KeAcquireSpinLock(&PiThreadListLock, &oldIrql); - r = InterlockedDecrement(&Thread->Tcb.SuspendCount); - DPRINT("r %d Thread->Tcb.SuspendCount %d\n",r,Thread->Tcb.SuspendCount); - if (r <= 0) + DPRINT("Thread->Tcb.SuspendCount %d\n",Thread->Tcb.SuspendCount); + r = Thread->Tcb.SuspendCount; + if ( Thread->Tcb.SuspendCount == TRUE ) { // DPRINT("Marking thread %x as runnable\n",Thread); + Thread->Tcb.SuspendCount = FALSE; Thread->Tcb.State = THREAD_STATE_RUNNABLE; if (WaitStatus != NULL) { @@ -373,7 +362,7 @@ ULONG PsResumeThread(PETHREAD Thread, DPRINT("About release ThreadListLock = %x\n", &PiThreadListLock); KeReleaseSpinLock(&PiThreadListLock, oldIrql); DPRINT("Finished PsResumeThread()\n"); - return(r); + return r; } @@ -382,32 +371,26 @@ ULONG PsSuspendThread(PETHREAD Thread, UCHAR Alertable, ULONG WaitMode) { - ULONG r; KIRQL oldIrql; - - assert_irql(PASSIVE_LEVEL); + ULONG r; DPRINT("PsSuspendThread(Thread %x)\n",Thread); DPRINT("Thread->Tcb.BasePriority %d\n", Thread->Tcb.BasePriority); DPRINT("Thread->Tcb.SuspendCount %d\n",Thread->Tcb.SuspendCount); KeAcquireSpinLock(&PiThreadListLock, &oldIrql); - r = InterlockedIncrement(&Thread->Tcb.SuspendCount); - DPRINT("r %d Thread->Tcb.SuspendCount %d\n",r,Thread->Tcb.SuspendCount); - - if (r > 0) - { - if (Thread != PsGetCurrentThread()) - { - if (Thread->Tcb.State == THREAD_STATE_RUNNABLE) - { - RemoveEntryList(&Thread->Tcb.QueueListEntry); - } - Thread->Tcb.State = THREAD_STATE_SUSPENDED; - Thread->Tcb.Alertable = Alertable; - Thread->Tcb.WaitMode = WaitMode; - PiNrRunnableThreads--; - KeReleaseSpinLock(&PiThreadListLock, oldIrql); - } + r = Thread->Tcb.SuspendCount; + if ( Thread->Tcb.SuspendCount == FALSE ) + { + Thread->Tcb.SuspendCount = TRUE; + if (Thread != PsGetCurrentThread()) + { + if (Thread->Tcb.State == THREAD_STATE_RUNNABLE) + RemoveEntryList(&Thread->Tcb.QueueListEntry); + Thread->Tcb.State = THREAD_STATE_SUSPENDED; + Thread->Tcb.Alertable = Alertable; + Thread->Tcb.WaitMode = WaitMode; + PiNrRunnableThreads--; + } else { DPRINT("Suspending current thread\n"); @@ -416,20 +399,16 @@ ULONG PsSuspendThread(PETHREAD Thread, PiNrRunnableThreads--; Thread->Tcb.WaitIrql = oldIrql; // save wait IRQL PsDispatchThreadNoLock(THREAD_STATE_SUSPENDED); - KeLowerIrql(oldIrql); if (WaitStatus != NULL) { *WaitStatus = PsGetCurrentThread()->Tcb.WaitStatus; } } - } - else - { + } DPRINT("About to release ThreadListLock = %x\n", &PiThreadListLock); KeReleaseSpinLock(&PiThreadListLock, oldIrql); - } - DPRINT("PsSuspendThread() finished\n"); - return(r); + DPRINT("PsSuspendThread() finished\n"); + return r; }