From d41145488c605bbfa1d5f9b31b2706238fe7af20 Mon Sep 17 00:00:00 2001 From: David Welch Date: Tue, 17 Apr 2001 23:39:26 +0000 Subject: [PATCH] SMP scheduling fixes Obey thread affinity Fix bogus invariant in KeAcquireSpinLockAtDpcLevel Protect display with spinlock svn path=/trunk/; revision=1809 --- reactos/ntoskrnl/.cvsignore | 1 + reactos/ntoskrnl/hal/x86/display.c | 91 +++++++++++++------------- reactos/ntoskrnl/hal/x86/mp.c | 99 +++++++++++++++-------------- reactos/ntoskrnl/ke/i386/kernel.c | 4 ++ reactos/ntoskrnl/ke/i386/v86m_sup.S | 4 +- reactos/ntoskrnl/ke/main.c | 11 ++-- reactos/ntoskrnl/ke/spinlock.c | 12 ++-- reactos/ntoskrnl/ke/timer.c | 14 +--- reactos/ntoskrnl/ps/idle.c | 22 ++++--- reactos/ntoskrnl/ps/thread.c | 47 ++++++++------ reactos/ntoskrnl/ps/tinfo.c | 2 +- 11 files changed, 164 insertions(+), 143 deletions(-) diff --git a/reactos/ntoskrnl/.cvsignore b/reactos/ntoskrnl/.cvsignore index dfcf970115b..8bcac6af7e8 100644 --- a/reactos/ntoskrnl/.cvsignore +++ b/reactos/ntoskrnl/.cvsignore @@ -7,3 +7,4 @@ depends depends.exe mkconfig mkconfig.exe +ntoskrnl.dbg diff --git a/reactos/ntoskrnl/hal/x86/display.c b/reactos/ntoskrnl/hal/x86/display.c index 3e2740f0795..6dc29759ef5 100644 --- a/reactos/ntoskrnl/hal/x86/display.c +++ b/reactos/ntoskrnl/hal/x86/display.c @@ -1,4 +1,4 @@ -/* $Id: display.c,v 1.12 2001/03/16 18:11:21 dwelch Exp $ +/* $Id: display.c,v 1.13 2001/04/17 23:39:25 dwelch Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -179,11 +179,8 @@ HalAcquireDisplayOwnership ( } -VOID -STDCALL -HalDisplayString ( - IN PCH String - ) +VOID STDCALL +HalDisplayString (IN PCH String) /* * FUNCTION: Switches the screen to HAL console mode (BSOD) if not there * already and displays a string @@ -193,64 +190,70 @@ HalDisplayString ( * mode */ { - PCH pch; + PCH pch; #ifdef SCREEN_SYNCHRONIZATION - int offset; + int offset; #endif + static KSPIN_LOCK Lock; - pch = String; + pch = String; - if (HalOwnsDisplay == FALSE) + __asm__ ("cli\n\t"); + KeAcquireSpinLockAtDpcLevel(&Lock); + + if (HalOwnsDisplay == FALSE) { - HalResetDisplay (); + HalResetDisplay (); } - + #ifdef SCREEN_SYNCHRONIZATION - WRITE_PORT_UCHAR((PUCHAR)CRTC_COMMAND, CRTC_CURHI); - offset = READ_PORT_UCHAR((PUCHAR)CRTC_DATA)<<8; - WRITE_PORT_UCHAR((PUCHAR)CRTC_COMMAND, CRTC_CURLO); - offset += READ_PORT_UCHAR((PUCHAR)CRTC_DATA); - - CursorY = offset / SizeX; - CursorX = offset % SizeX; + WRITE_PORT_UCHAR((PUCHAR)CRTC_COMMAND, CRTC_CURHI); + offset = READ_PORT_UCHAR((PUCHAR)CRTC_DATA)<<8; + WRITE_PORT_UCHAR((PUCHAR)CRTC_COMMAND, CRTC_CURLO); + offset += READ_PORT_UCHAR((PUCHAR)CRTC_DATA); + + CursorY = offset / SizeX; + CursorX = offset % SizeX; #endif - - while (*pch != 0) + + while (*pch != 0) { - if (*pch == '\n') + if (*pch == '\n') { - CursorY++; - CursorX = 0; + CursorY++; + CursorX = 0; } - else + else { - HalPutCharacter (*pch); - CursorX++; - - if (CursorX >= SizeX) + HalPutCharacter (*pch); + CursorX++; + + if (CursorX >= SizeX) { - CursorY++; - CursorX = 0; + CursorY++; + CursorX = 0; } } - - if (CursorY >= SizeY) + + if (CursorY >= SizeY) { - HalScrollDisplay (); - CursorY = SizeY - 1; + HalScrollDisplay (); + CursorY = SizeY - 1; } - - pch++; + + pch++; } - + #ifdef SCREEN_SYNCHRONIZATION - offset = (CursorY * SizeX) + CursorX; - - WRITE_PORT_UCHAR((PUCHAR)CRTC_COMMAND, CRTC_CURLO); - WRITE_PORT_UCHAR((PUCHAR)CRTC_DATA, offset & 0xff); - WRITE_PORT_UCHAR((PUCHAR)CRTC_COMMAND, CRTC_CURHI); - WRITE_PORT_UCHAR((PUCHAR)CRTC_DATA, (offset >> 8) & 0xff); + offset = (CursorY * SizeX) + CursorX; + + WRITE_PORT_UCHAR((PUCHAR)CRTC_COMMAND, CRTC_CURLO); + WRITE_PORT_UCHAR((PUCHAR)CRTC_DATA, offset & 0xff); + WRITE_PORT_UCHAR((PUCHAR)CRTC_COMMAND, CRTC_CURHI); + WRITE_PORT_UCHAR((PUCHAR)CRTC_DATA, (offset >> 8) & 0xff); #endif + KeReleaseSpinLockFromDpcLevel(&Lock); + __asm__ ("sti\n\t"); } diff --git a/reactos/ntoskrnl/hal/x86/mp.c b/reactos/ntoskrnl/hal/x86/mp.c index 5cd0e615b79..9bb0b0e6478 100644 --- a/reactos/ntoskrnl/hal/x86/mp.c +++ b/reactos/ntoskrnl/hal/x86/mp.c @@ -1,4 +1,4 @@ -/* $Id: mp.c,v 1.10 2001/04/16 23:29:54 dwelch Exp $ +/* $Id: mp.c,v 1.11 2001/04/17 23:39:25 dwelch Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -227,59 +227,60 @@ VOID IOAPICUnmaskIrq( IOAPICWrite(Apic, IOAPIC_REDTBL+2*Irq, *((PULONG)&Entry)); } -static VOID IOAPICSetupIds( - VOID) +static VOID +IOAPICSetupIds(VOID) { - ULONG tmp, apic, i; - UCHAR old_id; - - /* - * Set the IOAPIC ID to the value stored in the MPC table. - */ - for (apic = 0; apic < IOAPICCount; apic++) { - - /* Read the register 0 value */ + ULONG tmp, apic, i; + UCHAR old_id; + + /* + * Set the IOAPIC ID to the value stored in the MPC table. + */ + for (apic = 0; apic < IOAPICCount; apic++) { + + /* Read the register 0 value */ tmp = IOAPICRead(apic, IOAPIC_ID); - - old_id = IOAPICMap[apic].ApicId; - - if (IOAPICMap[apic].ApicId >= 0xf) { - DPRINT1("BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n", - apic, IOAPICMap[apic].ApicId); - DPRINT1("... fixing up to %d. (tell your hw vendor)\n", GET_IOAPIC_ID(tmp)); + + old_id = IOAPICMap[apic].ApicId; + + if (IOAPICMap[apic].ApicId >= 0xf) { + DPRINT1("BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n", + apic, IOAPICMap[apic].ApicId); + DPRINT1("... fixing up to %d. (tell your hw vendor)\n", + GET_IOAPIC_ID(tmp)); IOAPICMap[apic].ApicId = GET_IOAPIC_ID(tmp); - } - - /* - * We need to adjust the IRQ routing table - * if the ID changed. - */ - if (old_id != IOAPICMap[apic].ApicId) - for (i = 0; i < IRQCount; i++) - if (IRQMap[i].DstApicId == old_id) - IRQMap[i].DstApicId = IOAPICMap[apic].ApicId; - - /* - * Read the right value from the MPC table and - * write it into the ID register. - */ - DPRINT("Changing IO-APIC physical APIC ID to %d\n", - IOAPICMap[apic].ApicId); - - tmp &= ~IOAPIC_ID_MASK; + } + + /* + * We need to adjust the IRQ routing table + * if the ID changed. + */ + if (old_id != IOAPICMap[apic].ApicId) + for (i = 0; i < IRQCount; i++) + if (IRQMap[i].DstApicId == old_id) + IRQMap[i].DstApicId = IOAPICMap[apic].ApicId; + + /* + * Read the right value from the MPC table and + * write it into the ID register. + */ + DPRINT("Changing IO-APIC physical APIC ID to %d\n", + IOAPICMap[apic].ApicId); + + tmp &= ~IOAPIC_ID_MASK; tmp |= SET_IOAPIC_ID(IOAPICMap[apic].ApicId); - - IOAPICWrite(apic, IOAPIC_ID, tmp); - - /* - * Sanity check - */ - tmp = IOAPICRead(apic, 0); - if (GET_IOAPIC_ID(tmp) != IOAPICMap[apic].ApicId) { - DPRINT1("Could not set I/O APIC ID!\n"); + + IOAPICWrite(apic, IOAPIC_ID, tmp); + + /* + * Sanity check + */ + tmp = IOAPICRead(apic, 0); + if (GET_IOAPIC_ID(tmp) != IOAPICMap[apic].ApicId) { + DPRINT1("Could not set I/O APIC ID!\n"); KeBugCheck(0); - } - } + } + } } diff --git a/reactos/ntoskrnl/ke/i386/kernel.c b/reactos/ntoskrnl/ke/i386/kernel.c index 75f456cd206..083173525ca 100644 --- a/reactos/ntoskrnl/ke/i386/kernel.c +++ b/reactos/ntoskrnl/ke/i386/kernel.c @@ -89,6 +89,8 @@ KeApplicationProcessorInit(VOID) * Initialize a default LDT */ Ki386InitializeLdt(); + + __asm__ __volatile__ ("sti\n\t"); } VOID @@ -122,6 +124,8 @@ KeInit1(VOID) PcrsAllocated++; Ki386InitializeLdt(); + + __asm__ __volatile__ ("sti\n\t"); } VOID diff --git a/reactos/ntoskrnl/ke/i386/v86m_sup.S b/reactos/ntoskrnl/ke/i386/v86m_sup.S index 2d0a7464b7c..0ee36633812 100644 --- a/reactos/ntoskrnl/ke/i386/v86m_sup.S +++ b/reactos/ntoskrnl/ke/i386/v86m_sup.S @@ -75,7 +75,7 @@ _Ki386RetToV86Mode: /* * Save the old initial stack */ - movl _CurrentThread, %esi + movl %fs:KPCR_CURRENT_THREAD, %esi movl KTHREAD_INITIAL_STACK(%esi), %edi pushl %edi @@ -187,7 +187,7 @@ _KiV86Complete: /* * We also need to set the stack in the kthread structure */ - movl $_CurrentThread, %esi + movl %fs:KPCR_CURRENT_THREAD, %esi movl KTHREAD_INITIAL_STACK(%esi), %edi movl %eax, KTHREAD_INITIAL_STACK(%esi) diff --git a/reactos/ntoskrnl/ke/main.c b/reactos/ntoskrnl/ke/main.c index 0810181be23..cb3251a9485 100644 --- a/reactos/ntoskrnl/ke/main.c +++ b/reactos/ntoskrnl/ke/main.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: main.c,v 1.92 2001/04/17 04:11:00 dwelch Exp $ +/* $Id: main.c,v 1.93 2001/04/17 23:39:25 dwelch Exp $ * * PROJECT: ReactOS kernel * FILE: ntoskrnl/ke/main.c @@ -455,8 +455,11 @@ ExpInitializeExecutive(VOID) while (!HalAllProcessorsStarted()) { - KePrepareForApplicationProcessorInit(KeNumberProcessors); - PsPrepareForApplicationProcessorInit(KeNumberProcessors); + if (KeNumberProcessors != 0) + { + KePrepareForApplicationProcessorInit(KeNumberProcessors); + PsPrepareForApplicationProcessorInit(KeNumberProcessors); + } HalInitializeProcessor(KeNumberProcessors); KeNumberProcessors++; } @@ -493,7 +496,7 @@ ExpInitializeExecutive(VOID) #ifdef KDBG KdbEnter(); #endif /* KDBG */ - + /* * Initalize services loaded at boot time */ diff --git a/reactos/ntoskrnl/ke/spinlock.c b/reactos/ntoskrnl/ke/spinlock.c index e577ad4cbb1..983fc442eee 100644 --- a/reactos/ntoskrnl/ke/spinlock.c +++ b/reactos/ntoskrnl/ke/spinlock.c @@ -1,4 +1,4 @@ -/* $Id: spinlock.c,v 1.7 2001/04/17 04:11:01 dwelch Exp $ +/* $Id: spinlock.c,v 1.8 2001/04/17 23:39:25 dwelch Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -73,10 +73,14 @@ KeAcquireSpinLockAtDpcLevel (PKSPIN_LOCK SpinLock) */ { ULONG i; - - if (!(SpinLock->Lock == 0 || SpinLock->Lock == 1)) + + /* + * FIXME: This depends on gcc assembling this test to a single load from + * the spinlock's value. + */ + if ((ULONG)SpinLock->Lock >= 2) { - DbgPrint("Lock %x has bad value %x\n", SpinLock, i); + DbgPrint("Lock %x has bad value %x\n", SpinLock, SpinLock->Lock); KeBugCheck(0); } diff --git a/reactos/ntoskrnl/ke/timer.c b/reactos/ntoskrnl/ke/timer.c index 119ad952d78..ceb9f9b0504 100644 --- a/reactos/ntoskrnl/ke/timer.c +++ b/reactos/ntoskrnl/ke/timer.c @@ -1,4 +1,4 @@ -/* $Id: timer.c,v 1.44 2001/04/13 16:12:25 chorns Exp $ +/* $Id: timer.c,v 1.45 2001/04/17 23:39:25 dwelch Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -422,8 +422,6 @@ KiUpdateSystemTime (KIRQL oldIrql, ULONG Eip) * FUNCTION: Handles a timer interrupt */ { - char* vidmem=(char *)physical_to_linear(0xb8000 + 160 - 2); - KiRawTicks++; if (TimerInitDone == FALSE) @@ -436,16 +434,6 @@ KiUpdateSystemTime (KIRQL oldIrql, ULONG Eip) KiTimerTicks++; system_time = system_time + CLOCK_INCREMENT; - vidmem[0] = ' '; - if (oldIrql < DISPATCH_LEVEL) - { - vidmem[1] = 0x17; - } - else - { - vidmem[1] = 0x27; - } - /* * Queue a DPC that will expire timers */ diff --git a/reactos/ntoskrnl/ps/idle.c b/reactos/ntoskrnl/ps/idle.c index d21fcb4ad3c..ac9cfbac64a 100644 --- a/reactos/ntoskrnl/ps/idle.c +++ b/reactos/ntoskrnl/ps/idle.c @@ -32,20 +32,21 @@ PsIdleThreadMain(PVOID Context) for(;;) { - if (DpcQueueSize > 0) - { - KeRaiseIrql(DISPATCH_LEVEL,&oldlvl); - KiDispatchInterrupt(); - KeLowerIrql(oldlvl); - } - NtYieldExecution(); + if (DpcQueueSize > 0) + { + KeRaiseIrql(DISPATCH_LEVEL,&oldlvl); + KiDispatchInterrupt(); + KeLowerIrql(oldlvl); + } + NtYieldExecution(); } } VOID PsInitIdleThread(VOID) { KPRIORITY Priority; - + ULONG Affinity; + PsCreateSystemThread(&PsIdleThreadHandle, THREAD_ALL_ACCESS, NULL, @@ -59,4 +60,9 @@ VOID PsInitIdleThread(VOID) ThreadPriority, &Priority, sizeof(Priority)); + Affinity = 1 << 0; + NtSetInformationThread(PsIdleThreadHandle, + ThreadAffinityMask, + &Affinity, + sizeof(Affinity)); } diff --git a/reactos/ntoskrnl/ps/thread.c b/reactos/ntoskrnl/ps/thread.c index a0ce76a348d..350179324d2 100644 --- a/reactos/ntoskrnl/ps/thread.c +++ b/reactos/ntoskrnl/ps/thread.c @@ -1,4 +1,4 @@ -/* $Id: thread.c,v 1.76 2001/04/17 04:11:01 dwelch Exp $ +/* $Id: thread.c,v 1.77 2001/04/17 23:39:26 dwelch Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -48,8 +48,6 @@ static PETHREAD IdleThreads[MAXIMUM_PROCESSORS]; ULONG PiNrThreads = 0; ULONG PiNrRunnableThreads = 0; -PETHREAD CurrentThread = NULL; - static GENERIC_MAPPING PiThreadMapping = {THREAD_READ, THREAD_WRITE, THREAD_EXECUTE, @@ -59,12 +57,13 @@ static GENERIC_MAPPING PiThreadMapping = {THREAD_READ, PKTHREAD STDCALL KeGetCurrentThread(VOID) { - return(&(CurrentThread->Tcb)); + return(KeGetCurrentKPCR()->CurrentThread); } PETHREAD STDCALL PsGetCurrentThread(VOID) { - return(CurrentThread); + PKTHREAD CurrentThread = KeGetCurrentKPCR()->CurrentThread; + return(CONTAINING_RECORD(CurrentThread, ETHREAD, Tcb)); } HANDLE STDCALL PsGetCurrentThreadId(VOID) @@ -144,8 +143,13 @@ static PETHREAD PsScanThreadList (KPRIORITY Priority, ULONG Affinity) { current = CONTAINING_RECORD(current_entry, ETHREAD, Tcb.QueueListEntry); + assert(current->Tcb.State == THREAD_STATE_RUNNABLE); + DPRINT("current->Tcb.UserAffinity %x Affinity %x PID %d %d\n", + current->Tcb.UserAffinity, Affinity, current->Cid.UniqueThread, + Priority); if (current->Tcb.UserAffinity & Affinity) { + RemoveEntryList(¤t->Tcb.QueueListEntry); return(current); } current_entry = current_entry->Flink; @@ -160,6 +164,11 @@ VOID PsDispatchThreadNoLock (ULONG NewThreadStatus) KPRIORITY CurrentPriority; PETHREAD Candidate; ULONG Affinity; + PKTHREAD KCurrentThread = KeGetCurrentKPCR()->CurrentThread; + PETHREAD CurrentThread = CONTAINING_RECORD(KCurrentThread, ETHREAD, Tcb); + + DPRINT("PsDispatchThread() %d/%d\n", KeGetCurrentProcessorNumber(), + CurrentThread->Cid.UniqueThread); CurrentThread->Tcb.State = NewThreadStatus; if (CurrentThread->Tcb.State == THREAD_STATE_RUNNABLE) @@ -184,24 +193,25 @@ VOID PsDispatchThreadNoLock (ULONG NewThreadStatus) { PETHREAD OldThread; - DPRINT("Scheduling %x(%d)\n",Candidate, CurrentPriority); + DPRINT("Scheduling %x(%d)\n",Candidate, CurrentPriority); + + Candidate->Tcb.State = THREAD_STATE_RUNNING; + + OldThread = CurrentThread; + CurrentThread = Candidate; - Candidate->Tcb.State = THREAD_STATE_RUNNING; - - OldThread = CurrentThread; - CurrentThread = Candidate; - - KeReleaseSpinLockFromDpcLevel(&PiThreadListLock); - Ki386ContextSwitch(&CurrentThread->Tcb, &OldThread->Tcb); - PsReapThreads(); - return; + KeReleaseSpinLockFromDpcLevel(&PiThreadListLock); + Ki386ContextSwitch(&CurrentThread->Tcb, &OldThread->Tcb); + PsReapThreads(); + return; } } DbgPrint("CRITICAL: No threads are runnable\n"); KeBugCheck(0); } -VOID PsDispatchThread(ULONG NewThreadStatus) +VOID +PsDispatchThread(ULONG NewThreadStatus) { KIRQL oldIrql; @@ -214,7 +224,7 @@ VOID PsDispatchThread(ULONG NewThreadStatus) /* * Save wait IRQL */ - CurrentThread->Tcb.WaitIrql = oldIrql; + KeGetCurrentKPCR()->CurrentThread->WaitIrql = oldIrql; PsDispatchThreadNoLock(NewThreadStatus); KeLowerIrql(oldIrql); } @@ -316,6 +326,8 @@ PsPrepareForApplicationProcessorInit(ULONG Id) IdleThreads[Id] = IdleThread; NtClose(IdleThreadHandle); + DbgPrint("IdleThread for Processor %d has PID %d\n", + Id, IdleThread->Cid.UniqueThread); } VOID @@ -363,7 +375,6 @@ PsInitThreadManagment(VOID) HalInitFirstTask(FirstThread); FirstThread->Tcb.State = THREAD_STATE_RUNNING; FirstThread->Tcb.FreezeCount = 0; - CurrentThread = FirstThread; KeGetCurrentKPCR()->CurrentThread = (PVOID)FirstThread; NtClose(FirstThreadHandle); diff --git a/reactos/ntoskrnl/ps/tinfo.c b/reactos/ntoskrnl/ps/tinfo.c index bb4391dd210..b3f9761c236 100644 --- a/reactos/ntoskrnl/ps/tinfo.c +++ b/reactos/ntoskrnl/ps/tinfo.c @@ -74,7 +74,7 @@ NtSetInformationThread(HANDLE ThreadHandle, break; case ThreadAffinityMask: - Status = STATUS_NOT_IMPLEMENTED; + Thread->Tcb.UserAffinity = *((PULONG)ThreadInformation); break; case ThreadImpersonationToken: