HyperDbg/hyperdbg/libhyperdbg/code/common/spinlock.cpp
2026-05-05 23:46:12 +02:00

122 lines
2.6 KiB
C++

/**
* @file spinlock.cpp
* @author Sina Karvandi (sina@hyperdbg.org)
* @brief This is the implementation for custom spinlock.
*
* @details This implementation is derived from Hvpp by Petr Benes
* - https://github.com/wbenny/hvpp
* Based on my benchmarks, this simple implementation beats other (often
* more complex) spinlock implementations - such as queue spinlocks, ticket
* spinlocks, MCS locks. The only difference between this implementation
* and completely naive spinlock is the "backoff".
*
* Also, benefit of this implementation is that we can use it with
* STL lock guards, e.g.: std::lock_guard.
*
* Look here for more information:
* - https://locklessinc.com/articles/locks/
* - https://github.com/cyfdecyf/spinlock
*
* @version 0.1
* @date 2022-05-19
*
* @copyright This project is released under the GNU Public License v3.
*
*/
#include "pch.h"
/**
* @brief The maximum wait before PAUSE
*
*/
static unsigned MaxWait = 65536;
/**
* @brief Tries to get the lock otherwise returns
*
* @param LONG Lock variable
* @return BOOLEAN If it was successful on getting the lock
*/
BOOLEAN
SpinlockTryLock(volatile LONG * Lock)
{
return (!(*Lock) && !_interlockedbittestandset(Lock, 0));
}
/**
* @brief Tries to get the lock and won't return until successfully get the lock
*
* @param LONG Lock variable
*/
void
SpinlockLock(volatile LONG * Lock)
{
unsigned wait = 1;
while (!SpinlockTryLock(Lock))
{
for (unsigned i = 0; i < wait; ++i)
{
CpuPause();
}
//
// Don't call "pause" too many times. If the wait becomes too big,
// clamp it to the MaxWait.
//
if (wait * 2 > MaxWait)
{
wait = MaxWait;
}
else
{
wait = wait * 2;
}
}
}
/**
* @brief Tries to get the lock and won't return until successfully get the lock
*
* @param LONG Lock variable
* @param LONG MaxWait Maximum wait (pause) count
*/
void
SpinlockLockWithCustomWait(volatile LONG * Lock, unsigned MaximumWait)
{
unsigned wait = 1;
while (!SpinlockTryLock(Lock))
{
for (unsigned i = 0; i < wait; ++i)
{
CpuPause();
}
//
// Don't call "pause" too many times. If the wait becomes too big,
// clamp it to the MaxWait.
//
if (wait * 2 > MaximumWait)
{
wait = MaximumWait;
}
else
{
wait = wait * 2;
}
}
}
/**
* @brief Release the lock
*
* @param LONG Lock variable
*/
void
SpinlockUnlock(volatile LONG * Lock)
{
*Lock = 0;
}