LIST_ENTRY PriorityListHead[MAXIMUM_PRIORITY];
static ULONG PriorityListMask = 0;
ULONG IdleProcessorMask = 0;
-extern PETHREAD PspReaperList;
+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)
if (current->State != Ready) {
- DPRINT1("%d/%d\n", ¤t, current->State);
+ DPRINT1("%p/%d\n", current, current->State);
}
ASSERT(current->State == Ready);
return(NULL);
}
-VOID
+BOOLEAN
STDCALL
KiDispatchThreadNoLock(ULONG NewThreadStatus)
{
PKTHREAD Candidate;
ULONG Affinity;
PKTHREAD CurrentThread = KeGetCurrentThread();
+ BOOLEAN ApcState;
DPRINT("KiDispatchThreadNoLock() %d/%d/%d/%d\n", KeGetCurrentProcessorNumber(),
CurrentThread, NewThreadStatus, CurrentThread->State);
Candidate->State = Running;
KeReleaseDispatcherDatabaseLockFromDpcLevel();
- return;
+ return FALSE;
}
if (Candidate != NULL) {
MmUpdatePageDir((PEPROCESS)PsGetCurrentProcess(),((PETHREAD)CurrentThread)->ThreadsProcess, sizeof(EPROCESS));
/* Special note for Filip: This will release the Dispatcher DB Lock ;-) -- Alex */
- DPRINT("You are : %x, swapping to: %x\n", OldThread, CurrentThread);
- KiArchContextSwitch(CurrentThread);
+ DPRINT("You are : %x, swapping to: %x.\n", OldThread, CurrentThread);
+ ApcState = KiSwapContext(OldThread, CurrentThread);
DPRINT("You are : %x, swapped from: %x\n", OldThread, CurrentThread);
- return;
+ return ApcState;
}
}
DPRINT1("CRITICAL: No threads are ready (CPU%d)\n", KeGetCurrentProcessorNumber());
KEBUGCHECK(0);
+ return FALSE;
}
NTSTATUS
KiSwapThread(VOID)
{
PKTHREAD CurrentThread = KeGetCurrentThread();
+ BOOLEAN ApcState;
/* Find a new thread to run */
DPRINT("Dispatching Thread as blocked\n");
- KiDispatchThreadNoLock(Waiting);
+ ApcState = KiDispatchThreadNoLock(Waiting);
+
+ /* Check if we need to deliver APCs */
+ if (ApcState)
+ {
+ /* Lower to APC_LEVEL */
+ KeLowerIrql(APC_LEVEL);
- /* Lower IRQL back */
- DPRINT("Lowering IRQL \n");
+ /* Deliver APCs */
+ KiDeliverApc(KernelMode, NULL, NULL);
+ ASSERT(CurrentThread->WaitIrql == 0);
+ }
+
+ /* Lower IRQL back to what it was */
KfLowerIrql(CurrentThread->WaitIrql);
/* Return the wait status */
}
VOID
-STDCALL
-KiUnblockThread(PKTHREAD Thread,
- PNTSTATUS WaitStatus,
- KPRIORITY Increment)
+NTAPI
+KiReadyThread(IN PKTHREAD Thread)
{
- if (Terminated == Thread->State) {
-
- DPRINT("Can't unblock thread 0x%x because it's terminating\n",
- Thread);
-
- } else if (Ready == Thread->State ||
- Running == Thread->State) {
-
- DPRINT("Can't unblock thread 0x%x because it's %s\n",
- Thread, (Thread->State == Ready ? "ready" : "running"));
-
- } else {
-
- LONG Processor;
- KAFFINITY Affinity;
-
- /* FIXME: This propably isn't the right way to do it... */
- /* No it's not... i'll fix it later-- Alex */
- if (Thread->Priority < LOW_REALTIME_PRIORITY &&
- Thread->BasePriority < LOW_REALTIME_PRIORITY - 2) {
-
- if (!Thread->PriorityDecrement && !Thread->DisableBoost) {
-
- Thread->Priority = Thread->BasePriority + Increment;
- Thread->PriorityDecrement = Increment;
- }
-
- /* Also decrease quantum */
- Thread->Quantum--;
-
- } else {
-
- Thread->Quantum = Thread->QuantumReset;
- }
-
- if (WaitStatus != NULL) {
-
- Thread->WaitStatus = *WaitStatus;
- }
-
- Thread->State = Ready;
- KiInsertIntoThreadList(Thread->Priority, Thread);
- Processor = KeGetCurrentProcessorNumber();
- Affinity = Thread->Affinity;
-
- if (!(IdleProcessorMask & (1 << Processor) & Affinity) &&
- (IdleProcessorMask & ~(1 << Processor) & Affinity)) {
-
- LONG i;
-
- for (i = 0; i < KeNumberProcessors - 1; i++) {
-
- Processor++;
-
- if (Processor >= KeNumberProcessors) {
-
- Processor = 0;
- }
-
- if (IdleProcessorMask & (1 << Processor) & Affinity) {
-#if 0
- /* FIXME:
- * Reschedule the threads on an other processor
- */
- KeReleaseDispatcherDatabaseLockFromDpcLevel();
- KiRequestReschedule(Processor);
- KeAcquireDispatcherDatabaseLockAtDpcLevel();
-#endif
- break;
- }
- }
- }
- }
+ /* Makes a thread ready */
+ Thread->State = Ready;
+ KiInsertIntoThreadList(Thread->Priority, Thread);
}
VOID
}
ULONG
-STDCALL
-KeResumeThread(PKTHREAD Thread)
+NTAPI
+KeResumeThread(IN PKTHREAD Thread)
{
ULONG PreviousCount;
KIRQL OldIrql;
}
ULONG
-STDCALL
+NTAPI
KeAlertResumeThread(IN PKTHREAD Thread)
{
ULONG PreviousCount;
}
BOOLEAN
-STDCALL
-KeAlertThread(PKTHREAD Thread,
- KPROCESSOR_MODE AlertMode)
+NTAPI
+KeAlertThread(IN PKTHREAD Thread,
+ IN KPROCESSOR_MODE AlertMode)
{
KIRQL OldIrql;
BOOLEAN PreviousState;
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)
+NTAPI
+KeUninitThread(IN PKTHREAD Thread)
{
+ /* Delete the stack */
+ MmDeleteKernelStack(Thread->StackBase, FALSE);
+ Thread->InitialStack = NULL;
+}
+
+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);
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;
NULL);
/* Initialize the Suspend Semaphore */
- KeInitializeSemaphore(&Thread->SuspendSemaphore, 0, 128);
+ KeInitializeSemaphore(&Thread->SuspendSemaphore, 0, 2);
- /* FIXME OPTIMIZATION OF DOOM. DO NOT ENABLE FIXME */
+ /* Setup the timer */
Timer = &Thread->Timer;
KeInitializeTimer(Timer);
TimerWaitBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
/* 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
+ {
+#ifdef _M_IX86
+ /* Initalize the Thread Context */
+ Ke386InitThreadWithContext(Thread,
+ SystemRoutine,
+ StartRoutine,
+ StartContext,
+ Context);
+#endif
+ }
+ _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 */
+#ifdef _M_IX86
+ Thread->Iopl = Process->Iopl;
+#endif
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;
-#ifdef _M_IX86
- Thread->Iopl = Process->Iopl;
-#endif
- /* 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));
+
+ /* 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;
- /*
- * Insert the Thread into the Process's Thread List
- * Note, this is the KTHREAD Thread List. It is removed in
- * ke/kthread.c!KeTerminateThread.
- */
+ /* 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
{
KIRQL OldIrql;
PKTHREAD Thread = KeGetCurrentThread();
+ PKPROCESS Process = Thread->ApcState.Process;
+ PLIST_ENTRY *ListHead;
+ PETHREAD Entry, SavedEntry;
+ PETHREAD *ThreadAddr;
+ DPRINT("Terminating\n");
/* Lock the Dispatcher Database and the APC Queue */
- DPRINT("Terminating\n");
+ ASSERT_IRQL(DISPATCH_LEVEL);
OldIrql = KeAcquireDispatcherDatabaseLock();
+ ASSERT(Thread->SwapBusy == FALSE);
- /* Remove the thread from the list */
- RemoveEntryList(&Thread->ThreadListEntry);
+ /* Make sure we won't get Swapped */
+ Thread->SwapBusy = TRUE;
+
+ /* Save the Kernel and User Times */
+ Process->KernelTime += Thread->KernelTime;
+ Process->UserTime += Thread->UserTime;
+
+ /* Get the current entry and our Port */
+ Entry = (PETHREAD)PspReaperListHead.Flink;
+ ThreadAddr = &((PETHREAD)Thread)->ReaperLink;
+
+ /* Add it to the reaper's list */
+ do
+ {
+ /* Get the list head */
+ ListHead = &PspReaperListHead.Flink;
+
+ /* Link ourselves */
+ *ThreadAddr = Entry;
+ SavedEntry = Entry;
- /* Insert into the Reaper List */
- DPRINT("List: %p\n", PspReaperList);
- ((PETHREAD)Thread)->ReaperLink = PspReaperList;
- PspReaperList = (PETHREAD)Thread;
- DPRINT("List: %p\n", PspReaperList);
+ /* Now try to do the exchange */
+ Entry = InterlockedCompareExchangePointer(ListHead, ThreadAddr, Entry);
- /* Check if it's active */
- if (PspReaping == FALSE) {
+ /* Break out if the change was succesful */
+ } while (Entry != SavedEntry);
- /* Activate it. We use the internal function for speed, and use the Hyper Critical Queue */
- PspReaping = TRUE;
- DPRINT("Terminating\n");
+ /* Check if the reaper wasn't active */
+ if (!Entry)
+ {
+ /* Activate it as a work item, directly through its Queue */
KiInsertQueue(&ExWorkerQueue[HyperCriticalWorkQueue].WorkerQueue,
&PspReaperWorkItem.List,
FALSE);
}
/* Handle Kernel Queues */
- if (Thread->Queue) {
-
+ if (Thread->Queue)
+ {
DPRINT("Waking Queue\n");
RemoveEntryList(&Thread->QueueListEntry);
KiWakeQueue(Thread->Queue);
/* Signal the thread */
Thread->DispatcherHeader.SignalState = TRUE;
- if (IsListEmpty(&Thread->DispatcherHeader.WaitListHead) != TRUE) {
-
+ if (IsListEmpty(&Thread->DispatcherHeader.WaitListHead) != TRUE)
+ {
/* Satisfy waits */
KiWaitTest((PVOID)Thread, Increment);
}
+ /* Remove the thread from the list */
+ RemoveEntryList(&Thread->ThreadListEntry);
+
+ /* Set us as terminated, decrease the Process's stack count */
+ Thread->State = Terminated;
+ Process->StackCount--;
+
/* Find a new Thread */
KiDispatchThreadNoLock(Terminated);
}
return OldState;
}
-/*
- *
- * NOT EXPORTED
- */
-NTSTATUS
-STDCALL
-NtAlertResumeThread(IN HANDLE ThreadHandle,
- OUT PULONG SuspendCount)
-{
- KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
- PETHREAD Thread;
- NTSTATUS Status;
- ULONG PreviousState;
-
- /* Check if parameters are valid */
- if(PreviousMode != KernelMode) {
-
- _SEH_TRY {
-
- ProbeForWriteUlong(SuspendCount);
-
- } _SEH_HANDLE {
-
- Status = _SEH_GetExceptionCode();
-
- } _SEH_END;
- }
-
- /* Reference the Object */
- Status = ObReferenceObjectByHandle(ThreadHandle,
- THREAD_SUSPEND_RESUME,
- PsThreadType,
- PreviousMode,
- (PVOID*)&Thread,
- NULL);
-
- /* Check for Success */
- if (NT_SUCCESS(Status)) {
-
- /* Call the Kernel Function */
- PreviousState = KeAlertResumeThread(&Thread->Tcb);
-
- /* Dereference Object */
- ObDereferenceObject(Thread);
-
- if (SuspendCount) {
-
- _SEH_TRY {
-
- *SuspendCount = PreviousState;
-
- } _SEH_HANDLE {
-
- Status = _SEH_GetExceptionCode();
-
- } _SEH_END;
- }
- }
-
- /* Return status */
- return Status;
-}
-
-/*
- * @implemented
- *
- * EXPORTED
- */
-NTSTATUS
-STDCALL
-NtAlertThread (IN HANDLE ThreadHandle)
-{
- KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
- PETHREAD Thread;
- NTSTATUS Status;
-
- /* Reference the Object */
- Status = ObReferenceObjectByHandle(ThreadHandle,
- THREAD_SUSPEND_RESUME,
- PsThreadType,
- PreviousMode,
- (PVOID*)&Thread,
- NULL);
-
- /* Check for Success */
- if (NT_SUCCESS(Status)) {
-
- /*
- * Do an alert depending on the processor mode. If some kmode code wants to
- * enforce a umode alert it should call KeAlertThread() directly. If kmode
- * code wants to do a kmode alert it's sufficient to call it with Zw or just
- * use KeAlertThread() directly
- */
- KeAlertThread(&Thread->Tcb, PreviousMode);
-
- /* Dereference Object */
- ObDereferenceObject(Thread);
- }
-
- /* Return status */
- return Status;
-}
-
NTSTATUS
STDCALL
NtDelayExecution(IN BOOLEAN Alertable,