Skip to content

Commit

Permalink
Merge branch 'main' into cxplatlock
Browse files Browse the repository at this point in the history
  • Loading branch information
nibanks committed Jul 20, 2024
2 parents 6c771a5 + 28dedc3 commit e28c54d
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 63 deletions.
71 changes: 34 additions & 37 deletions inc/cxplat.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,46 +58,47 @@ struct CxPlatRwLockDispatch {
};
#pragma warning(pop)

typedef void* CxPlatCallback(
_Inout_ void* Context
);
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; }
operator CXPLAT_EVENT() const noexcept { return Handle; }
void Set() { CxPlatEventSet(Handle); }
void Reset() { CxPlatEventReset(Handle); }
void WaitForever() { CxPlatEventWaitForever(Handle); }
bool WaitTimeout(uint32_t TimeoutMs) { return CxPlatEventWaitWithTimeout(Handle, TimeoutMs); }
};

class CxPlatAsync {
template <typename T>
class CxPlatAsyncT {
private:
struct CxPlatAsyncContext {
void* UserContext;
CxPlatCallback *UserCallback;
void* ReturnValue;
typedef void CallbackT(_Inout_ T* Context);

struct ContextT {
T* UserContext;
CallbackT *UserCallback;
};

static CXPLAT_THREAD_CALLBACK(CxPlatAsyncWrapperCallback, Context)
{
struct CxPlatAsyncContext* AsyncContext = (struct CxPlatAsyncContext*)Context;
AsyncContext->ReturnValue = AsyncContext->UserCallback(AsyncContext->UserContext);
static CXPLAT_THREAD_CALLBACK(ThreadCallback, Context) {
auto AsyncContext = (ContextT*)Context;
AsyncContext->UserCallback(AsyncContext->UserContext);
CXPLAT_THREAD_RETURN(0);
}

struct ContextT AsyncContext {0, 0};
CXPLAT_THREAD_CONFIG ThreadConfig {0, 0, "CxPlatAsync", ThreadCallback, &AsyncContext};
CXPLAT_THREAD Thread {0};
CXPLAT_THREAD_CONFIG ThreadConfig {0};
struct CxPlatAsyncContext AsyncContext {0};
bool Initialized = false;
bool ThreadCompleted = false;
bool ThreadCompleted {false};
bool Initialized;
public:
CxPlatAsync(CxPlatCallback Callback, void* UserContext = nullptr) noexcept {
AsyncContext.UserContext = UserContext;
AsyncContext.UserCallback = Callback;
AsyncContext.ReturnValue = nullptr;

ThreadConfig.Name = "CxPlatAsync";
ThreadConfig.Callback = CxPlatAsyncWrapperCallback;
ThreadConfig.Context = &AsyncContext;
if (CxPlatThreadCreate(&ThreadConfig, &Thread) != 0) {
Initialized = false;
return;
}
Initialized = true;
CxPlatAsyncT(CallbackT Callback, T* UserContext = nullptr) noexcept
: AsyncContext({UserContext, Callback}),
Initialized(CxPlatThreadCreate(&ThreadConfig, &Thread) == 0) {
}
~CxPlatAsync() noexcept {
~CxPlatAsyncT() noexcept {
if (Initialized) {
if (!ThreadCompleted) {
CxPlatThreadWaitForever(&Thread);
Expand All @@ -116,17 +117,13 @@ class CxPlatAsync {
#if defined(CX_PLATFORM_WINUSER) || defined(CX_PLATFORM_WINKERNEL)
bool WaitFor(uint32_t TimeoutMs) noexcept {
if (Initialized) {
if (CxPlatThreadWaitWithTimeout(&Thread, TimeoutMs)) {
return true;
}
return (ThreadCompleted = CxPlatThreadWaitWithTimeout(&Thread, TimeoutMs));
}
return false;
}
#endif

void* Get() noexcept {
return AsyncContext.ReturnValue;
}
};

typedef CxPlatAsyncT<void> CxPlatAsync;

#endif
10 changes: 7 additions & 3 deletions src/test/CxPlatTests.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ void CxPlatTestTimeBasic();
//

void CxPlatTestEventBasic();
void CxPlatTestEventCpp();

//
// Processor Tests
Expand Down Expand Up @@ -151,10 +152,13 @@ static const GUID CXPLAT_TEST_DEVICE_INSTANCE =
#define IOCTL_CXPLAT_RUN_THREAD_ASYNC \
CXPLAT_CTL_CODE(9, METHOD_BUFFERED, FILE_WRITE_DATA)

#define IOCTL_CXPLAT_RUN_LOCK_BASIC \
#define IOCTL_CXPLAT_RUN_EVENT_CPP \
CXPLAT_CTL_CODE(10, METHOD_BUFFERED, FILE_WRITE_DATA)

#define IOCTL_CXPLAT_RUN_LOCK_READ_WRITE \
#define IOCTL_CXPLAT_RUN_LOCK_BASIC \
CXPLAT_CTL_CODE(11, METHOD_BUFFERED, FILE_WRITE_DATA)

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

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

TEST(EventSuite, Cpp) {
TestLogger Logger("CxPlatTestEventCpp");
if (TestingKernelMode) {
ASSERT_TRUE(DriverClient.Run(IOCTL_CXPLAT_RUN_EVENT_CPP));
} else {
CxPlatTestEventCpp();
}
}

TEST(ProcSuite, Basic) {
TestLogger Logger("CxPlatTestProcBasic");
if (TestingKernelMode) {
Expand Down
5 changes: 5 additions & 0 deletions src/test/bin/winkernel/control.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ size_t CXPLAT_IOCTL_BUFFER_SIZES[] =
0,
0,
0,
0,
};

static_assert(
Expand Down Expand Up @@ -515,6 +516,10 @@ CxPlatTestCtlEvtIoDeviceControl(
CxPlatTestCtlRun(VectorBasic());
break;

case IOCTL_CXPLAT_RUN_EVENT_CPP:
CxPlatTestCtlRun(CxPlatTestEventCpp());
break;

case IOCTL_CXPLAT_RUN_LOCK_BASIC:
CxPlatTestCtlRun(CxPlatTestLockBasic());
break;
Expand Down
18 changes: 18 additions & 0 deletions src/test/lib/EventTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,21 @@ void CxPlatTestEventBasic()

CxPlatEventUninitialize(Event);
}

void CxPlatTestEventCpp()
{
const uint32_t TimeoutMs = 100;

{
CxPlatEvent Event;
TEST_FALSE(Event.WaitTimeout(TimeoutMs));

Event.Reset();
Event.Set();
TEST_TRUE(Event.WaitTimeout(TimeoutMs));

Event.Reset();
Event.Set();
Event.WaitForever();
}
}
40 changes: 17 additions & 23 deletions src/test/lib/ThreadTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,48 +64,42 @@ void CxPlatTestThreadBasic()
void CxPlatTestThreadAsync()
{
{
CxPlatAsync Async([](void*) -> void* {
return nullptr;
CxPlatAsync Async([](void*) -> void {
// no-op
});
}

{
struct TempCtx {
uint32_t Value;
} TempCtx = { 0 };
CxPlatAsync Async([](void* Ctx) -> void* {
struct TempCtx* TempCtx = (struct TempCtx*)Ctx;
TempCtx->Value = 123;
return nullptr;
}, &TempCtx);
uint32_t Ctx = 0;
CxPlatAsyncT<uint32_t> Async([](uint32_t* Ctx) -> void {
*Ctx = 123;
}, &Ctx);
Async.Wait();
TEST_EQUAL(123, TempCtx.Value);
}
TEST_EQUAL(123, Ctx);
}

{
CXPLAT_THREAD_ID ThreadId = INITIAL_THREAD_ID_VALUE;
CxPlatAsync Async([](void* Ctx) -> void* {
CXPLAT_THREAD_ID* ThreadId = (CXPLAT_THREAD_ID*)Ctx;
*ThreadId = CxPlatCurThreadID();
return (void*)(intptr_t)(*ThreadId);
CxPlatAsyncT<CXPLAT_THREAD_ID> Async([](CXPLAT_THREAD_ID* Ctx) -> void {
*Ctx = CxPlatCurThreadID();
}, &ThreadId);

Async.Wait();
TEST_EQUAL((CXPLAT_THREAD_ID)((intptr_t)Async.Get()), ThreadId);
TEST_NOT_EQUAL(INITIAL_THREAD_ID_VALUE, ThreadId);
}

#if defined(CX_PLATFORM_WINUSER) || defined(CX_PLATFORM_WINKERNEL)
{
CxPlatAsync Async([](void*) -> void* {
CxPlatSleep(2000);
return (void*)(intptr_t)(0xdeadbeaf);
});
intptr_t Ctx = 0;
CxPlatAsyncT<intptr_t> Async([](intptr_t* Ctx) -> void {
CxPlatSleep(2000);
*Ctx = (intptr_t)(0xdeadbeaf);
}, &Ctx);

TEST_FALSE(Async.WaitFor(50));
TEST_EQUAL(Async.Get(), nullptr);
TEST_EQUAL(Ctx, 0);
Async.Wait();
TEST_NOT_EQUAL(Async.Get(), nullptr);
TEST_NOT_EQUAL(Ctx, 0);
}
#endif
}
Expand Down

0 comments on commit e28c54d

Please sign in to comment.