From 03d1fa3dcd3d285651d8bce62d4b99e76eee3345 Mon Sep 17 00:00:00 2001 From: Yi Huang Date: Thu, 18 Jul 2024 16:15:08 -0700 Subject: [PATCH 1/9] CxPlatAsync --- inc/cxplat.hpp | 87 ++++++++++++++++++++++++++++++ src/test/CxPlatTests.h | 8 ++- src/test/bin/cxplat_gtest.cpp | 9 ++++ src/test/bin/winkernel/control.cpp | 4 ++ src/test/lib/ThreadTest.cpp | 36 +++++++++++++ src/test/lib/precomp.h | 1 + 6 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 inc/cxplat.hpp diff --git a/inc/cxplat.hpp b/inc/cxplat.hpp new file mode 100644 index 0000000..98d7ef8 --- /dev/null +++ b/inc/cxplat.hpp @@ -0,0 +1,87 @@ +/*++ + + Copyright (c) Microsoft Corporation. + Licensed under the MIT License. + +Abstract: + + C++ header only cxplat wrappers + +--*/ + +#ifndef CXPLATCPP_H +#define CXPLATCPP_H + +#include "cxplat.h" +#include "cxplat_sal_stub.h" + +typedef void* CxPlatCallback( + _Inout_ void* Context +); + +class CxPlatAsync { +private: + struct CxPlatAsyncContext { + void* UserContext; + CxPlatCallback *UserCallback; + void* ReturnValue; + }; + + static + CXPLAT_THREAD_CALLBACK(CxPlatAsyncWrapperCallback, Context) + { + struct CxPlatAsyncContext *AsyncContext = (struct CxPlatAsyncContext*)Context; + AsyncContext->ReturnValue = AsyncContext->UserCallback(AsyncContext->UserContext); + CXPLAT_THREAD_RETURN(0); + } + + CXPLAT_THREAD Thread {0}; + CXPLAT_THREAD_CONFIG ThreadConfig {0}; + struct CxPlatAsyncContext AsyncContext {0}; + bool Initialized : 1; + bool WaitOnDelete : 1; +public: + CxPlatAsync(CxPlatCallback Callback, void* UserContext = nullptr, bool WaitOnDelete = true) 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; + this->WaitOnDelete = WaitOnDelete; + } + ~CxPlatAsync() noexcept { + if (Initialized) { + if (WaitOnDelete) { + CxPlatThreadWaitForever(&Thread); + } + CxPlatThreadDelete(&Thread); + } + } + + void Wait() noexcept { + if (Initialized) { + CxPlatThreadWaitForever(&Thread); + } + } + +#if defined(CX_PLATFORM_WINUSER) || defined(CX_PLATFORM_WINKERNEL) + void WaitFor(uint32_t TimeoutMs) noexcept { + if (Initialized) { + CxPlatThreadWaitWithTimeout(&Thread, TimeoutMs); + } + } +#endif + + void* Get() noexcept { + return AsyncContext.ReturnValue; + } +}; + +#endif \ No newline at end of file diff --git a/src/test/CxPlatTests.h b/src/test/CxPlatTests.h index 7c1ff50..b962354 100644 --- a/src/test/CxPlatTests.h +++ b/src/test/CxPlatTests.h @@ -54,6 +54,7 @@ void CxPlatTestProcBasic(); // void CxPlatTestThreadBasic(); +void CxPlatTestThreadAsync(); #if defined(CX_PLATFORM_WINUSER) || defined(CX_PLATFORM_WINKERNEL) void CxPlatTestThreadWaitTimeout(); #endif @@ -135,10 +136,13 @@ static const GUID CXPLAT_TEST_DEVICE_INSTANCE = #define IOCTL_CXPLAT_RUN_THREAD_BASIC \ CXPLAT_CTL_CODE(6, METHOD_BUFFERED, FILE_WRITE_DATA) -#define IOCTL_CXPLAT_RUN_THREAD_WAIT_TIMEOUT \ +#define IOCTL_CXPLAT_RUN_THREAD_ASYNC \ CXPLAT_CTL_CODE(7, METHOD_BUFFERED, FILE_WRITE_DATA) -#define IOCTL_CXPLAT_RUN_VECTOR_BASIC \ +#define IOCTL_CXPLAT_RUN_THREAD_WAIT_TIMEOUT \ CXPLAT_CTL_CODE(8, METHOD_BUFFERED, FILE_WRITE_DATA) +#define IOCTL_CXPLAT_RUN_VECTOR_BASIC \ + CXPLAT_CTL_CODE(9, METHOD_BUFFERED, FILE_WRITE_DATA) + #define CXPLAT_MAX_IOCTL_FUNC_CODE 8 diff --git a/src/test/bin/cxplat_gtest.cpp b/src/test/bin/cxplat_gtest.cpp index badec4f..64c2973 100644 --- a/src/test/bin/cxplat_gtest.cpp +++ b/src/test/bin/cxplat_gtest.cpp @@ -170,6 +170,15 @@ TEST(ThreadSuite, Basic) { } } +TEST(ThreadSuite, Async) { + TestLogger Logger("CxPlatTestThreadAsync"); + if (TestingKernelMode) { + ASSERT_TRUE(DriverClient.Run(IOCTL_CXPLAT_RUN_THREAD_ASYNC)); + } else { + CxPlatTestThreadAsync(); + } +} + #if defined(CX_PLATFORM_WINUSER) || defined(CX_PLATFORM_WINKERNEL) TEST(ThreadSuite, WithTimeout) { TestLogger Logger("CxPlatTestThreadWaitTimeout"); diff --git a/src/test/bin/winkernel/control.cpp b/src/test/bin/winkernel/control.cpp index cc6da2c..4d80aea 100644 --- a/src/test/bin/winkernel/control.cpp +++ b/src/test/bin/winkernel/control.cpp @@ -500,6 +500,10 @@ CxPlatTestCtlEvtIoDeviceControl( CxPlatTestCtlRun(CxPlatTestThreadBasic()); break; + case IOCTL_CXPLAT_RUN_THREAD_ASYNC: + CxPlatTestCtlRun(CxPlatTestThreadAsync()); + break; + case IOCTL_CXPLAT_RUN_THREAD_WAIT_TIMEOUT: CxPlatTestCtlRun(CxPlatTestThreadWaitTimeout()); break; diff --git a/src/test/lib/ThreadTest.cpp b/src/test/lib/ThreadTest.cpp index d51e0cb..9a580b0 100644 --- a/src/test/lib/ThreadTest.cpp +++ b/src/test/lib/ThreadTest.cpp @@ -61,6 +61,42 @@ void CxPlatTestThreadBasic() CxPlatThreadDelete(&Thread); } +void CxPlatTestThreadAsync() +{ + { + CxPlatAsync Async([](void*) -> void* { + return nullptr; + }); + } + + { + 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); + }, &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); + }); + + Async.WaitFor(50); + TEST_EQUAL(Async.Get(), nullptr); + Async.Wait(); + TEST_NOT_EQUAL(Async.Get(), nullptr); + } +#endif +} + #if defined(CX_PLATFORM_WINUSER) || defined(CX_PLATFORM_WINKERNEL) void CxPlatTestThreadWaitTimeout() { diff --git a/src/test/lib/precomp.h b/src/test/lib/precomp.h index 1fb7648..6151454 100644 --- a/src/test/lib/precomp.h +++ b/src/test/lib/precomp.h @@ -45,6 +45,7 @@ #include "TestAbstractionLayer.h" #include "cxplatvector.h" +#include "cxplat.hpp" #if defined(_ARM64_) || defined(_ARM64EC_) #pragma optimize("", off) From 24f77fa2c87bbaecdafb9a49a06e684e1e316170 Mon Sep 17 00:00:00 2001 From: Yi Huang Date: Thu, 18 Jul 2024 16:15:48 -0700 Subject: [PATCH 2/9] WS --- inc/cxplat.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/cxplat.hpp b/inc/cxplat.hpp index 98d7ef8..c39511a 100644 --- a/inc/cxplat.hpp +++ b/inc/cxplat.hpp @@ -84,4 +84,4 @@ class CxPlatAsync { } }; -#endif \ No newline at end of file +#endif From 6f21ca9693a9306c60b13230e2489711dc1e1e4d Mon Sep 17 00:00:00 2001 From: Yi Huang Date: Thu, 18 Jul 2024 17:17:01 -0700 Subject: [PATCH 3/9] More tests --- src/test/lib/ThreadTest.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/test/lib/ThreadTest.cpp b/src/test/lib/ThreadTest.cpp index 9a580b0..a9734df 100644 --- a/src/test/lib/ThreadTest.cpp +++ b/src/test/lib/ThreadTest.cpp @@ -69,6 +69,19 @@ void CxPlatTestThreadAsync() }); } + { + struct TempCtx { + uint32_t Value; + } TempCtx = { 0 }; + CxPlatAsync Async([](void* Ctx) -> void* { + struct TempCtx* TempCtx = (struct TempCtx*)Ctx; + TempCtx->Value = 123; + return nullptr; + }, &TempCtx); + Async.Wait(); + TEST_EQUAL(123, TempCtx.Value); + } + { CXPLAT_THREAD_ID ThreadId = INITIAL_THREAD_ID_VALUE; CxPlatAsync Async([](void* Ctx) -> void* { From 994f714cd584bc1df7bf9d403f775e8dc7553680 Mon Sep 17 00:00:00 2001 From: Yi Huang Date: Thu, 18 Jul 2024 20:47:51 -0700 Subject: [PATCH 4/9] Kick off tests --- inc/cxplat.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/cxplat.hpp b/inc/cxplat.hpp index c39511a..c9a3de6 100644 --- a/inc/cxplat.hpp +++ b/inc/cxplat.hpp @@ -5,7 +5,7 @@ Abstract: - C++ header only cxplat wrappers + C++ header only cxplat wrappers --*/ From 841e66294b7eb808809572b4b2c0e4006fe3edd7 Mon Sep 17 00:00:00 2001 From: Yi Huang Date: Thu, 18 Jul 2024 22:00:27 -0700 Subject: [PATCH 5/9] max ioctl value --- src/test/CxPlatTests.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/CxPlatTests.h b/src/test/CxPlatTests.h index b962354..137b903 100644 --- a/src/test/CxPlatTests.h +++ b/src/test/CxPlatTests.h @@ -145,4 +145,4 @@ static const GUID CXPLAT_TEST_DEVICE_INSTANCE = #define IOCTL_CXPLAT_RUN_VECTOR_BASIC \ CXPLAT_CTL_CODE(9, METHOD_BUFFERED, FILE_WRITE_DATA) -#define CXPLAT_MAX_IOCTL_FUNC_CODE 8 +#define CXPLAT_MAX_IOCTL_FUNC_CODE 9 From cc5e3e2c753d993d3746b93e8d1ecf891da9a2db Mon Sep 17 00:00:00 2001 From: Yi Huang Date: Thu, 18 Jul 2024 22:06:38 -0700 Subject: [PATCH 6/9] update ioctl buffer size array --- src/test/bin/winkernel/control.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/bin/winkernel/control.cpp b/src/test/bin/winkernel/control.cpp index 4d80aea..a7a4ce6 100644 --- a/src/test/bin/winkernel/control.cpp +++ b/src/test/bin/winkernel/control.cpp @@ -366,6 +366,7 @@ size_t CXPLAT_IOCTL_BUFFER_SIZES[] = 0, 0, 0, + 0, }; static_assert( From 6ae4b708baa14dc49614ca1fc3c250c25212a35c Mon Sep 17 00:00:00 2001 From: Yi Huang Date: Thu, 18 Jul 2024 22:35:19 -0700 Subject: [PATCH 7/9] Fix posix --- inc/cxplat.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/inc/cxplat.hpp b/inc/cxplat.hpp index c9a3de6..e95229e 100644 --- a/inc/cxplat.hpp +++ b/inc/cxplat.hpp @@ -38,10 +38,10 @@ class CxPlatAsync { CXPLAT_THREAD Thread {0}; CXPLAT_THREAD_CONFIG ThreadConfig {0}; struct CxPlatAsyncContext AsyncContext {0}; - bool Initialized : 1; - bool WaitOnDelete : 1; + bool Initialized = false; + bool ThreadCompleted = false; public: - CxPlatAsync(CxPlatCallback Callback, void* UserContext = nullptr, bool WaitOnDelete = true) noexcept { + CxPlatAsync(CxPlatCallback Callback, void* UserContext = nullptr) noexcept { AsyncContext.UserContext = UserContext; AsyncContext.UserCallback = Callback; AsyncContext.ReturnValue = nullptr; @@ -54,11 +54,10 @@ class CxPlatAsync { return; } Initialized = true; - this->WaitOnDelete = WaitOnDelete; } ~CxPlatAsync() noexcept { if (Initialized) { - if (WaitOnDelete) { + if (!ThreadCompleted) { CxPlatThreadWaitForever(&Thread); } CxPlatThreadDelete(&Thread); @@ -68,6 +67,7 @@ class CxPlatAsync { void Wait() noexcept { if (Initialized) { CxPlatThreadWaitForever(&Thread); + ThreadCompleted = true; } } From ed4903b4caa657b3ebbe2fb20e80b85fee9f48e9 Mon Sep 17 00:00:00 2001 From: Yi Huang Date: Fri, 19 Jul 2024 10:43:48 -0700 Subject: [PATCH 8/9] Apply suggestions from code review Co-authored-by: Nick Banks --- inc/cxplat.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/inc/cxplat.hpp b/inc/cxplat.hpp index e95229e..404b7c4 100644 --- a/inc/cxplat.hpp +++ b/inc/cxplat.hpp @@ -27,10 +27,9 @@ class CxPlatAsync { void* ReturnValue; }; - static - CXPLAT_THREAD_CALLBACK(CxPlatAsyncWrapperCallback, Context) + static CXPLAT_THREAD_CALLBACK(CxPlatAsyncWrapperCallback, Context) { - struct CxPlatAsyncContext *AsyncContext = (struct CxPlatAsyncContext*)Context; + struct CxPlatAsyncContext* AsyncContext = (struct CxPlatAsyncContext*)Context; AsyncContext->ReturnValue = AsyncContext->UserCallback(AsyncContext->UserContext); CXPLAT_THREAD_RETURN(0); } From a616304ba303015aeed2df6490f13fb4cfbd4bcb Mon Sep 17 00:00:00 2001 From: Yi Huang Date: Fri, 19 Jul 2024 10:51:56 -0700 Subject: [PATCH 9/9] cr feedback --- inc/cxplat.hpp | 4 ++++ src/test/CxPlatTests.h | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/inc/cxplat.hpp b/inc/cxplat.hpp index e95229e..86a1f67 100644 --- a/inc/cxplat.hpp +++ b/inc/cxplat.hpp @@ -9,6 +9,10 @@ --*/ +#ifdef _WIN32 +#pragma once +#endif + #ifndef CXPLATCPP_H #define CXPLATCPP_H diff --git a/src/test/CxPlatTests.h b/src/test/CxPlatTests.h index 137b903..b63f1c0 100644 --- a/src/test/CxPlatTests.h +++ b/src/test/CxPlatTests.h @@ -136,13 +136,13 @@ static const GUID CXPLAT_TEST_DEVICE_INSTANCE = #define IOCTL_CXPLAT_RUN_THREAD_BASIC \ CXPLAT_CTL_CODE(6, METHOD_BUFFERED, FILE_WRITE_DATA) -#define IOCTL_CXPLAT_RUN_THREAD_ASYNC \ +#define IOCTL_CXPLAT_RUN_THREAD_WAIT_TIMEOUT \ CXPLAT_CTL_CODE(7, METHOD_BUFFERED, FILE_WRITE_DATA) -#define IOCTL_CXPLAT_RUN_THREAD_WAIT_TIMEOUT \ +#define IOCTL_CXPLAT_RUN_VECTOR_BASIC \ CXPLAT_CTL_CODE(8, METHOD_BUFFERED, FILE_WRITE_DATA) -#define IOCTL_CXPLAT_RUN_VECTOR_BASIC \ +#define IOCTL_CXPLAT_RUN_THREAD_ASYNC \ CXPLAT_CTL_CODE(9, METHOD_BUFFERED, FILE_WRITE_DATA) #define CXPLAT_MAX_IOCTL_FUNC_CODE 9