From e8d3709d31fdb0a7b9d0f7be40c6e527d77a88f9 Mon Sep 17 00:00:00 2001 From: fallenoak Date: Fri, 3 Mar 2023 15:34:02 -0600 Subject: [PATCH] feat(lock): add basic lock functions --- bc/CMakeLists.txt | 1 + bc/Lock.cpp | 58 ++++++++++++++++++++++++++++++++++++++++++++++ bc/Lock.hpp | 37 +++++++++++++++++++++++++++++ bc/System_Lock.cpp | 13 +++++++++++ bc/System_Lock.hpp | 30 ++++++++++++++++++++++++ bc/lock/Atomic.cpp | 13 +++++++++++ bc/lock/Atomic.hpp | 16 +++++++++++++ test/Lock.cpp | 39 +++++++++++++++++++++++++++++++ 8 files changed, 207 insertions(+) create mode 100644 bc/Lock.cpp create mode 100644 bc/Lock.hpp create mode 100644 bc/System_Lock.cpp create mode 100644 bc/System_Lock.hpp create mode 100644 bc/lock/Atomic.cpp create mode 100644 bc/lock/Atomic.hpp create mode 100644 test/Lock.cpp diff --git a/bc/CMakeLists.txt b/bc/CMakeLists.txt index 04e36bc..c8a8aa4 100644 --- a/bc/CMakeLists.txt +++ b/bc/CMakeLists.txt @@ -1,5 +1,6 @@ file(GLOB BC_SOURCES "*.cpp" + "lock/*.cpp" ) add_library(bc STATIC diff --git a/bc/Lock.cpp b/bc/Lock.cpp new file mode 100644 index 0000000..6f6f340 --- /dev/null +++ b/bc/Lock.cpp @@ -0,0 +1,58 @@ +#include "bc/Lock.hpp" +#include "bc/Debug.hpp" +#include "bc/Process.hpp" +#include "bc/System_Lock.hpp" + +void Blizzard::Lock::DoOnce(DoOnceData& a1, void (*a2)(void*), void* a3) { + if (!a1.done) { + if (Blizzard::Lock::Atomic::Increment(&a1.atomic) == 1) { + a2(a3); + a1.done = true; + } else { + while (!a1.done) { + Blizzard::Process::Sleep(1); + } + } + } +} + +int32_t Blizzard::Lock::MutexCreate(Blizzard::Lock::Mutex& mutex) { +#if defined(WHOA_SYSTEM_WIN) + InitializeCriticalSection(&mutex); + + return 0; +#elif defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX) + Blizzard::Lock::DoOnce(System_Lock::s_initMutexAttrOnce, System_Lock::InitAttr, nullptr); + + auto result = pthread_mutex_init(&mutex, &System_Lock::s_mutexattr); + BLIZZARD_ASSERT(result == 0); + + return result; +#endif +} + +int32_t Blizzard::Lock::MutexEnter(Blizzard::Lock::Mutex& mutex) { +#if defined(WHOA_SYSTEM_WIN) + EnterCriticalSection(&mutex); + + return 0; +#elif defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX) + auto result = pthread_mutex_lock(&mutex); + BLIZZARD_ASSERT(result == 0); + + return result; +#endif +} + +int32_t Blizzard::Lock::MutexLeave(Blizzard::Lock::Mutex& mutex) { +#if defined(WHOA_SYSTEM_WIN) + LeaveCriticalSection(&mutex); + + return 0; +#elif defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX) + auto result = pthread_mutex_unlock(&mutex); + BLIZZARD_ASSERT(result == 0); + + return result; +#endif +} diff --git a/bc/Lock.hpp b/bc/Lock.hpp new file mode 100644 index 0000000..a680ba5 --- /dev/null +++ b/bc/Lock.hpp @@ -0,0 +1,37 @@ +#ifndef BC_LOCK_HPP +#define BC_LOCK_HPP + +#include "bc/lock/Atomic.hpp" +#include + +#if defined(WHOA_SYSTEM_WIN) +#include +#elif defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX) +#include +#endif + +namespace Blizzard { +namespace Lock { + +// Types +#if defined(WHOA_SYSTEM_WIN) +typedef CRITICAL_SECTION Mutex; +#elif defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX) +typedef pthread_mutex_t Mutex; +#endif + +struct DoOnceData { + bool done; + int32_t atomic; +}; + +// Functions +void DoOnce(DoOnceData& a1, void (*a2)(void*), void* a3); +int32_t MutexCreate(Mutex& mutex); +int32_t MutexEnter(Mutex& mutex); +int32_t MutexLeave(Mutex& mutex); + +} // namespace Lock +} // namespace Blizzard + +#endif diff --git a/bc/System_Lock.cpp b/bc/System_Lock.cpp new file mode 100644 index 0000000..effec30 --- /dev/null +++ b/bc/System_Lock.cpp @@ -0,0 +1,13 @@ +#include "bc/System_Lock.hpp" + +#if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX) +Blizzard::Lock::DoOnceData Blizzard::System_Lock::s_initMutexAttrOnce; +Blizzard::System_Lock::MutexAttr Blizzard::System_Lock::s_mutexattr; +#endif + +void Blizzard::System_Lock::InitAttr(void* a1) { +#if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX) + pthread_mutexattr_init(&System_Lock::s_mutexattr); + pthread_mutexattr_settype(&System_Lock::s_mutexattr, PTHREAD_MUTEX_RECURSIVE); +#endif +} diff --git a/bc/System_Lock.hpp b/bc/System_Lock.hpp new file mode 100644 index 0000000..5aea546 --- /dev/null +++ b/bc/System_Lock.hpp @@ -0,0 +1,30 @@ +#ifndef BC_SYSTEM_LOCK_HPP +#define BC_SYSTEM_LOCK_HPP + +#include "bc/Lock.hpp" + +#if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX) +#include +#endif + +namespace Blizzard { +namespace System_Lock { + +// Types +#if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX) +typedef pthread_mutexattr_t MutexAttr; +#endif + +// Variables +#if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX) +extern Lock::DoOnceData s_initMutexAttrOnce; +extern MutexAttr s_mutexattr; +#endif + +// Functions +void InitAttr(void* a1); + +} // namespace System_Lock +} // namespace Blizzard + +#endif diff --git a/bc/lock/Atomic.cpp b/bc/lock/Atomic.cpp new file mode 100644 index 0000000..7be788b --- /dev/null +++ b/bc/lock/Atomic.cpp @@ -0,0 +1,13 @@ +#include "bc/lock/Atomic.hpp" + +#if defined(WHOA_SYSTEM_WIN) +#include +#endif + +int32_t Blizzard::Lock::Atomic::Increment(volatile int32_t* value) { +#if defined(WHOA_SYSTEM_WIN) + return InterlockedIncrement(reinterpret_cast(value)); +#elif defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX) + return __sync_fetch_and_add(value, 1) + 1; +#endif +} diff --git a/bc/lock/Atomic.hpp b/bc/lock/Atomic.hpp new file mode 100644 index 0000000..dc40fc7 --- /dev/null +++ b/bc/lock/Atomic.hpp @@ -0,0 +1,16 @@ +#ifndef BC_LOCK_ATOMIC_HPP +#define BC_LOCK_ATOMIC_HPP + +#include + +namespace Blizzard { +namespace Lock { +namespace Atomic { + +int32_t Increment(volatile int32_t* value); + +} // namespace Atomic +} // namespace Lock +} // namespace Blizzard + +#endif diff --git a/test/Lock.cpp b/test/Lock.cpp new file mode 100644 index 0000000..8a71656 --- /dev/null +++ b/test/Lock.cpp @@ -0,0 +1,39 @@ +#include "bc/Lock.hpp" +#include "test/Test.hpp" + +TEST_CASE("Blizzard::Lock::Atomic::Increment", "[lock]") { + SECTION("increments -1") { + int32_t value = -1; + REQUIRE(Blizzard::Lock::Atomic::Increment(&value) == 0); + } + + SECTION("increments 0") { + int32_t value = 0; + REQUIRE(Blizzard::Lock::Atomic::Increment(&value) == 1); + } +} + +TEST_CASE("Blizzard::Lock::MutexCreate", "[lock]") { + SECTION("creates mutex") { + Blizzard::Lock::Mutex mutex1; + REQUIRE(Blizzard::Lock::MutexCreate(mutex1) == 0); + + Blizzard::Lock::Mutex mutex2; + REQUIRE(Blizzard::Lock::MutexCreate(mutex2) == 0); + } +} + +TEST_CASE("Blizzard::Lock::MutexEnter", "[lock]") { + SECTION("enters and leaves mutex") { + Blizzard::Lock::Mutex mutex; + Blizzard::Lock::MutexCreate(mutex); + + int32_t mutexEntered = 0; + + Blizzard::Lock::MutexEnter(mutex); + mutexEntered = 1; + Blizzard::Lock::MutexLeave(mutex); + + REQUIRE(mutexEntered == 1); + } +}