feat(lock): add basic lock functions

This commit is contained in:
fallenoak 2023-03-03 15:34:02 -06:00 committed by GitHub
parent 3b5da1af9c
commit e8d3709d31
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 207 additions and 0 deletions

View file

@ -1,5 +1,6 @@
file(GLOB BC_SOURCES
"*.cpp"
"lock/*.cpp"
)
add_library(bc STATIC

58
bc/Lock.cpp Normal file
View file

@ -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
}

37
bc/Lock.hpp Normal file
View file

@ -0,0 +1,37 @@
#ifndef BC_LOCK_HPP
#define BC_LOCK_HPP
#include "bc/lock/Atomic.hpp"
#include <cstdint>
#if defined(WHOA_SYSTEM_WIN)
#include <windows.h>
#elif defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX)
#include <pthread.h>
#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

13
bc/System_Lock.cpp Normal file
View file

@ -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
}

30
bc/System_Lock.hpp Normal file
View file

@ -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 <pthread.h>
#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

13
bc/lock/Atomic.cpp Normal file
View file

@ -0,0 +1,13 @@
#include "bc/lock/Atomic.hpp"
#if defined(WHOA_SYSTEM_WIN)
#include <windows.h>
#endif
int32_t Blizzard::Lock::Atomic::Increment(volatile int32_t* value) {
#if defined(WHOA_SYSTEM_WIN)
return InterlockedIncrement(reinterpret_cast<volatile long*>(value));
#elif defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX)
return __sync_fetch_and_add(value, 1) + 1;
#endif
}

16
bc/lock/Atomic.hpp Normal file
View file

@ -0,0 +1,16 @@
#ifndef BC_LOCK_ATOMIC_HPP
#define BC_LOCK_ATOMIC_HPP
#include <cstdint>
namespace Blizzard {
namespace Lock {
namespace Atomic {
int32_t Increment(volatile int32_t* value);
} // namespace Atomic
} // namespace Lock
} // namespace Blizzard
#endif

39
test/Lock.cpp Normal file
View file

@ -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);
}
}