2022-05-19 02:06:26 +04:30
|
|
|
/**
|
|
|
|
|
* @file spinlock.cpp
|
|
|
|
|
* @author Sina Karvandi (sina@hyperdbg.org)
|
|
|
|
|
* @brief This is the implementation for custom spinlock.
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
|
|
|
|
* @details This implementation is derived from Hvpp by Petr Benes
|
2022-05-19 02:06:26 +04:30
|
|
|
* - 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".
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2022-05-19 02:06:26 +04:30
|
|
|
* Also, benefit of this implementation is that we can use it with
|
|
|
|
|
* STL lock guards, e.g.: std::lock_guard.
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2022-05-19 02:06:26 +04:30
|
|
|
* Look here for more information:
|
|
|
|
|
* - https://locklessinc.com/articles/locks/
|
|
|
|
|
* - https://github.com/cyfdecyf/spinlock
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2022-05-19 02:06:26 +04:30
|
|
|
* @version 0.1
|
|
|
|
|
* @date 2022-05-19
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2022-05-19 02:06:26 +04:30
|
|
|
* @copyright This project is released under the GNU Public License v3.
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2022-05-19 02:06:26 +04:30
|
|
|
*/
|
|
|
|
|
#include "pch.h"
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief The maximum wait before PAUSE
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2022-05-19 02:06:26 +04:30
|
|
|
*/
|
2026-05-31 18:34:03 +02:00
|
|
|
static UINT32 MaxWait = 65536;
|
2022-05-19 02:06:26 +04:30
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Tries to get the lock otherwise returns
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2026-05-31 18:34:03 +02:00
|
|
|
* @param Lock Lock variable
|
2023-03-23 18:42:33 +09:00
|
|
|
* @return BOOLEAN If it was successful on getting the lock
|
2022-05-19 02:06:26 +04:30
|
|
|
*/
|
|
|
|
|
BOOLEAN
|
|
|
|
|
SpinlockTryLock(volatile LONG * Lock)
|
|
|
|
|
{
|
2026-06-08 17:15:14 +02:00
|
|
|
return (!(*Lock) && !CpuInterlockedBitTestAndSet(Lock, 0));
|
2022-05-19 02:06:26 +04:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Tries to get the lock and won't return until successfully get the lock
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2026-05-31 18:34:03 +02:00
|
|
|
* @param Lock Lock variable
|
2022-05-19 02:06:26 +04:30
|
|
|
*/
|
2026-05-31 18:34:03 +02:00
|
|
|
VOID
|
2022-05-19 02:06:26 +04:30
|
|
|
SpinlockLock(volatile LONG * Lock)
|
|
|
|
|
{
|
2026-05-31 18:34:03 +02:00
|
|
|
UINT32 Wait = 1;
|
2022-05-19 02:06:26 +04:30
|
|
|
|
|
|
|
|
while (!SpinlockTryLock(Lock))
|
|
|
|
|
{
|
2026-05-31 18:34:03 +02:00
|
|
|
for (UINT32 i = 0; i < Wait; ++i)
|
2022-05-19 02:06:26 +04:30
|
|
|
{
|
2026-05-05 23:46:12 +02:00
|
|
|
CpuPause();
|
2022-05-19 02:06:26 +04:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Don't call "pause" too many times. If the wait becomes too big,
|
|
|
|
|
// clamp it to the MaxWait.
|
|
|
|
|
//
|
|
|
|
|
|
2026-05-31 18:34:03 +02:00
|
|
|
if (Wait * 2 > MaxWait)
|
2022-05-19 02:06:26 +04:30
|
|
|
{
|
2026-05-31 18:34:03 +02:00
|
|
|
Wait = MaxWait;
|
2022-05-19 02:06:26 +04:30
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2026-05-31 18:34:03 +02:00
|
|
|
Wait = Wait * 2;
|
2022-05-19 02:06:26 +04:30
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Tries to get the lock and won't return until successfully get the lock
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2026-05-31 18:34:03 +02:00
|
|
|
* @param Lock Lock variable
|
|
|
|
|
* @param MaximumWait Maximum wait (pause) count
|
2022-05-19 02:06:26 +04:30
|
|
|
*/
|
2026-05-31 18:34:03 +02:00
|
|
|
VOID
|
|
|
|
|
SpinlockLockWithCustomWait(volatile LONG * Lock, UINT32 MaximumWait)
|
2022-05-19 02:06:26 +04:30
|
|
|
{
|
2026-05-31 18:34:03 +02:00
|
|
|
UINT32 Wait = 1;
|
2022-05-19 02:06:26 +04:30
|
|
|
|
|
|
|
|
while (!SpinlockTryLock(Lock))
|
|
|
|
|
{
|
2026-05-31 18:34:03 +02:00
|
|
|
for (UINT32 i = 0; i < Wait; ++i)
|
2022-05-19 02:06:26 +04:30
|
|
|
{
|
2026-05-05 23:46:12 +02:00
|
|
|
CpuPause();
|
2022-05-19 02:06:26 +04:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Don't call "pause" too many times. If the wait becomes too big,
|
|
|
|
|
// clamp it to the MaxWait.
|
|
|
|
|
//
|
|
|
|
|
|
2026-05-31 18:34:03 +02:00
|
|
|
if (Wait * 2 > MaximumWait)
|
2022-05-19 02:06:26 +04:30
|
|
|
{
|
2026-05-31 18:34:03 +02:00
|
|
|
Wait = MaximumWait;
|
2022-05-19 02:06:26 +04:30
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2026-05-31 18:34:03 +02:00
|
|
|
Wait = Wait * 2;
|
2022-05-19 02:06:26 +04:30
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Release the lock
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2026-05-31 18:34:03 +02:00
|
|
|
* @param Lock Lock variable
|
2022-05-19 02:06:26 +04:30
|
|
|
*/
|
2026-05-31 18:34:03 +02:00
|
|
|
VOID
|
2022-05-19 02:06:26 +04:30
|
|
|
SpinlockUnlock(volatile LONG * Lock)
|
|
|
|
|
{
|
|
|
|
|
*Lock = 0;
|
|
|
|
|
}
|