/*
 * PROJECT: Alcyone System Kernel
 * LICENSE: BSD Clause 3
 * PURPOSE: Mutexes
 * NT KERNEL: 5.11.9360
 * COPYRIGHT:  2023-2029 Dibymartanda Samanta <>
 */ 


#include <ntoskrnl.h>
#define NTDEBUG

extern "C"
/*Mutex Count :
0 => Can Be aquired, 
1 => Is Aquired by a Thread 
In Negative Indigates, Number of Threads waiting*/

constexpr ULONG MUTEX_READY_TO_BE_AQUIRED = 0;

/*Internal Function*/ 

typedef struct _FAST_MUTEX
{
    LONG Count;                                                             //0x0
    VOID* Owner;                                                            //0x4
    ULONG Contention;                                                       //0x8
    struct _KEVENT Event;                                                   //0xc
    ULONG OldIrql;                                                          //0x1c
} FAST_MUTEX, *PFAST_MUTEX;                                                 //0x20 bytes (sizeof)

/*Internal Functio*/
VOID
FASTCALL
KiAcquireFastMutex(
    _Inout_ PFAST_MUTEX Mutex
    )
{
    LONG AcquireMarker;
    LONG AcquireBit;
    LONG OldCount;

    PAGED_CODE();

    /* Increment contention count */
    InterlockedIncrement(&Mutex->Contention);

    /* Initialize loop variables */
    AcquireMarker = 4;
    AcquireBit = 1;

AcquireLoop:
    while(true)
    {
        /* Read current count */
        OldCount = ReadForWriteAccess(&Mutex->Count);

        /* Check if mutex is free */
        if ((OldCount & 1) == 0)
        {
            /* Attempt to acquire by incrementing count */
            if (InterlockedCompareExchange(&Mutex->Count, OldCount + AcquireMarker,OldCount) == OldCount)
            {
                /* Wait for the mutex event */
                KeWaitForSingleObject(&Mutex->Event,WrFastMutex,KernelMode,false,0);

                AcquireMarker = 2;
                AcquireBit = 3;
                goto AcquireLoop;
            }
        }
        else
        {
            /* Attempt to mark mutex as owned */
            if (InterlockedCompareExchange(&Mutex->Count, AcquireBit ^ OldCount,OldCount) == OldCount)
            {
                /* Mutex acquired successfully */
                break;
            }
        }
    }
}

/* Exported   Function */ 

VOID
NTAPI
KeInitializeFastMutex(
    _Out_ PFAST_MUTEX Mutex
    )
{
    PAGED_CODE();

    /* Initialize the mutex structure */
    RtlZeroMemory(Mutex, sizeof(FAST_MUTEX));

    /* Set initial values */
    Mutex->Owner = nullptr;
    Mutex->Contention = 0;
    Mutex->Count = 1;

    /* Initialize the Mutex Gate */
    KeInitializeEvent(&Mutex->Event, SynchronizationEvent, FALSE);
}

BOOLEAN
VECTORCALL
KeTryToAcquireFastMutex(
    _Inout_ PFAST_MUTEX Mutex)
{
    KIRQL CurrentIrql = KeGetCurrentIrql();
    BOOLEAN Result = false; 
    if(_InterlockedBitTestAndReset(&FastMutex->Count, MUTEX_READY_TO_BE_AQUIRED))
    {  
        FastMutex->Owner = (PVOID)KeGetCurrentThread();
        Mutex->OldIrql = KeRaiseIrql(APC_LEVEL);
        Result = TRUE;
    }
    else 
    {
        /* Failed to acquire the mutex */
        KeLowerIrql(CurrentIrql);
        KeYieldProcessor();
        Result = FALSE;
    }
    
return Result;
}