Files
exectos/xtoskrnl/ke/kthread.cc
Aiken Harris f680830b53
All checks were successful
Builds / ExectOS (i686, debug) (push) Successful in 45s
Builds / ExectOS (amd64, release) (push) Successful in 47s
Builds / ExectOS (amd64, debug) (push) Successful in 47s
Builds / ExectOS (i686, release) (push) Successful in 45s
Implement resource cleanup for failed allocations during idle thread setup
2026-06-04 14:36:43 +02:00

381 lines
11 KiB
C++

/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtoskrnl/ke/kthread.cc
* DESCRIPTION: XT kernel thread manipulation support
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include <xtos.hh>
/**
* Retrieves a pointer to the system's initial executive thread object.
*
* @return This routine returns a pointer to the initial executive thread.
*
* @since XT 1.0
*/
XTAPI
PETHREAD
KE::KThread::GetInitialThread(VOID)
{
return &InitialThread;
}
/**
* Initializes an Idle Thread.
*
* @param IdleProcess
* Supplies a pointer to the global Idle Process container.
*
* @param IdleThread
* Supplies a pointer to the KTHREAD structure being initialized.
*
* @param Prcb
* Supplies a pointer to the Processor Control Block of the target CPU.
*
* @param Stack
* Supplies a pointer to the pre-allocated kernel stack for this thread.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTAPI
XTSTATUS
KE::KThread::InitializeIdleThread(IN PKPROCESS IdleProcess,
IN OUT PKTHREAD IdleThread,
IN PKPROCESSOR_CONTROL_BLOCK Prcb,
IN PVOID Stack)
{
ULONG AffinitySize, CpuIndex, CpuTargetBit, MapSize;
PACPI_SYSTEM_INFO SysInfo;
XTSTATUS Status;
/* Retrieve hardware topology from ACPI */
HL::Acpi::GetSystemInformation(&SysInfo);
/* Calculate the required size for KAFFINITY_MAP structures */
AffinitySize = (SysInfo->CpuCount + 63) / 64;
MapSize = sizeof(KAFFINITY_MAP) + (AffinitySize * sizeof(KAFFINITY));
/* Align size to the 8-byte boundary */
MapSize = (MapSize + 7) & ~7;
/* Allocate the thread-level affinity structure */
Status = MM::Allocator::AllocatePool(NonPagedPool, MapSize, (PVOID*)&IdleThread->Affinity);
if(Status != STATUS_SUCCESS)
{
/* Memory allocation failed, return the status code */
return Status;
}
/* Allocate the thread-level user affinity structure */
Status = MM::Allocator::AllocatePool(NonPagedPool, MapSize, (PVOID*)&IdleThread->UserAffinity);
if(Status != STATUS_SUCCESS)
{
/* Memory allocation failed, free previously allocated memory and return the status code */
MM::Allocator::FreePool((PVOID)IdleThread->Affinity);
return Status;
}
/* Zero the thread-level affinity structures */
RTL::Memory::ZeroMemory(IdleThread->Affinity, MapSize);
RTL::Memory::ZeroMemory(IdleThread->UserAffinity, MapSize);
/* Initialize Idle thread */
Status = KE::KThread::InitializeThread(IdleProcess, IdleThread, NULLPTR, NULLPTR, NULLPTR,
NULLPTR, NULLPTR, Stack, TRUE);
if(Status != STATUS_SUCCESS)
{
/* Failed to initialize IDLE thread, free both affinity maps and return the status code */
MM::Allocator::FreePool((PVOID)IdleThread->Affinity);
MM::Allocator::FreePool((PVOID)IdleThread->UserAffinity);
return Status;
}
/* Configure Idle thread scheduling parameters */
IdleThread->NextProcessor = Prcb->CpuNumber;
IdleThread->Priority = THREAD_HIGH_PRIORITY;
IdleThread->State = Running;
IdleThread->WaitRunLevel = DISPATCH_LEVEL;
/* Calculate exact block array index and bit offset for this specific CPU */
CpuIndex = Prcb->CpuNumber / 64;
CpuTargetBit = Prcb->CpuNumber % 64;
/* Configure Idle thread affinity */
IdleThread->Affinity->Bitmap[CpuIndex] = ((KAFFINITY)1 << CpuTargetBit);
IdleThread->Affinity->Count = (USHORT)(CpuIndex + 1);
IdleThread->Affinity->Size = (USHORT)AffinitySize;
/* Configure Idle thread user affinity */
IdleThread->UserAffinity->Bitmap[CpuIndex] = ((KAFFINITY)1 << CpuTargetBit);
IdleThread->UserAffinity->Count = (USHORT)(CpuIndex + 1);
IdleThread->UserAffinity->Size = (USHORT)AffinitySize;
/* Register this CPU as active in the Idle Process */
IdleProcess->ActiveProcessors->Bitmap[CpuIndex] |= ((KAFFINITY)1 << CpuTargetBit);
/* Return success */
return STATUS_SUCCESS;
}
/**
* Initializes the thread.
*
* @param Process
* Supplies a pointer to the process that owns the thread.
*
* @param Thread
* Supplies a pointer to thread that will be initialized.
*
* @param SystemRoutine
* Supplies a pointer to the routine called during first scheduling.
*
* @param StartRoutine
* Supplies a pointer to the routine called during thread startup.
*
* @param StartContext
* Supplies a pointer to a context data that will be passed to start routine.
*
* @param Context
* Supplies a pointer to the context frame containing state of the user mode thread.
*
* @param EnvironmentBlock
* Supplies a pointer to the environment block of the thread.
*
* @param Stack
* Supplies a pointer to the stack of the thread.
*
* @return This routine returns a status code indicating the success or failure of the operation.
*
* @since XT 1.0
*/
XTAPI
XTSTATUS
KE::KThread::InitializeThread(IN PKPROCESS Process,
IN OUT PKTHREAD Thread,
IN PKSYSTEM_ROUTINE SystemRoutine,
IN PKSTART_ROUTINE StartRoutine,
IN PVOID StartContext,
IN PCONTEXT Context,
IN PVOID EnvironmentBlock,
IN PVOID Stack,
IN BOOLEAN RunThread)
{
PKWAIT_BLOCK TimerWaitBlock;
BOOLEAN Allocation;
XTSTATUS Status;
ULONG Index;
/* No stack allocation was done yet */
Allocation = FALSE;
/* Initialize thread dispatcher header */
Thread->Header.Type = ThreadObject;
Thread->Header.SignalState = 0;
/* Initialize thread wait list */
RTL::LinkedList::InitializeListHead(&Thread->Header.WaitListHead);
/* Initialize thread mutant list head */
RTL::LinkedList::InitializeListHead(&Thread->MutantListHead);
/* Initialize the builtin wait blocks */
for(Index = 0; Index <= KTHREAD_WAIT_BLOCK; Index++)
{
Thread->WaitBlock[Index].Thread = Thread;
}
/* Initialize stack resident and stack swap */
Thread->AutoAlignment = Process->AutoAlignment;
Thread->StackResident = TRUE;
Thread->StackSwap = TRUE;
Thread->SwapBusy = FALSE;
/* Set priority adjustment reason */
Thread->AdjustReason = AdjustNone;
/* Initialize thread lock */
KE::SpinLock::InitializeSpinLock(&Thread->ThreadLock);
/* Initialize thread APC */
Thread->ApcStatePointer[0] = &Thread->ApcState;
Thread->ApcStatePointer[1] = &Thread->SavedApcState;
Thread->ApcQueueable = TRUE;
Thread->ApcState.Process = Process;
Thread->Process = Process;
/* Initialize APC list heads */
RTL::LinkedList::InitializeListHead(&Thread->ApcState.ApcListHead[KernelMode]);
RTL::LinkedList::InitializeListHead(&Thread->ApcState.ApcListHead[UserMode]);
/* Initialize APC queue lock */
KE::SpinLock::InitializeSpinLock(&Thread->ApcQueueLock);
/* Initialize kernel-mode suspend APC */
KE::Apc::InitializeApc(&Thread->SuspendApc, Thread, OriginalApcEnvironment, SuspendNop,
SuspendRundown, SuspendThread, KernelMode, NULLPTR);
/* Initialize suspend semaphore */
KE::Semaphore::InitializeSemaphore(&Thread->SuspendSemaphore, 0, 2);
/* Initialize the builtin timer */
KE::Timer::InitializeTimer(&Thread->Timer, NotificationTimer);
TimerWaitBlock = &Thread->WaitBlock[KTIMER_WAIT_BLOCK];
TimerWaitBlock->Object = &Thread->Timer;
TimerWaitBlock->WaitKey = STATUS_TIMEOUT;
TimerWaitBlock->WaitType = WaitAny;
TimerWaitBlock->WaitListEntry.Flink = &(&Thread->Timer)->Header.WaitListHead;
TimerWaitBlock->WaitListEntry.Blink = &(&Thread->Timer)->Header.WaitListHead;
/* Initialize Thread Environment Block*/
Thread->EnvironmentBlock = (PTHREAD_ENVIRONMENT_BLOCK)EnvironmentBlock;
/* Make sure there is a valid stack available */
if(!Stack)
{
/* Allocate new stack */
Status = MM::KernelPool::AllocateKernelStack(&Stack, KERNEL_STACK_SIZE);
if(Status != STATUS_SUCCESS || !Stack)
{
/* Stack allocation failed */
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Mark allocation as successful */
Allocation = TRUE;
}
Thread->InitialStack = Stack;
Thread->StackBase = Stack;
Thread->StackLimit = (PVOID)((ULONG_PTR)Stack - KERNEL_STACK_SIZE);
__try
{
/* Initialize thread context */
InitializeThreadContext(Thread, SystemRoutine, StartRoutine, StartContext, Context);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
/* Failed to initialize thread context, check stack allocation */
if(Allocation)
{
/* Deallocate stack */
MM::KernelPool::FreeKernelStack(Stack, FALSE);
Thread->InitialStack = NULLPTR;
Thread->StackBase = NULLPTR;
}
/* Thread initialization failed */
return STATUS_UNSUCCESSFUL;
}
/* Mark thread as initialized and run it */
Thread->State = Initialized;
/* Check if thread should be started */
if(RunThread)
{
/* Start thread */
StartThread(Thread);
}
/* Return success */
return STATUS_SUCCESS;
}
/**
* Starts the thread.
*
* @param Thread
* Supplies a pointer to the thread.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTAPI
VOID
KE::KThread::StartThread(IN PKTHREAD Thread)
{
UNIMPLEMENTED;
}
/**
* Suspend APC-built thread NOP routine. It takes no actions.
*
* @param Apc
* Supplies a pointer to the APC object.
*
* @param NormalRoutine
* Supplies a pointer to the normal routine set during the APC initialization. Unused by this routine.
*
* @param NormalContext
* Supplies a pointer a context data set during the APC initialization. Unused by this routine.
*
* @param SystemArgument1
* Supplies a pointer to an unused system argument.
*
* @param SystemArgument2
* Supplies a pointer to an unused system argument.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTAPI
VOID
KE::KThread::SuspendNop(IN PKAPC Apc,
IN OUT PKNORMAL_ROUTINE *NormalRoutine,
IN OUT PVOID *NormalContext,
IN OUT PVOID *SystemArgument1,
IN OUT PVOID *SystemArgument2)
{
/* No action here */
}
/**
* Suspend APC-built thread rundown routine. It takes no actions.
*
* @param Apc
* Supplies a pointer to the APC object.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTAPI
VOID
KE::KThread::SuspendRundown(IN PKAPC Apc)
{
/* No action here */
}
/**
* Suspends thread execution by waiting on the thread's semaphore.
*
* @param NormalContext
* Supplies a pointer a context data set during the APC initialization. Unused by this routine.
*
* @param SystemArgument1
* Supplies a pointer to an unused system argument.
*
* @param SystemArgument2
* Supplies a pointer to an unused system argument.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTAPI
VOID
KE::KThread::SuspendThread(IN PVOID NormalContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2)
{
UNIMPLEMENTED;
}