Add dispatcher object routing for wait satisfaction and interval calculation
Some checks failed
Builds / ExectOS (i686, debug) (push) Failing after 30s
Builds / ExectOS (amd64, debug) (push) Failing after 32s
Builds / ExectOS (amd64, release) (push) Failing after 32s
Builds / ExectOS (i686, release) (push) Failing after 29s

This commit is contained in:
2026-06-28 23:25:45 +02:00
parent 3011df6f3c
commit 119480382b
7 changed files with 331 additions and 1 deletions

View File

@@ -67,6 +67,9 @@
#define READY_SKIP_QUANTUM 2 #define READY_SKIP_QUANTUM 2
#define THREAD_QUANTUM 6 #define THREAD_QUANTUM 6
/* Dispatcher object type mask */
#define DISPATCHER_OBJECT_TYPE_MASK 0x7L
/* Thread priority levels */ /* Thread priority levels */
#define THREAD_LOW_PRIORITY 0 #define THREAD_LOW_PRIORITY 0
#define THREAD_LOW_REALTIME_PRIORITY 16 #define THREAD_LOW_REALTIME_PRIORITY 16

View File

@@ -49,6 +49,7 @@ list(APPEND XTOSKRNL_SOURCE
${XTOSKRNL_SOURCE_DIR}/ke/crash.cc ${XTOSKRNL_SOURCE_DIR}/ke/crash.cc
${XTOSKRNL_SOURCE_DIR}/ke/data.cc ${XTOSKRNL_SOURCE_DIR}/ke/data.cc
${XTOSKRNL_SOURCE_DIR}/ke/dispatch.cc ${XTOSKRNL_SOURCE_DIR}/ke/dispatch.cc
${XTOSKRNL_SOURCE_DIR}/ke/dispobj.cc
${XTOSKRNL_SOURCE_DIR}/ke/dpc.cc ${XTOSKRNL_SOURCE_DIR}/ke/dpc.cc
${XTOSKRNL_SOURCE_DIR}/ke/event.cc ${XTOSKRNL_SOURCE_DIR}/ke/event.cc
${XTOSKRNL_SOURCE_DIR}/ke/exports.cc ${XTOSKRNL_SOURCE_DIR}/ke/exports.cc

View File

@@ -16,6 +16,7 @@
#include <ke/bootinfo.hh> #include <ke/bootinfo.hh>
#include <ke/crash.hh> #include <ke/crash.hh>
#include <ke/dispatch.hh> #include <ke/dispatch.hh>
#include <ke/dispobj.hh>
#include <ke/dpc.hh> #include <ke/dpc.hh>
#include <ke/event.hh> #include <ke/event.hh>
#include <ke/guard.hh> #include <ke/guard.hh>

View File

@@ -23,10 +23,20 @@ namespace KE
STATIC XTCDECL VOID HandleDispatchInterrupt(IN PKTRAP_FRAME TrapFrame); STATIC XTCDECL VOID HandleDispatchInterrupt(IN PKTRAP_FRAME TrapFrame);
STATIC XTFASTCALL BOOLEAN SwitchContext(IN PKTHREAD CurrentThread, STATIC XTFASTCALL BOOLEAN SwitchContext(IN PKTHREAD CurrentThread,
IN KRUNLEVEL RunLevel); IN KRUNLEVEL RunLevel);
STATIC XTAPI XTSTATUS WaitForSingleObject(IN PVOID Object,
IN KWAIT_REASON WaitReason,
IN KPROCESSOR_MODE WaitMode,
IN BOOLEAN Alertable,
IN PLARGE_INTEGER Timeout);
STATIC XTAPI VOID UpdateRunTime(IN PKTRAP_FRAME TrapFrame, STATIC XTAPI VOID UpdateRunTime(IN PKTRAP_FRAME TrapFrame,
IN KRUNLEVEL RunLevel); IN KRUNLEVEL RunLevel);
private: private:
STATIC XTFASTCALL PLARGE_INTEGER ComputeWaitInterval(IN PLARGE_INTEGER OriginalDueTime,
IN PLARGE_INTEGER PreviousDueTime,
IN OUT PLARGE_INTEGER NewDueTime);
STATIC XTFASTCALL XTSTATUS SatisfyWaitingObject(IN PDISPATCHER_HEADER Object,
IN PKTHREAD Thread);
STATIC XTFASTCALL BOOLEAN SwitchThreadContext(IN PKTHREAD CurrentThread, STATIC XTFASTCALL BOOLEAN SwitchThreadContext(IN PKTHREAD CurrentThread,
IN BOOLEAN ApcBypass); IN BOOLEAN ApcBypass);
STATIC XTFASTCALL BOOLEAN SwitchThreadStack(IN PKTHREAD CurrentThread, STATIC XTFASTCALL BOOLEAN SwitchThreadStack(IN PKTHREAD CurrentThread,

View File

@@ -0,0 +1,29 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtoskrnl/includes/ke/dispobj.hh
* DESCRIPTION: Kernel Thread Dispatcher Objects
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
*/
#ifndef __XTOSKRNL_KE_DISPOBJ_HH
#define __XTOSKRNL_KE_DISPOBJ_HH
#include <xtos.hh>
/* Kernel Library */
namespace KE
{
class DispatcherObject
{
public:
STATIC XTFASTCALL VOID SatisfyWaitingMutexObject(IN PKMUTEX MutexObject,
IN PKTHREAD Thread);
STATIC XTFASTCALL VOID SatisfyWaitingNonMutexObject(IN PDISPATCHER_HEADER MutexObject);
STATIC XTFASTCALL VOID SatisfyWaitingObject(IN PDISPATCHER_HEADER MutexObject,
IN PKTHREAD Thread);
};
}
#endif /* __XTOSKRNL_KE_DISPOBJ_HH */

View File

@@ -10,6 +10,45 @@
#include <xtos.hh> #include <xtos.hh>
/**
* Calculates the remaining wait interval for a thread after a wait operation has been interrupted.
*
* @param OriginalDueTime
* Supplies the original timeout value requested by the caller.
*
* @param PreviousDueTime
* Supplies the base timestamp, usually the time when the wait was first initiated.
*
* @param NewDueTime
* Supplies a pointer to a LARGE_INTEGER buffer where the recalculated time will be stored.
*
* @return This routine returns a pointer to the resulting due time.
*
* @since XT 1.0
*/
XTFASTCALL
PLARGE_INTEGER
KE::Dispatcher::ComputeWaitInterval(IN PLARGE_INTEGER OriginalDueTime,
IN PLARGE_INTEGER PreviousDueTime,
IN OUT PLARGE_INTEGER NewDueTime)
{
/* Check if the timeout is absolute */
if(OriginalDueTime->QuadPart >= 0)
{
/* No recalculation is needed, return the original value */
return OriginalDueTime;
}
/* Fetch the current system interrupt time for the recalculation base */
KE::SystemTime::GetInterruptTime(NewDueTime);
/* Calculate the delta */
NewDueTime->QuadPart -= PreviousDueTime->QuadPart;
/* Return the new due time */
return NewDueTime;
}
/** /**
* Enters the system idle thread loop for the current processor, running continuously when no other * Enters the system idle thread loop for the current processor, running continuously when no other
* threads are scheduled for execution. * threads are scheduled for execution.
@@ -149,7 +188,7 @@ KE::Dispatcher::HandleDispatchInterrupt(IN PKTRAP_FRAME TrapFrame)
/* Start a guarded code block */ /* Start a guarded code block */
{ {
/* Lock the processor control block */ /* Lock the processor control block */
KE::SpinLockGuard ControlBlockGuard(&Prcb->PrcbLock); KE::SpinLockGuard PrcbGuard(&Prcb->PrcbLock);
/* Capture the outgoing (preempted) and incoming threads */ /* Capture the outgoing (preempted) and incoming threads */
CurrentThread = Prcb->CurrentThread; CurrentThread = Prcb->CurrentThread;
@@ -175,6 +214,60 @@ KE::Dispatcher::HandleDispatchInterrupt(IN PKTRAP_FRAME TrapFrame)
AR::CpuFunctions::ClearInterruptFlag(); AR::CpuFunctions::ClearInterruptFlag();
} }
/**
* Evaluates the state of a dispatcher object to determine if a wait can be satisfied immediately without
* suspending the current thread.
*
* @param Object
* Supplies a pointer to the dispatcher object header.
*
* @param Thread
* Supplies a pointer to the current thread attempting to acquire the object.
*
* @return This routine returns a status code indicating the success or failure of the operation.
*
* @since XT 1.0
*/
XTFASTCALL
XTSTATUS
KE::Dispatcher::SatisfyWaitingObject(IN PDISPATCHER_HEADER Object,
IN PKTHREAD Thread)
{
PKMUTEX Mutex;
/* Check if the object is a Mutex */
if(Object->Type == MutexObject)
{
/* Get a pointer to the Mutex object */
Mutex = (PKMUTEX)Object;
/* Check if the mutex is free or if the current thread already owns it */
if((Mutex->Header.SignalState > 0) || (Thread == Mutex->OwnerThread))
{
/* Verify that recursive acquisition has not hit the mathematical lower bound */
if(Mutex->Header.SignalState != MINLONG)
{
/* Satisfy the wait and inherit priority if applicable */
KE::DispatcherObject::SatisfyWaitingMutexObject(Mutex, Thread);
return (XTSTATUS)Thread->WaitStatus;
}
/* The mutex counter has overflowed */
return STATUS_MUTEX_LIMIT_EXCEEDED;
}
}
else if(Object->SignalState > 0)
{
/* Apply generic satisfaction rules */
KE::DispatcherObject::SatisfyWaitingNonMutexObject(Object);
return STATUS_WAIT_0;
}
/* Object is not signaled, the thread must be queued */
return STATUS_PENDING;
}
/** /**
* Updates the runtime quantum of the currently executing thread and handles preemption. * Updates the runtime quantum of the currently executing thread and handles preemption.
* *
@@ -291,3 +384,83 @@ KE::Dispatcher::UpdateRunTime(IN PKTRAP_FRAME TrapFrame,
HL::Irq::SendSoftwareInterrupt(DISPATCH_LEVEL); HL::Irq::SendSoftwareInterrupt(DISPATCH_LEVEL);
} }
} }
/**
* Places the current thread into a wait state until the specified dispatcher object is set to a signaled state,
* or until the optional timeout expires.
*
* @param Object
* Supplies a pointer to the dispatcher object to wait on.
*
* @param WaitReason
* Supplies the reason for the wait, utilized for diagnostic and profiling purposes.
*
* @param WaitMode
* Supplies the processor mode in which the wait is occurring (KernelMode or UserMode).
*
* @param Alertable
* Specifies whether the wait is alertable by asynchronous procedure calls (APCs).
*
* @param Timeout
* Supplies an optional pointer to an absolute or relative timeout value.
*
* @return This routine returns the completion status of the wait operation.
*
* @since XT 1.0
*/
XTAPI
XTSTATUS
KE::Dispatcher::WaitForSingleObject(IN PVOID Object,
IN KWAIT_REASON WaitReason,
IN KPROCESSOR_MODE WaitMode,
IN BOOLEAN Alertable,
IN PLARGE_INTEGER Timeout)
{
PDISPATCHER_HEADER Header;
LARGE_INTEGER CurrentTime;
PKTHREAD CurrentThread;
/* Not implemented, active polling only */
UNIMPLEMENTED;
/* Get the dispatcher header */
Header = (PDISPATCHER_HEADER)Object;
/* Get the current thread */
CurrentThread = KE::Processor::GetCurrentThread();
/* Check if the object is already signaled or if it is an already owned Mutex */
if((Header->SignalState > 0) || ((Header->Type == MutexObject) && (CurrentThread == ((PKMUTEX)Object)->OwnerThread)))
{
/* Satisfy the object and return status code */
SatisfyWaitingObject(Header, CurrentThread);
return STATUS_WAIT_0;
}
/* Enter cctive polling loop */
while(Header->SignalState <= 0)
{
/* Check if the timeout has expired */
if(Timeout != NULLPTR)
{
/* Get the current interrupt time */
KE::SystemTime::GetInterruptTime(&CurrentTime);
/* Check if current time exceeds the timeout value */
if(CurrentTime.QuadPart >= Timeout->QuadPart)
{
/* Wait expired, return status code */
return STATUS_TIMEOUT;
}
}
/* Yield the processor */
AR::CpuFunctions::YieldProcessor();
}
/* Apply acquisition rules */
SatisfyWaitingObject(Header, CurrentThread);
/* Return status code */
return STATUS_WAIT_0;
}

113
xtoskrnl/ke/dispobj.cc Normal file
View File

@@ -0,0 +1,113 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtoskrnl/ke/dispobj.cc
* DESCRIPTION: Kernel Thread Dispatcher Objects
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
*/
#include <xtos.hh>
/**
* Satisfies a wait operation specifically for a Mutex object.
*
* @param Mutex
* Supplies a pointer to the Mutex object being acquired.
*
* @param Thread
* Supplies a pointer to the thread that is acquiring the Mutex.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTFASTCALL
VOID
KE::DispatcherObject::SatisfyWaitingMutexObject(IN PKMUTEX Mutex,
IN PKTHREAD Thread)
{
/* Decrement the signal state */
Mutex->Header.SignalState--;
/* Check if the mutex is now fully acquired */
if(!Mutex->Header.SignalState)
{
/* Bind the mutex ownership to the current acquiring thread */
Mutex->OwnerThread = Thread;
/* Inherit the APC disable from the mutex */
Thread->KernelApcDisable = Thread->KernelApcDisable - Mutex->ApcDisable;
/* Check if the previous owner terminated without releasing the mutex */
if(Mutex->Abandoned)
{
/* Clear the abandonment flag */
Mutex->Abandoned = FALSE;
/* Alert the thread */
Thread->WaitStatus = STATUS_ABANDONED;
}
/* Track this mutex in the thread's local list */
RTL::LinkedList::InsertHeadList(Thread->MutexListHead.Blink, &Mutex->MutexListEntry);
}
}
/**
* Satisfies a wait operation for non-mutex dispatcher objects, such as Synchronization Events and Semaphores.
*
* @param Object
* Supplies a pointer to the dispatcher object.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTFASTCALL
VOID
KE::DispatcherObject::SatisfyWaitingNonMutexObject(IN PDISPATCHER_HEADER Object)
{
/* Check if the object is a Synchronization Event */
if((Object->Type & DISPATCHER_OBJECT_TYPE_MASK) == EventSynchronizationObject)
{
/* Reset the event */
Object->SignalState = 0;
}
else if(Object->Type == SemaphoreObject)
{
/* Decrement the signal state */
Object->SignalState--;
}
}
/**
* Evaluates the object type and routes the wait satisfaction logic to the appropriate specialized handler.
*
* @param Object
* Supplies a pointer to the dispatcher object being acquired.
*
* @param Thread
* Supplies a pointer to the thread acquiring the object.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTFASTCALL
VOID
KE::DispatcherObject::SatisfyWaitingObject(IN PDISPATCHER_HEADER Object,
IN PKTHREAD Thread)
{
/* Check if the object is a Mutex */
if(Object->Type == MutexObject)
{
/* Apply mutex-specific acquisition rules */
SatisfyWaitingMutexObject((PKMUTEX)Object, Thread);
}
else
{
/* Apply generic acquisition rules for events, semaphores, and timers */
SatisfyWaitingNonMutexObject(Object);
}
}