[NTOSKRNL:KE] Added Spinning Ring
*Added Spinning Ring Lock Implementation *Added Information/Objective of the function *Provided Methodology for Faster Modulus Operator.
This commit is contained in:
parent
3adfb0cff6
commit
3eacac0223
179
NTOSKRNL/KE/sringlock.cpp
Normal file
179
NTOSKRNL/KE/sringlock.cpp
Normal file
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* PROJECT: Alcyone System Kernel
|
||||
* LICENSE: BSD Clause 3
|
||||
* PURPOSE: Spinning Ring Lock
|
||||
* NT KERNEL: 5.11.9360
|
||||
* COPYRIGHT: 2023-2029 Dibymartanda Samanta <>
|
||||
*/
|
||||
|
||||
/*Alcyone's Spinning Ring Lock is a tweaked Mellor-Crummey and Scott Spin Lock algorithm that utilizes a Ring Buffer for
|
||||
implementing a FIFO algorithm for lock acquisition and unlocking. The Ring Buffer queue is completely lock-free, utilizing a Hazard
|
||||
Pointer for accessing members of the structure.
|
||||
|
||||
It has been designed for high contention scenarios to provide:
|
||||
|
||||
- High degree of scalability
|
||||
- Fairness
|
||||
- Reduced cache coherency traffic
|
||||
- Reduced latency
|
||||
- Superior cache line utilization
|
||||
|
||||
Note: The Spinning Ring Lock should only be used when dealing with high contention scenarios */
|
||||
|
||||
/* Spinning Ring Lock Data Type */
|
||||
typedef struct _MCS_NODE {
|
||||
struct _MCS_NODE* Next;
|
||||
LONG Locked;
|
||||
} MCS_NODE, *PMCS_NODE;
|
||||
|
||||
typedef struct _SRING_LOCK {
|
||||
volatile PMCS_NODE Tail;
|
||||
MCS_NODE RingBuffer[RING_BUFFER_SIZE];
|
||||
volatile LONG64 Head;
|
||||
volatile LONG64 Tail;
|
||||
volatile PMCS_NODE HazardPointer;
|
||||
} SRING_LOCK, *PSRING_LOCK;
|
||||
|
||||
/* In Future if needed Size can be increased , but fallback to Dynamic Allocation is present*/
|
||||
#define RING_BUFFER_SIZE 256
|
||||
|
||||
|
||||
/* Internal Function for MCS Node Allocation */
|
||||
PMCS_NODE
|
||||
KiAllocateRingLockNode(
|
||||
_Inout_ PSRING_LOCK Lock
|
||||
)
|
||||
{
|
||||
LONG64 OldTail, NewTail;
|
||||
PMCS_NODE Node;
|
||||
|
||||
do {
|
||||
OldTail = Lock->Tail;
|
||||
NewTail = (OldTail + 1) & (RING_BUFFER_SIZE - 1);
|
||||
|
||||
if (NewTail == (Lock->Head & (RING_BUFFER_SIZE - 1)))
|
||||
{
|
||||
/*Ring buffer is full, fallback to dynamic allocation*/
|
||||
return ExAllocatePoolWithTag(NonPagedPool, sizeof(MCS_NODE), 'MCSN');
|
||||
}
|
||||
} while (InterlockedCompareExchange64(&Lock->Tail, NewTail, OldTail) != OldTail);
|
||||
|
||||
Node = &Lock->RingBuffer[OldTail];
|
||||
|
||||
/*Set hazard pointer to protect the node from being freed*/
|
||||
InterlockedExchangePointer((PVOID*)&Lock->HazardPointer, Node);
|
||||
KeMemoryBarrier();
|
||||
|
||||
return Node;
|
||||
}
|
||||
VOID
|
||||
KiFreeRingLockNode(
|
||||
_Inout_ PSRING_LOCK Lock,
|
||||
_In_ PMCS_NODE Node
|
||||
)
|
||||
{
|
||||
if (Node < &Lock->RingBuffer[0] || Node >= &Lock->RingBuffer[RING_BUFFER_SIZE]) {
|
||||
/* Node was dynamically allocated, free the pool */
|
||||
ExFreePoolWithTag(Node, 'MCSN');
|
||||
return;
|
||||
}
|
||||
|
||||
/*Clear hazard pointer if it's pointing to this node*/
|
||||
if (InterlockedCompareExchangePointer((PVOID*)&Lock->HazardPointer, NULL, Node) == Node) {
|
||||
LONG64 NewHead;
|
||||
do {
|
||||
NewHead = (Lock->Head + 1) & (RING_BUFFER_SIZE - 1);
|
||||
} while (InterlockedCompareExchange64(&Lock->Head, NewHead, Lock->Head) != Lock->Head);
|
||||
}
|
||||
}
|
||||
|
||||
/* External Function */
|
||||
|
||||
KeInitializeSpinningRingLock(
|
||||
_Out_ PSRING_LOCK Lock
|
||||
)
|
||||
{
|
||||
Lock->Tail = NULL;
|
||||
RtlZeroMemory(Lock->RingBuffer, sizeof(Lock->RingBuffer));
|
||||
Lock->Head = 0;
|
||||
Lock->Tail = 0;
|
||||
Lock->HazardPointer = NULL;
|
||||
}
|
||||
|
||||
VOID
|
||||
KeAcquireSpinningRingLock(
|
||||
_Inout_ PSRING_LOCK Lock
|
||||
)
|
||||
{
|
||||
PMCS_NODE Node = KiAllocateRingLockNode(Lock);
|
||||
PMCS_NODE Predecessor;
|
||||
|
||||
Node->Next = NULL;
|
||||
Node->Locked = 1;
|
||||
|
||||
// Set hazard pointer before we exchange
|
||||
InterlockedExchangePointer((PVOID*)&Lock->HazardPointer, Node);
|
||||
KeMemoryBarrier();
|
||||
|
||||
Predecessor = (PMCS_NODE)InterlockedExchangePointer((PVOID*)&Lock->Tail, Node);
|
||||
|
||||
if (Predecessor != NULL) {
|
||||
/*Set hazard pointer to predecessor*/
|
||||
InterlockedExchangePointer((PVOID*)&Lock->HazardPointer, Predecessor);
|
||||
KeMemoryBarrier();
|
||||
|
||||
Predecessor->Next = Node;
|
||||
while (Node->Locked) {
|
||||
KeYieldProcessor();
|
||||
}
|
||||
}
|
||||
|
||||
/*Clear hazard pointer*/
|
||||
InterlockedExchangePointer((PVOID*)&Lock->HazardPointer, NULL);
|
||||
}
|
||||
|
||||
VOID
|
||||
KeReleaseSpinningRingLock(
|
||||
_Inout_ PSRING_LOCK Lock
|
||||
)
|
||||
{
|
||||
PMCS_NODE Node = Lock->Tail;
|
||||
|
||||
// Set hazard pointer
|
||||
InterlockedExchangePointer((PVOID*)&Lock->HazardPointer, Node);
|
||||
KeMemoryBarrier();
|
||||
|
||||
if (Node->Next == NULL) {
|
||||
if (InterlockedCompareExchangePointer((PVOID*)&Lock->Tail, NULL, Node) == Node)
|
||||
{
|
||||
/*Clear hazard pointer before returning*/
|
||||
InterlockedExchangePointer((PVOID*)&Lock->HazardPointer, NULL);
|
||||
KiFreeRingLockNode(Lock, Node);
|
||||
return;
|
||||
}
|
||||
|
||||
while (Node->Next == NULL) {
|
||||
KeYieldProcessor();
|
||||
}
|
||||
}
|
||||
|
||||
/*Set hazard pointer to next node*/
|
||||
InterlockedExchangePointer((PVOID*)&Lock->HazardPointer, Node->Next);
|
||||
KeMemoryBarrier();
|
||||
|
||||
Node->Next->Locked = 0;
|
||||
|
||||
/*Clear hazard pointer*/
|
||||
InterlockedExchangePointer((PVOID*)&Lock->HazardPointer, NULL);
|
||||
|
||||
KiFreeRingLockNode(Lock, Node);
|
||||
}
|
||||
|
||||
/* Understanding Bit Manipulation being done to retrieving data from RING Buffer,
|
||||
(Lock->Tail + 1) & (RING_BUFFER_SIZE - 1)
|
||||
RING_BUFFER_SIZE` is defined as 256, which is a power of 2. This is crucial for this operation to work.
|
||||
(RING_BUFFER_SIZE - 1)` is 255, which in binary is "11111111"
|
||||
(Lock->Tail + 1)` increments the tail index.
|
||||
Now, bitwise AND operation `&` with `(RING_BUFFER_SIZE - 1) act like % Operator but much faster in performance */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user