Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Locking Abstractions #53

Merged
merged 7 commits into from
Jul 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 39 additions & 1 deletion inc/cxplat.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,51 @@
#include "cxplat.h"
#include "cxplat_sal_stub.h"

struct CxPlatLock {
CXPLAT_LOCK Handle;
CxPlatLock() noexcept { CxPlatLockInitialize(&Handle); }
~CxPlatLock() noexcept { CxPlatLockUninitialize(&Handle); }
void Acquire() noexcept { CxPlatLockAcquire(&Handle); }
void Release() noexcept { CxPlatLockRelease(&Handle); }
};

struct CxPlatRwLock {
CXPLAT_RW_LOCK Handle;
CxPlatRwLock() noexcept { CxPlatRwLockInitialize(&Handle); }
~CxPlatRwLock() noexcept { CxPlatRwLockUninitialize(&Handle); }
void AcquireShared() noexcept { CxPlatRwLockAcquireShared(&Handle); }
void AcquireExclusive() noexcept { CxPlatRwLockAcquireExclusive(&Handle); }
void ReleaseShared() noexcept { CxPlatRwLockReleaseShared(&Handle); }
void ReleaseExclusive() noexcept { CxPlatRwLockReleaseExclusive(&Handle); }
};

#pragma warning(push)
#pragma warning(disable:28167) // TODO - Fix SAL annotations for IRQL changes
struct CxPlatLockDispatch {
CXPLAT_DISPATCH_LOCK Handle;
CxPlatLockDispatch() noexcept { CxPlatDispatchLockInitialize(&Handle); }
~CxPlatLockDispatch() noexcept { CxPlatDispatchLockUninitialize(&Handle); }
void Acquire() noexcept { CxPlatDispatchLockAcquire(&Handle); }
void Release() noexcept { CxPlatDispatchLockRelease(&Handle); }
};

struct CxPlatRwLockDispatch {
CXPLAT_DISPATCH_RW_LOCK Handle;
CxPlatRwLockDispatch() noexcept { CxPlatDispatchRwLockInitialize(&Handle); }
~CxPlatRwLockDispatch() noexcept { CxPlatDispatchRwLockUninitialize(&Handle); }
void AcquireShared() noexcept { CxPlatDispatchRwLockAcquireShared(&Handle); }
void AcquireExclusive() noexcept { CxPlatDispatchRwLockAcquireExclusive(&Handle); }
void ReleaseShared() noexcept { CxPlatDispatchRwLockReleaseShared(&Handle); }
void ReleaseExclusive() noexcept { CxPlatDispatchRwLockReleaseExclusive(&Handle); }
};
#pragma warning(pop)

struct CxPlatEvent {
CXPLAT_EVENT Handle;
CxPlatEvent() noexcept { CxPlatEventInitialize(&Handle, FALSE, FALSE); }
CxPlatEvent(bool ManualReset) noexcept { CxPlatEventInitialize(&Handle, ManualReset, FALSE); }
CxPlatEvent(CXPLAT_EVENT event) noexcept : Handle(event) { }
~CxPlatEvent() noexcept { CxPlatEventUninitialize(Handle); }
CXPLAT_EVENT* operator &() noexcept { return &Handle; }
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary, and actually broke passing a pointer to this struct.

operator CXPLAT_EVENT() const noexcept { return Handle; }
void Set() { CxPlatEventSet(Handle); }
void Reset() { CxPlatEventReset(Handle); }
Expand Down
63 changes: 63 additions & 0 deletions inc/cxplat_posix.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,69 @@ CxPlatFree(
#define CxPlatMoveMemory(Destination, Source, Length) memmove((Destination), (Source), (Length))
#define CxPlatSecureZeroMemory CxPlatZeroMemory // TODO - Something better?

//
// Interrupt ReQuest Level
//

#define CXPLAT_IRQL() 0
#define CXPLAT_PASSIVE_CODE()
#define CXPLAT_AT_DISPATCH() FALSE

//
// Locking interfaces
//

typedef struct CXPLAT_LOCK {
alignas(16) pthread_mutex_t Mutex;
} CXPLAT_LOCK;

#define CxPlatLockInitialize(Lock) { \
pthread_mutexattr_t Attr; \
CXPLAT_FRE_ASSERT(pthread_mutexattr_init(&Attr) == 0); \
CXPLAT_FRE_ASSERT(pthread_mutexattr_settype(&Attr, PTHREAD_MUTEX_RECURSIVE) == 0); \
CXPLAT_FRE_ASSERT(pthread_mutex_init(&(Lock)->Mutex, &Attr) == 0); \
CXPLAT_FRE_ASSERT(pthread_mutexattr_destroy(&Attr) == 0); \
}
#define CxPlatLockUninitialize(Lock) \
CXPLAT_FRE_ASSERT(pthread_mutex_destroy(&(Lock)->Mutex) == 0)
#define CxPlatLockAcquire(Lock) \
CXPLAT_FRE_ASSERT(pthread_mutex_lock(&(Lock)->Mutex) == 0)
#define CxPlatLockRelease(Lock) \
CXPLAT_FRE_ASSERT(pthread_mutex_unlock(&(Lock)->Mutex) == 0)

typedef CXPLAT_LOCK CXPLAT_DISPATCH_LOCK;

#define CxPlatDispatchLockInitialize CxPlatLockInitialize
#define CxPlatDispatchLockUninitialize CxPlatLockUninitialize
#define CxPlatDispatchLockAcquire CxPlatLockAcquire
#define CxPlatDispatchLockRelease CxPlatLockRelease

typedef struct CXPLAT_RW_LOCK {
pthread_rwlock_t RwLock;
} CXPLAT_RW_LOCK;

#define CxPlatRwLockInitialize(Lock) \
CXPLAT_FRE_ASSERT(pthread_rwlock_init(&(Lock)->RwLock, NULL) == 0)
#define CxPlatRwLockUninitialize(Lock) \
CXPLAT_FRE_ASSERT(pthread_rwlock_destroy(&(Lock)->RwLock) == 0)
#define CxPlatRwLockAcquireShared(Lock) \
CXPLAT_FRE_ASSERT(pthread_rwlock_rdlock(&(Lock)->RwLock) == 0)
#define CxPlatRwLockAcquireExclusive(Lock) \
CXPLAT_FRE_ASSERT(pthread_rwlock_wrlock(&(Lock)->RwLock) == 0)
#define CxPlatRwLockReleaseShared(Lock) \
CXPLAT_FRE_ASSERT(pthread_rwlock_unlock(&(Lock)->RwLock) == 0)
#define CxPlatRwLockReleaseExclusive(Lock) \
CXPLAT_FRE_ASSERT(pthread_rwlock_unlock(&(Lock)->RwLock) == 0)

typedef CXPLAT_RW_LOCK CXPLAT_DISPATCH_RW_LOCK;

#define CxPlatDispatchRwLockInitialize CxPlatRwLockInitialize
#define CxPlatDispatchRwLockUninitialize CxPlatRwLockUninitialize
#define CxPlatDispatchRwLockAcquireShared CxPlatRwLockAcquireShared
#define CxPlatDispatchRwLockAcquireExclusive CxPlatRwLockAcquireExclusive
#define CxPlatDispatchRwLockReleaseShared CxPlatRwLockReleaseShared
#define CxPlatDispatchRwLockReleaseExclusive CxPlatRwLockReleaseExclusive

//
// Time Measurement Interfaces
//
Expand Down
58 changes: 58 additions & 0 deletions inc/cxplat_winkernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,64 @@ CxPlatLogAssert(
#define CxPlatMoveMemory RtlMoveMemory
#define CxPlatSecureZeroMemory RtlSecureZeroMemory

//
// Interrupt ReQuest Level
//

#define CXPLAT_IRQL() KeGetCurrentIrql()

#define CXPLAT_PASSIVE_CODE() CXPLAT_DBG_ASSERT(CXPLAT_IRQL() == PASSIVE_LEVEL)
#define CXPLAT_AT_DISPATCH() (CXPLAT_IRQL() == DISPATCH_LEVEL)

#define CXPLAT_RAISE_IRQL() KIRQL OldIrql; KeRaiseIrql(DISPATCH_LEVEL, &OldIrql)
#define CXPLAT_LOWER_IRQL() KeLowerIrql(OldIrql)

//
// Locking Interfaces
//

typedef EX_PUSH_LOCK CXPLAT_LOCK;

#define CxPlatLockInitialize(Lock) ExInitializePushLock(Lock)
#define CxPlatLockUninitialize(Lock)
#define CxPlatLockAcquire(Lock) KeEnterCriticalRegion(); ExAcquirePushLockExclusive(Lock)
#define CxPlatLockRelease(Lock) ExReleasePushLockExclusive(Lock); KeLeaveCriticalRegion()

typedef struct CXPLAT_DISPATCH_LOCK {
KSPIN_LOCK SpinLock;
KIRQL PrevIrql;
} CXPLAT_DISPATCH_LOCK;

#define CxPlatDispatchLockInitialize(Lock) KeInitializeSpinLock(&(Lock)->SpinLock)
#define CxPlatDispatchLockUninitialize(Lock)
#if defined(_AMD64_) || defined(_ARM64_)
#define CxPlatDispatchLockAcquire(Lock) (Lock)->PrevIrql = KeAcquireSpinLockRaiseToDpc(&(Lock)->SpinLock)
#else
#define CxPlatDispatchLockAcquire(Lock) KeAcquireSpinLock(&(Lock)->SpinLock, &(Lock)->PrevIrql)
#endif
#define CxPlatDispatchLockRelease(Lock) KeReleaseSpinLock(&(Lock)->SpinLock, (Lock)->PrevIrql)

typedef EX_PUSH_LOCK CXPLAT_RW_LOCK;

#define CxPlatRwLockInitialize(Lock) ExInitializePushLock(Lock)
#define CxPlatRwLockUninitialize(Lock)
#define CxPlatRwLockAcquireShared(Lock) KeEnterCriticalRegion(); ExAcquirePushLockShared(Lock)
#define CxPlatRwLockAcquireExclusive(Lock) KeEnterCriticalRegion(); ExAcquirePushLockExclusive(Lock)
#define CxPlatRwLockReleaseShared(Lock) ExReleasePushLockShared(Lock); KeLeaveCriticalRegion()
#define CxPlatRwLockReleaseExclusive(Lock) ExReleasePushLockExclusive(Lock); KeLeaveCriticalRegion()

typedef struct CXPLAT_DISPATCH_RW_LOCK {
EX_SPIN_LOCK SpinLock;
KIRQL PrevIrql;
} CXPLAT_DISPATCH_RW_LOCK;

#define CxPlatDispatchRwLockInitialize(Lock) (Lock)->SpinLock = 0
#define CxPlatDispatchRwLockUninitialize(Lock)
#define CxPlatDispatchRwLockAcquireShared(Lock) (Lock)->PrevIrql = ExAcquireSpinLockShared(&(Lock)->SpinLock)
#define CxPlatDispatchRwLockAcquireExclusive(Lock) (Lock)->PrevIrql = ExAcquireSpinLockExclusive(&(Lock)->SpinLock)
#define CxPlatDispatchRwLockReleaseShared(Lock) ExReleaseSpinLockShared(&(Lock)->SpinLock, (Lock)->PrevIrql)
#define CxPlatDispatchRwLockReleaseExclusive(Lock) ExReleaseSpinLockExclusive(&(Lock)->SpinLock, (Lock)->PrevIrql)

//
// Time Measurement Interfaces
//
Expand Down
45 changes: 45 additions & 0 deletions inc/cxplat_winuser.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,51 @@ CxPlatFree(
#define CxPlatMoveMemory RtlMoveMemory
#define CxPlatSecureZeroMemory RtlSecureZeroMemory

//
// Interrupt ReQuest Level
//

#define CXPLAT_IRQL() PASSIVE_LEVEL

#define CXPLAT_PASSIVE_CODE() CXPLAT_DBG_ASSERT(CXPLAT_IRQL() == PASSIVE_LEVEL)
#define CXPLAT_AT_DISPATCH() FALSE

//
// Locking interfaces
//

typedef CRITICAL_SECTION CXPLAT_LOCK;

#define CxPlatLockInitialize(Lock) InitializeCriticalSection(Lock)
#define CxPlatLockUninitialize(Lock) DeleteCriticalSection(Lock)
#define CxPlatLockAcquire(Lock) EnterCriticalSection(Lock)
#define CxPlatLockRelease(Lock) LeaveCriticalSection(Lock)

typedef CRITICAL_SECTION CXPLAT_DISPATCH_LOCK;

#define CxPlatDispatchLockInitialize(Lock) InitializeCriticalSection(Lock)
#define CxPlatDispatchLockUninitialize(Lock) DeleteCriticalSection(Lock)
#define CxPlatDispatchLockAcquire(Lock) EnterCriticalSection(Lock)
#define CxPlatDispatchLockRelease(Lock) LeaveCriticalSection(Lock)

typedef SRWLOCK CXPLAT_RW_LOCK;

#define CxPlatRwLockInitialize(Lock) InitializeSRWLock(Lock)
#define CxPlatRwLockUninitialize(Lock)
#define CxPlatRwLockAcquireShared(Lock) AcquireSRWLockShared(Lock)
#define CxPlatRwLockAcquireExclusive(Lock) AcquireSRWLockExclusive(Lock)
#define CxPlatRwLockReleaseShared(Lock) ReleaseSRWLockShared(Lock)
#define CxPlatRwLockReleaseExclusive(Lock) ReleaseSRWLockExclusive(Lock)

typedef SRWLOCK CXPLAT_DISPATCH_RW_LOCK;

#define CxPlatDispatchRwLockInitialize(Lock) InitializeSRWLock(Lock)
#define CxPlatDispatchRwLockUninitialize(Lock)
#define CxPlatDispatchRwLockAcquireShared(Lock) AcquireSRWLockShared(Lock)
#define CxPlatDispatchRwLockAcquireExclusive(Lock) AcquireSRWLockExclusive(Lock)
#define CxPlatDispatchRwLockReleaseShared(Lock) ReleaseSRWLockShared(Lock)
#define CxPlatDispatchRwLockReleaseExclusive(Lock) ReleaseSRWLockExclusive(Lock)

//
// Time Measurement Interfaces
//
Expand Down
14 changes: 13 additions & 1 deletion src/test/CxPlatTests.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ void CxPlatTestThreadWaitTimeout();
//
void VectorBasic();

//
// Lock Tests
//
void CxPlatTestLockBasic();
void CxPlatTestLockReadWrite();

//
// Platform Specific Functions
//
Expand Down Expand Up @@ -149,4 +155,10 @@ static const GUID CXPLAT_TEST_DEVICE_INSTANCE =
#define IOCTL_CXPLAT_RUN_EVENT_CPP \
CXPLAT_CTL_CODE(10, METHOD_BUFFERED, FILE_WRITE_DATA)

#define CXPLAT_MAX_IOCTL_FUNC_CODE 10
#define IOCTL_CXPLAT_RUN_LOCK_BASIC \
CXPLAT_CTL_CODE(11, METHOD_BUFFERED, FILE_WRITE_DATA)

#define IOCTL_CXPLAT_RUN_LOCK_READ_WRITE \
CXPLAT_CTL_CODE(12, METHOD_BUFFERED, FILE_WRITE_DATA)

#define CXPLAT_MAX_IOCTL_FUNC_CODE 12
18 changes: 18 additions & 0 deletions src/test/bin/cxplat_gtest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,24 @@ TEST(VectorSuite, Basic) {
}
}

TEST(LockSuite, Basic) {
TestLogger Logger("CxPlatTestLockBasic");
if (TestingKernelMode) {
ASSERT_TRUE(DriverClient.Run(IOCTL_CXPLAT_RUN_LOCK_BASIC));
} else {
CxPlatTestLockBasic();
}
}

TEST(LockSuite, ReadWrite) {
TestLogger Logger("CxPlatTestLockReadWrite");
if (TestingKernelMode) {
ASSERT_TRUE(DriverClient.Run(IOCTL_CXPLAT_RUN_LOCK_READ_WRITE));
} else {
CxPlatTestLockReadWrite();
}
}

int main(int argc, char** argv) {
for (int i = 0; i < argc; ++i) {
if (strcmp("--kernel", argv[i]) == 0) {
Expand Down
10 changes: 10 additions & 0 deletions src/test/bin/winkernel/control.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,8 @@ size_t CXPLAT_IOCTL_BUFFER_SIZES[] =
0,
0,
0,
0,
0,
};

static_assert(
Expand Down Expand Up @@ -518,6 +520,14 @@ CxPlatTestCtlEvtIoDeviceControl(
CxPlatTestCtlRun(CxPlatTestEventCpp());
break;

case IOCTL_CXPLAT_RUN_LOCK_BASIC:
CxPlatTestCtlRun(CxPlatTestLockBasic());
break;

case IOCTL_CXPLAT_RUN_LOCK_READ_WRITE:
CxPlatTestCtlRun(CxPlatTestLockReadWrite());
break;

default:
Status = STATUS_NOT_IMPLEMENTED;
break;
Expand Down
1 change: 1 addition & 0 deletions src/test/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
set(SOURCES
CryptTest.cpp
EventTest.cpp
LockTest.cpp
MemoryTest.cpp
ProcTest.cpp
ThreadTest.cpp
Expand Down
Loading