- Added another MSVC intrinsic to gcc (BitScanReverse). Thanks to Vampyre.
authorAlex Ionescu <aionescu@gmail.com>
Mon, 17 Jul 2006 01:40:10 +0000 (01:40 +0000)
committerAlex Ionescu <aionescu@gmail.com>
Mon, 17 Jul 2006 01:40:10 +0000 (01:40 +0000)
- Added very basic and skeletal NUMA code when creating a thread and process, currently only does some basic affinity checks and settings.
- Added a table and helper function (KeFindNextRightSetAffinity) for calculating affinity masks and sets.
- Split KeInitailizeThread into KeStartThread and KeInitThread, and modified Ps code to use the calls. Now added a failure case where Init fails, but we don't have to backout the entire effects of a "Start".
- Changes based on WI4 and Windows Internals II.

svn path=/trunk/; revision=23111

reactos/include/psdk/winnt.h
reactos/ntoskrnl/include/internal/ke.h
reactos/ntoskrnl/ke/i386/kernel.c
reactos/ntoskrnl/ke/kthread.c
reactos/ntoskrnl/ke/process.c
reactos/ntoskrnl/ps/thread.c

index 49149f0..5fb86b0 100644 (file)
@@ -3814,6 +3814,19 @@ InterlockedBitTestAndReset(IN LONG volatile *Base,
        return OldBit;
 }
 
+static __inline__ BOOLEAN
+BitScanReverse(OUT ULONG *Index,
+               IN ULONG Mask)
+{
+       LONG OldBit;
+       __asm__ __volatile__("bsrl %1,%2\n\t"
+                            "sbbl %0,%0\n\t"
+                            :"=r" (OldBit),"=m" (*Index)
+                            :"Ir" (Mask)
+                            : "memory");
+       return OldBit;
+}
+
 #endif
 
 #define YieldProcessor() __asm__ __volatile__("pause");
index 651d884..d927500 100644 (file)
@@ -44,6 +44,9 @@ extern ULONG_PTR KERNEL_BASE;
 extern ULONG KeI386NpxPresent;
 extern ULONG KeI386XMMIPresent;
 extern ULONG KeI386FxsrPresent;
+extern PKNODE KeNodeBlock[1];
+extern UCHAR KeNumberNodes;
+extern UCHAR KeProcessNodeSeed;
 
 /* MACROS *************************************************************************/
 
@@ -68,6 +71,8 @@ extern ULONG KeI386FxsrPresent;
 #define KeReleaseDispatcherDatabaseLockFromDpcLevel()
 #endif
 
+#define AFFINITY_MASK(Id) KiMask32Array[Id]
+
 /* The following macro initializes a dispatcher object's header */
 #define KeInitializeDispatcherHeader(Header, t, s, State)                   \
 {                                                                           \
@@ -188,6 +193,13 @@ KiIpiSendRequest(
 
 /* next file ***************************************************************/
 
+UCHAR
+NTAPI
+KeFindNextRightSetAffinity(
+    IN UCHAR Number,
+    IN ULONG Set
+);
+
 VOID 
 STDCALL
 DbgBreakPointNoBugCheck(VOID);
@@ -267,16 +279,35 @@ KiExpireTimers(
 );
 
 VOID
-STDCALL
+NTAPI
 KeInitializeThread(
-    struct _KPROCESS* Process,
-    PKTHREAD Thread,
-    PKSYSTEM_ROUTINE SystemRoutine,
-    PKSTART_ROUTINE StartRoutine,
-    PVOID StartContext,
-    PCONTEXT Context,
-    PVOID Teb,
-    PVOID KernelStack
+    IN PKPROCESS Process,
+    IN OUT PKTHREAD Thread,
+    IN PKSYSTEM_ROUTINE SystemRoutine,
+    IN PKSTART_ROUTINE StartRoutine,
+    IN PVOID StartContext,
+    IN PCONTEXT Context,
+    IN PVOID Teb,
+    IN PVOID KernelStack
+);
+
+NTSTATUS
+NTAPI
+KeInitThread(
+    IN OUT PKTHREAD Thread,
+    IN PVOID KernelStack,
+    IN PKSYSTEM_ROUTINE SystemRoutine,
+    IN PKSTART_ROUTINE StartRoutine,
+    IN PVOID StartContext,
+    IN PCONTEXT Context,
+    IN PVOID Teb,
+    IN PKPROCESS Process
+);
+
+VOID
+NTAPI
+KeStartThread(
+    IN OUT PKTHREAD Thread
 );
 
 VOID
index 64a0368..2676108 100644 (file)
 
 /* GLOBALS *******************************************************************/
 
+KNODE KiNode0;
+PKNODE KeNodeBlock[1];
+UCHAR KeNumberNodes = 1;
+UCHAR KeProcessNodeSeed;
 ULONG KiPcrInitDone = 0;
 static ULONG PcrsAllocated = 0;
 static ULONG Ke386CpuidFlags2, Ke386CpuidExFlags, Ke386CpuidExMisc;
@@ -340,6 +344,10 @@ KeInit1(PCHAR CommandLine, PULONG LastKernelAddress)
 
    KeActiveProcessors |= 1 << 0;
 
+    /* Set Node Data */
+    KeNodeBlock[0] = &KiNode0;
+    KPCR->PrcbData.ParentNode = KeNodeBlock[0];
+    KeNodeBlock[0]->ProcessorMask = KPCR->PrcbData.SetMember;
 
    if (KPCR->PrcbData.FeatureBits & X86_FEATURE_PGE)
    {
index 5cf0762..c94bb51 100644 (file)
@@ -24,8 +24,37 @@ static ULONG PriorityListMask = 0;
 ULONG IdleProcessorMask = 0;
 extern LIST_ENTRY PspReaperListHead;
 
+ULONG KiMask32Array[MAXIMUM_PRIORITY] =
+{
+    0x1,        0x2,       0x4,       0x8,       0x10,       0x20,
+    0x40,       0x80,      0x100,     0x200,     0x4000,     0x800,
+    0x1000,     0x2000,    0x4000,    0x8000,    0x10000,    0x20000,
+    0x40000,    0x80000,   0x100000,  0x200000,  0x400000,   0x800000,
+    0x1000000,  0x2000000, 0x4000000, 0x8000000, 0x10000000, 0x20000000,
+    0x40000000, 0x80000000
+};
+
 /* FUNCTIONS *****************************************************************/
 
+UCHAR
+NTAPI
+KeFindNextRightSetAffinity(IN UCHAR Number,
+                           IN ULONG Set)
+{
+    ULONG Bit, Result;
+    ASSERT(Set != 0);
+
+    /* Calculate the mask */
+    Bit = (AFFINITY_MASK(Number) - 1) & Set;
+
+    /* If it's 0, use the one we got */
+    if (!Bit) Bit = Set;
+
+    /* Now find the right set and return it */
+    BitScanReverse(&Result, Bit);
+    return (UCHAR)Result;
+}
+
 STATIC
 VOID
 KiRequestReschedule(CCHAR Processor)
@@ -699,35 +728,29 @@ KeCapturePersistentThreadState(IN PVOID CurrentThread,
     UNIMPLEMENTED;
 }
 
-/*
- * FUNCTION: Initialize the microkernel state of the thread
- */
-VOID
-STDCALL
-KeInitializeThread(PKPROCESS Process,
-                   PKTHREAD Thread,
-                   PKSYSTEM_ROUTINE SystemRoutine,
-                   PKSTART_ROUTINE StartRoutine,
-                   PVOID StartContext,
-                   PCONTEXT Context,
-                   PVOID Teb,
-                   PVOID KernelStack)
+NTSTATUS
+NTAPI
+KeInitThread(IN OUT PKTHREAD Thread,
+             IN PVOID KernelStack,
+             IN PKSYSTEM_ROUTINE SystemRoutine,
+             IN PKSTART_ROUTINE StartRoutine,
+             IN PVOID StartContext,
+             IN PCONTEXT Context,
+             IN PVOID Teb,
+             IN PKPROCESS Process)
 {
+    BOOLEAN AllocatedStack = FALSE;
     ULONG i;
     PKWAIT_BLOCK TimerWaitBlock;
     PKTIMER Timer;
+    NTSTATUS Status;
 
     /* Initalize the Dispatcher Header */
-    DPRINT("Initializing Dispatcher Header for New Thread: %x in Process: %x\n", Thread, Process);
     KeInitializeDispatcherHeader(&Thread->DispatcherHeader,
                                  ThreadObject,
                                  sizeof(KTHREAD) / sizeof(LONG),
                                  FALSE);
 
-    DPRINT("Thread Header Created. SystemRoutine: %x, StartRoutine: %x with Context: %x\n",
-            SystemRoutine, StartRoutine, StartContext);
-    DPRINT("UserMode Information. Context: %x, Teb: %x\n", Context, Teb);
-
     /* Initialize the Mutant List */
     InitializeListHead(&Thread->MutantListHead);
 
@@ -738,6 +761,15 @@ KeInitializeThread(PKPROCESS Process,
         Thread->WaitBlock[i].Thread = Thread;
     }
 
+    /* Set swap settings */
+    Thread->EnableStackSwap = FALSE;//TRUE;
+    Thread->IdealProcessor = 1;
+    Thread->SwapBusy = FALSE;
+    Thread->AdjustReason = 0;
+
+    /* Initialize the lock */
+    KeInitializeSpinLock(&Thread->ThreadLock);
+
     /* Setup the Service Descriptor Table for Native Calls */
     Thread->ServiceTable = KeServiceDescriptorTable;
 
@@ -762,7 +794,7 @@ KeInitializeThread(PKPROCESS Process,
                     NULL);
 
     /* Initialize the Suspend Semaphore */
-    KeInitializeSemaphore(&Thread->SuspendSemaphore, 0, 128);
+    KeInitializeSemaphore(&Thread->SuspendSemaphore, 0, 2);
 
     /* Setup the timer */
     Timer = &Thread->Timer;
@@ -780,53 +812,148 @@ KeInitializeThread(PKPROCESS Process,
     /* Set the TEB */
     Thread->Teb = Teb;
 
+    /* Check if we have a kernel stack */
+    if (!KernelStack)
+    {
+        /* We don't, allocate one */
+        KernelStack = (PVOID)((ULONG_PTR)MmCreateKernelStack(FALSE) +
+                              KERNEL_STACK_SIZE);
+        if (!KernelStack) return STATUS_INSUFFICIENT_RESOURCES;
+
+        /* Remember for later */
+        AllocatedStack = TRUE;
+    }
+
     /* Set the Thread Stacks */
     Thread->InitialStack = (PCHAR)KernelStack;
     Thread->StackBase = (PCHAR)KernelStack;
     Thread->StackLimit = (ULONG_PTR)KernelStack - KERNEL_STACK_SIZE;
     Thread->KernelStackResident = TRUE;
 
-    /*
-     * Establish the pde's for the new stack and the thread structure within the
-     * address space of the new process. They are accessed while taskswitching or
-     * while handling page faults. At this point it isn't possible to call the
-     * page fault handler for the missing pde's.
-     */
-    MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread->StackLimit, KERNEL_STACK_SIZE);
+    /* ROS Mm HACK */
+    MmUpdatePageDir((PEPROCESS)Process,
+                    (PVOID)Thread->StackLimit,
+                    KERNEL_STACK_SIZE);
     MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread, sizeof(ETHREAD));
 
-    /* Initalize the Thread Context */
-    DPRINT("Initializing the Context for the thread: %x\n", Thread);
-    KiArchInitThreadWithContext(Thread,
-                                SystemRoutine,
-                                StartRoutine,
-                                StartContext,
-                                Context);
+    /* Enter SEH to avoid crashes due to user mode */
+    Status = STATUS_SUCCESS;
+    _SEH_TRY
+    {
+        /* Initalize the Thread Context */
+        KiArchInitThreadWithContext(Thread,
+                                    SystemRoutine,
+                                    StartRoutine,
+                                    StartContext,
+                                    Context);
+    }
+    _SEH_HANDLE
+    {
+        /* Set failure status */
+        Status = STATUS_UNSUCCESSFUL;
 
-    /* Setup scheduler Fields based on Parent */
-    DPRINT("Thread context created, setting Scheduler Data\n");
-    Thread->BasePriority = Process->BasePriority;
+        /* Check if a stack was allocated */
+        if (AllocatedStack)
+        {
+            /* Delete the stack */
+            MmDeleteKernelStack(Thread->StackBase, FALSE);
+            Thread->InitialStack = NULL;
+        }
+    }
+    _SEH_END;
+
+    /* Set the Thread to initalized */
+    Thread->State = Initialized;
+    return Status;
+}
+
+VOID
+NTAPI
+KeStartThread(IN OUT PKTHREAD Thread)
+{
+    KIRQL OldIrql;
+    PKPROCESS Process = Thread->ApcState.Process;
+    PKNODE Node;
+    PKPRCB NodePrcb;
+    ULONG Set, Mask;
+    UCHAR IdealProcessor;
+
+    /* Setup static fields from parent */
+    Thread->Iopl = Process->Iopl;
     Thread->Quantum = Process->QuantumReset;
     Thread->QuantumReset = Process->QuantumReset;
-    Thread->Affinity = Process->Affinity;
+    Thread->SystemAffinityActive = FALSE;
+
+    /* Lock the process */
+    KeAcquireSpinLock(&Process->ProcessLock, &OldIrql);
+
+    /* Setup volatile data */
     Thread->Priority = Process->BasePriority;
+    Thread->BasePriority = Process->BasePriority;
+    Thread->Affinity = Process->Affinity;
     Thread->UserAffinity = Process->Affinity;
-    Thread->DisableBoost = Process->DisableBoost;
-    Thread->AutoAlignment = Process->AutoAlignment;
-    Thread->Iopl = Process->Iopl;
 
-    /* Set the Thread to initalized */
-    Thread->State = Initialized;
+    /* Get the KNODE and its PRCB */
+    Node = KeNodeBlock[Process->IdealNode];
+    NodePrcb = (PKPRCB)(KPCR_BASE + (Process->ThreadSeed * PAGE_SIZE));
 
-    /*
-     * Insert the Thread into the Process's Thread List
-     * Note, this is the KTHREAD Thread List. It is removed in
-     * ke/kthread.c!KeTerminateThread.
-     */
+    /* Calculate affinity mask */
+    Set = ~NodePrcb->MultiThreadProcessorSet;
+    Mask = (ULONG)(Node->ProcessorMask & Process->Affinity);
+    Set &= Mask;
+    if (Set) Mask = Set;
+
+    /* Get the new thread seed */
+    IdealProcessor = KeFindNextRightSetAffinity(Process->ThreadSeed, Mask);
+    Process->ThreadSeed = IdealProcessor;
+
+    /* Sanity check */
+    ASSERT((Thread->UserAffinity & AFFINITY_MASK(IdealProcessor)));
+
+    /* Set the Ideal Processor */
+    Thread->IdealProcessor = IdealProcessor;
+    Thread->UserIdealProcessor = IdealProcessor;
+
+    /* Lock the Dispatcher Database */
+    KeAcquireDispatcherDatabaseLockAtDpcLevel();
+
+    /* Insert the thread into the process list */
     InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry);
-    DPRINT("Thread initalized\n");
+
+    /* Increase the stack count */
+    ASSERT(Process->StackCount != MAXULONG_PTR);
+    Process->StackCount++;
+
+    /* Release locks and return */
+    KeReleaseDispatcherDatabaseLockFromDpcLevel();
+    KeReleaseSpinLock(&Process->ProcessLock, OldIrql);
 }
 
+VOID
+NTAPI
+KeInitializeThread(IN PKPROCESS Process,
+                   IN OUT PKTHREAD Thread,
+                   IN PKSYSTEM_ROUTINE SystemRoutine,
+                   IN PKSTART_ROUTINE StartRoutine,
+                   IN PVOID StartContext,
+                   IN PCONTEXT Context,
+                   IN PVOID Teb,
+                   IN PVOID KernelStack)
+{
+    /* Initailize and start the thread on success */
+    if (NT_SUCCESS(KeInitThread(Thread,
+                                KernelStack,
+                                SystemRoutine,
+                                StartRoutine,
+                                StartContext,
+                                Context,
+                                Teb,
+                                Process)))
+    {
+        /* Start it */
+        KeStartThread(Thread);
+    }
+}
 
 /*
  * @implemented
index e136051..eacb5fc 100644 (file)
@@ -113,13 +113,14 @@ KiAttachProcess(PKTHREAD Thread,
 
 VOID
 NTAPI
-KeInitializeProcess(PKPROCESS Process,
-                    KPRIORITY Priority,
-                    KAFFINITY Affinity,
-                    LARGE_INTEGER DirectoryTableBase)
+KeInitializeProcess(IN OUT PKPROCESS Process,
+                    IN KPRIORITY Priority,
+                    IN KAFFINITY Affinity,
+                    IN LARGE_INTEGER DirectoryTableBase)
 {
-    DPRINT("KeInitializeProcess. Process: %x, DirectoryTableBase: %x\n",
-            Process, DirectoryTableBase);
+    ULONG i = 0;
+    UCHAR IdealNode = 0;
+    PKNODE Node;
 
     /* Initialize the Dispatcher Header */
     KeInitializeDispatcherHeader(&Process->Header,
@@ -127,19 +128,58 @@ KeInitializeProcess(PKPROCESS Process,
                                  sizeof(KPROCESS),
                                  FALSE);
 
-    /* Initialize Scheduler Data, Disable Alignment Faults and Set the PDE */
+    /* Initialize Scheduler Data, Alignment Faults and Set the PDE */
     Process->Affinity = Affinity;
-    Process->BasePriority = Priority;
+    Process->BasePriority = (CHAR)Priority;
     Process->QuantumReset = 6;
     Process->DirectoryTableBase = DirectoryTableBase;
     Process->AutoAlignment = TRUE;
     Process->IopmOffset = 0xFFFF;
-    Process->State = ProcessInMemory;
 
-    /* Initialize the Thread List */
+    /* Initialize the lists */
     InitializeListHead(&Process->ThreadListHead);
-    KeInitializeSpinLock(&Process->ProcessLock);
-    DPRINT("The Process has now been initalized with the Kernel\n");
+    InitializeListHead(&Process->ProfileListHead);
+    InitializeListHead(&Process->ReadyListHead);
+
+    /* Initialize the current State */
+    Process->State = ProcessInMemory;
+
+    /* Check how many Nodes there are on the system */
+    if (KeNumberNodes > 1)
+    {
+        /* Set the new seed */
+        KeProcessNodeSeed = (KeProcessNodeSeed + 1) / KeNumberNodes;
+        IdealNode = KeProcessNodeSeed;
+
+        /* Loop every node */
+        do
+        {
+            /* Check if the affinity matches */
+            if (KeNodeBlock[IdealNode]->ProcessorMask != Affinity) break;
+
+            /* No match, try next Ideal Node and increase node loop index */
+            IdealNode++;
+            i++;
+
+            /* Check if the Ideal Node is beyond the total number of nodes */
+            if (IdealNode >= KeNumberNodes)
+            {
+                /* Normalize the Ideal Node */
+                IdealNode -= KeNumberNodes;
+            }
+        } while (i < KeNumberNodes);
+    }
+
+    /* Set the ideal node and get the ideal node block */
+    Process->IdealNode = IdealNode;
+    Node = KeNodeBlock[IdealNode];
+    ASSERT(Node->ProcessorMask & Affinity);
+
+    /* Find the matching affinity set to calculate the thread seed */
+    Affinity &= Node->ProcessorMask;
+    Process->ThreadSeed = KeFindNextRightSetAffinity(Node->Seed,
+                                                     (ULONG)Affinity);
+    Node->Seed = Process->ThreadSeed;
 }
 
 ULONG
index 66ead43..6c0ece4 100644 (file)
@@ -15,7 +15,6 @@
  *  - MAJOR: Use Guarded Mutex instead of Fast Mutex for Active Process Locks.
  *  - Generate process cookie for user-more thread.
  *  - Add security calls where necessary.
- *  - KeInit/StartThread for better isolation of code
  */
 
 /* INCLUDES ****************************************************************/
@@ -56,7 +55,7 @@ PspUserThreadStartup(PKSTART_ROUTINE StartRoutine,
     {
         /* Remember that we're dead */
         DeadThread = TRUE;
-}
+    }
     else
     {
         /* Get the Locale ID and save Preferred Proc */
@@ -157,12 +156,11 @@ PspCreateThread(OUT PHANDLE ThreadHandle,
     HANDLE hThread;
     PEPROCESS Process;
     PETHREAD Thread;
-    PTEB TebBase;
+    PTEB TebBase = NULL;
     KIRQL OldIrql;
     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
     NTSTATUS Status;
     HANDLE_TABLE_ENTRY CidEntry;
-    ULONG_PTR KernelStack;
     PAGED_CODE();
 
     /* If we were called from PsCreateSystemThread, then we're kernel mode */
@@ -260,9 +258,6 @@ PspCreateThread(OUT PHANDLE ThreadHandle,
     /* Acquire rundown protection */
     ExAcquireRundownProtection(&Process->RundownProtect);
 
-    /* Allocate Stack for non-GUI Thread */
-    KernelStack = (ULONG_PTR)MmCreateKernelStack(FALSE) + KERNEL_STACK_SIZE;
-
     /* Now let the kernel initialize the context */
     if (ThreadContext)
     {
@@ -281,14 +276,14 @@ PspCreateThread(OUT PHANDLE ThreadHandle,
         Thread->Win32StartAddress = (PVOID)ThreadContext->Eax;
 
         /* Let the kernel intialize the Thread */
-        KeInitializeThread(&Process->Pcb,
-                           &Thread->Tcb,
-                           PspUserThreadStartup,
-                           NULL,
-                           NULL,
-                           ThreadContext,
-                           TebBase,
-                           (PVOID)KernelStack);
+        Status = KeInitThread(&Thread->Tcb,
+                              NULL,
+                              PspUserThreadStartup,
+                              NULL,
+                              Thread->StartAddress,
+                              ThreadContext,
+                              TebBase,
+                              &Process->Pcb);
     }
     else
     {
@@ -297,16 +292,30 @@ PspCreateThread(OUT PHANDLE ThreadHandle,
         InterlockedOr((PLONG)&Thread->CrossThreadFlags, CT_SYSTEM_THREAD_BIT);
 
         /* Let the kernel intialize the Thread */
-        KeInitializeThread(&Process->Pcb,
-                           &Thread->Tcb,
-                           PspSystemThreadStartup,
-                           StartRoutine,
-                           StartContext,
-                           NULL,
-                           NULL,
-                           (PVOID)KernelStack);
+        Status = KeInitThread(&Thread->Tcb,
+                              NULL,
+                              PspSystemThreadStartup,
+                              StartRoutine,
+                              StartContext,
+                              NULL,
+                              NULL,
+                              &Process->Pcb);
     }
 
+    /* Check if we failed */
+    if (!NT_SUCCESS(Status))
+    {
+        /* Delete the TEB if we had done */
+        if (TebBase) MmDeleteTeb(Process, TebBase);
+
+        /* Release rundown and dereference */
+        ExReleaseRundownProtection(&Process->RundownProtect);
+        ObDereferenceObject(Thread);
+        return Status;
+    }
+
+    /* FIXME: Acquire exclusive pushlock */
+
     /*
      * Insert the Thread into the Process's Thread List
      * Note, this is the ETHREAD Thread List. It is removed in
@@ -315,6 +324,11 @@ PspCreateThread(OUT PHANDLE ThreadHandle,
     InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry);
     Process->ActiveThreads++;
 
+    /* Start the thread */
+    KeStartThread(&Thread->Tcb);
+
+    /* FIXME: Wake pushlock */
+
     /* Release rundown */
     ExReleaseRundownProtection(&Process->RundownProtect);
 
@@ -326,10 +340,7 @@ PspCreateThread(OUT PHANDLE ThreadHandle,
     PspRunCreateThreadNotifyRoutines(Thread, TRUE);
 
     /* Suspend the Thread if we have to */
-    if (CreateSuspended)
-    {
-        KeSuspendThread(&Thread->Tcb);
-    }
+    if (CreateSuspended) KeSuspendThread(&Thread->Tcb);
 
     /* Check if we were already terminated */
     if (Thread->Terminated)