Skip to content

Commit

Permalink
Add preemptible work item APIs to cxplat library (#94)
Browse files Browse the repository at this point in the history
* Add preemptible work item APIs to cxplat library
* Fix symbol decoder if already in use by the process
* Fix initialization bug in aligned allocate
* Use INVALID_STATE error code

Signed-off-by: Dave Thaler <[email protected]>
  • Loading branch information
dthaler authored Aug 28, 2023
1 parent ff7327b commit 1d9a9f4
Show file tree
Hide file tree
Showing 34 changed files with 831 additions and 418 deletions.
2 changes: 2 additions & 0 deletions cxplat/cxplat_test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ FetchContent_MakeAvailable(Catch2)

add_executable(cxplat_test
cxplat_memory_test.cpp
cxplat_rundown_test.cpp
cxplat_workitem_test.cpp
)

target_include_directories(cxplat_test PRIVATE
Expand Down
24 changes: 24 additions & 0 deletions cxplat/cxplat_test/cxplat_rundown_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation
// SPDX-License-Identifier: MIT

#if !defined(CMAKE_NUGET)
#include <catch2/catch_all.hpp>
#else
#include <catch2/catch.hpp>
#endif
#include "cxplat.h"
#include <windows.h>

TEST_CASE("rundown_protection", "[rundown]")
{
cxplat_rundown_reference_t rundown_reference;
cxplat_initialize_rundown_protection(&rundown_reference);
cxplat_acquire_rundown_protection(&rundown_reference);
cxplat_release_rundown_protection(&rundown_reference);
cxplat_wait_for_rundown_protection_release(&rundown_reference);

cxplat_reinitialize_rundown_protection(&rundown_reference);
cxplat_acquire_rundown_protection(&rundown_reference);
cxplat_release_rundown_protection(&rundown_reference);
cxplat_wait_for_rundown_protection_release(&rundown_reference);
}
2 changes: 2 additions & 0 deletions cxplat/cxplat_test/cxplat_test.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,9 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="cxplat_memory_test.cpp" />
<ClCompile Include="cxplat_rundown_test.cpp" />
<ClCompile Include="cxplat_size_test.cpp" />
<ClCompile Include="cxplat_workitem_test.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
Expand Down
6 changes: 6 additions & 0 deletions cxplat/cxplat_test/cxplat_test.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@
<ClCompile Include="cxplat_size_test.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="cxplat_rundown_test.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="cxplat_workitem_test.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
Expand Down
50 changes: 50 additions & 0 deletions cxplat/cxplat_test/cxplat_workitem_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) Microsoft Corporation
// SPDX-License-Identifier: MIT

#if !defined(CMAKE_NUGET)
#include <catch2/catch_all.hpp>
#else
#include <catch2/catch.hpp>
#endif
#include "cxplat.h"
#include <windows.h>

static void
_test_work_item_routine(_Inout_opt_ void* work_item_context)
{
int* context = (int*)work_item_context;
REQUIRE(*context == 1);
(*context)++;
}

TEST_CASE("queue_preemptible_work_item", "[workitem]")
{
REQUIRE(cxplat_initialize() == CXPLAT_STATUS_SUCCESS);

cxplat_preemptible_work_item_t* work_item = nullptr;
int context = 1;
REQUIRE(
cxplat_allocate_preemptible_work_item(nullptr, &work_item, _test_work_item_routine, &context) ==
CXPLAT_STATUS_SUCCESS);

cxplat_queue_preemptible_work_item(work_item);
cxplat_wait_for_preemptible_work_items_complete();
REQUIRE(context == 2);

cxplat_cleanup();
}

TEST_CASE("free_preemptible_work_item", "[workitem]")
{
REQUIRE(cxplat_initialize() == CXPLAT_STATUS_SUCCESS);

cxplat_preemptible_work_item_t* work_item = nullptr;
int context = 1;
REQUIRE(
cxplat_allocate_preemptible_work_item(nullptr, &work_item, _test_work_item_routine, &context) ==
CXPLAT_STATUS_SUCCESS);
cxplat_free_preemptible_work_item(work_item);
REQUIRE(context == 1);

cxplat_cleanup();
}
2 changes: 2 additions & 0 deletions cxplat/inc/cxplat.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
#include "cxplat_common.h"
#include "cxplat_fault_injection.h"
#include "cxplat_memory.h"
#include "cxplat_rundown.h"
#include "cxplat_size.h"
#include "cxplat_workitem.h"

CXPLAT_EXTERN_C_BEGIN

Expand Down
1 change: 1 addition & 0 deletions cxplat/inc/cxplat_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,5 @@ typedef _Return_type_success_(CXPLAT_SUCCEEDED(return )) enum {
CXPLAT_STATUS_SUCCESS = CXPLAT_PLATFORM_STATUS_SUCCESS,
CXPLAT_STATUS_NO_MEMORY = CXPLAT_PLATFORM_STATUS_NO_MEMORY,
CXPLAT_STATUS_ARITHMETIC_OVERFLOW = CXPLAT_PLATFORM_STATUS_ARITHMETIC_OVERFLOW,
CXPLAT_STATUS_INVALID_STATE = CXPLAT_PLATFORM_STATUS_INVALID_STATE,
} cxplat_status_t;
4 changes: 2 additions & 2 deletions cxplat/inc/cxplat_memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,9 @@ __drv_allocatesMem(Mem) _Must_inspect_result_

/**
* @brief Allocate memory that has a starting address that is cache aligned with tag.
* @param[in] size Size of memory to allocate
* @param[in] size Size of memory to allocate.
* @param[in] tag Pool tag to use.
* @returns Pointer to memory block allocated, or null on failure.
* @returns Pointer to zero-initialized memory block allocated, or null on failure.
*/
__drv_allocatesMem(Mem) _Must_inspect_result_
_Ret_writes_maybenull_(size) void* cxplat_allocate_cache_aligned_with_tag(size_t size, uint32_t tag);
Expand Down
50 changes: 50 additions & 0 deletions cxplat/inc/cxplat_rundown.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) Microsoft Corporation
// SPDX-License-Identifier: MIT
#pragma once
#include "cxplat_platform.h"

CXPLAT_EXTERN_C_BEGIN

/**
* @brief Initialize the rundown reference table entry for the given context.
*
* @param[in] context The address of a cxplat_rundown_reference_t structure.
*/
void
cxplat_initialize_rundown_protection(_Out_ cxplat_rundown_reference_t* rundown_reference);

/**
* @brief Reinitialize the rundown reference table entry for the given context.
*
* @param[in] context The address of a previously run down cxplat_rundown_reference_t structure.
*/
void
cxplat_reinitialize_rundown_protection(_Inout_ cxplat_rundown_reference_t* rundown_reference);

/**
* @brief Wait for the rundown reference count to reach 0 for the given context.
*
* @param[in] context The address of a cxplat_rundown_reference_t structure.
*/
void
cxplat_wait_for_rundown_protection_release(_Inout_ cxplat_rundown_reference_t* rundown_reference);

/**
* @brief Acquire a rundown reference for the given context.
*
* @param[in] context The address of a cxplat_rundown_reference_t structure.
* @retval TRUE Rundown has not started.
* @retval FALSE Rundown has started.
*/
int
cxplat_acquire_rundown_protection(_Inout_ cxplat_rundown_reference_t* rundown_reference);

/**
* @brief Release a rundown reference for the given context.
*
* @param[in] context The address of a cxplat_rundown_reference_t structure.
*/
void
cxplat_release_rundown_protection(_Inout_ cxplat_rundown_reference_t* rundown_reference);

CXPLAT_EXTERN_C_END
52 changes: 52 additions & 0 deletions cxplat/inc/cxplat_workitem.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) Microsoft Corporation
// SPDX-License-Identifier: MIT
#pragma once

CXPLAT_EXTERN_C_BEGIN

typedef struct _cxplat_preemptible_work_item cxplat_preemptible_work_item_t;

/**
* @brief Create a preemptible work item.
*
* @param[in] caller_context Caller context, such as a DEVICE_OBJECT used to
* create the work item.
* @param[out] work_item Pointer to memory that will contain the pointer to
* the preemptible work item on success.
* @param[in] work_item_routine Routine to execute as a work item.
* @param[in, out] work_item_context Context to pass to the routine.
* @retval CXPLAT_STATUS_SUCCESS The operation was successful.
* @retval CXPLAT_STATUS_NO_MEMORY Unable to allocate resources for this
* work item.
*/
_Must_inspect_result_ cxplat_status_t
cxplat_allocate_preemptible_work_item(
_In_opt_ void* caller_context,
_Outptr_ cxplat_preemptible_work_item_t** work_item,
_In_ void (*work_item_routine)(_Inout_opt_ void* work_item_context),
_Inout_opt_ void* work_item_context);

/**
* @brief Queue a preemptible work item for execution. After execution,
* it will automatically be freed.
*
* @param[in] work_item Pointer to the work item to execute and free.
*/
void
cxplat_queue_preemptible_work_item(_Inout_ cxplat_preemptible_work_item_t* work_item);

/**
* @brief Free a preemptible work item.
*
* @param[in] work_item Pointer to the work item to free.
*/
void
cxplat_free_preemptible_work_item(_Frees_ptr_opt_ cxplat_preemptible_work_item_t* work_item);

/**
* @brief Wait for all preemptible work items to complete.
*/
void
cxplat_wait_for_preemptible_work_items_complete();

CXPLAT_EXTERN_C_END
3 changes: 3 additions & 0 deletions cxplat/inc/winkernel/cxplat_winkernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,8 @@
#define CXPLAT_PLATFORM_STATUS_SUCCESS STATUS_SUCCESS
#define CXPLAT_PLATFORM_STATUS_NO_MEMORY STATUS_NO_MEMORY
#define CXPLAT_PLATFORM_STATUS_ARITHMETIC_OVERFLOW STATUS_INTEGER_OVERFLOW
#define CXPLAT_PLATFORM_STATUS_INVALID_STATE STATUS_INVALID_STATE_TRANSITION

#define CXPLAT_SUCCEEDED(status) NT_SUCCESS(status)

typedef struct _EX_RUNDOWN_REF cxplat_rundown_reference_t;
6 changes: 6 additions & 0 deletions cxplat/inc/winuser/cxplat_winuser.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,11 @@
#define CXPLAT_PLATFORM_STATUS_SUCCESS S_OK
#define CXPLAT_PLATFORM_STATUS_NO_MEMORY __HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY)
#define CXPLAT_PLATFORM_STATUS_ARITHMETIC_OVERFLOW __HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW)
#define CXPLAT_PLATFORM_STATUS_INVALID_STATE __HRESULT_FROM_WIN32(ERROR_INVALID_STATE)

#define CXPLAT_SUCCEEDED(status) SUCCEEDED((HRESULT)(status))

typedef struct _cxplat_rundown_reference
{
void* reserved;
} cxplat_rundown_reference_t;
4 changes: 4 additions & 0 deletions cxplat/src/cxplat_winkernel/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ add_library(cxplat_winkernel STATIC
../../inc/cxplat.h
../../inc/cxplat_common.h
../../inc/cxplat_memory.h
../../inc/cxplat_rundown.h
../../inc/cxplat_workitem.h
../../inc/winkernel/cxplat_fault_injection.h
../../inc/winkernel/cxplat_platform.h
../../inc/winkernel/cxplat_winkernel.h
../memory.c
memory_winkernel.c
rundown_winkernel.c
workitem_winkernel.c
)

target_include_directories(cxplat_winkernel PRIVATE
Expand Down
16 changes: 16 additions & 0 deletions cxplat/src/cxplat_winkernel/cxplat_winkernel.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) Microsoft Corporation
// SPDX-License-Identifier: MIT

// This file contains initialization/cleanup routines for the Windows kernel-mode cxplat library.
#include "cxplat.h"

cxplat_status_t
cxplat_initialize()
{
return CXPLAT_STATUS_SUCCESS;
}

void
cxplat_cleanup()
{
}
5 changes: 5 additions & 0 deletions cxplat/src/cxplat_winkernel/cxplat_winkernel.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,20 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\memory.c" />
<ClCompile Include="cxplat_winkernel.c" />
<ClCompile Include="memory_winkernel.c" />
<ClCompile Include="rundown_winkernel.c" />
<ClCompile Include="size_winkernel.c" />
<ClCompile Include="workitem_winkernel.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\inc\cxplat.h" />
<ClInclude Include="..\..\inc\cxplat_common.h" />
<ClInclude Include="..\..\inc\cxplat_fault_injection.h" />
<ClInclude Include="..\..\inc\cxplat_memory.h" />
<ClInclude Include="..\..\inc\cxplat_rundown.h" />
<ClInclude Include="..\..\inc\cxplat_size.h" />
<ClInclude Include="..\..\inc\cxplat_workitem.h" />
<ClInclude Include="..\..\inc\winkernel\cxplat_platform.h" />
<ClInclude Include="..\..\inc\winkernel\cxplat_winkernel.h" />
</ItemGroup>
Expand Down
18 changes: 18 additions & 0 deletions cxplat/src/cxplat_winkernel/cxplat_winkernel.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,18 @@
<ClCompile Include="memory_winkernel.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="size_winkernel.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="rundown_winkernel.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="workitem_winkernel.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="cxplat_winkernel.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\inc\cxplat.h">
Expand All @@ -44,5 +56,11 @@
<ClInclude Include="..\..\inc\cxplat_size.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\inc\cxplat_rundown.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\inc\cxplat_workitem.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
3 changes: 2 additions & 1 deletion cxplat/src/cxplat_winkernel/memory_winkernel.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,12 @@ cxplat_free(_Frees_ptr_opt_ void* pointer)
__drv_allocatesMem(Mem) _Must_inspect_result_ _Ret_writes_maybenull_(size) void*
cxplat_allocate_cache_aligned_with_tag(size_t size, uint32_t tag)
{
return cxplat_allocate_with_tag(CxPlatNonPagedPoolNxCacheAligned, size, tag, false);
return cxplat_allocate_with_tag(CxPlatNonPagedPoolNxCacheAligned, size, tag, true);
}

void
cxplat_free_cache_aligned(_Frees_ptr_opt_ void* memory)
{
cxplat_free(memory);
}

36 changes: 36 additions & 0 deletions cxplat/src/cxplat_winkernel/rundown_winkernel.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) Microsoft Corporation
// SPDX-License-Identifier: MIT
#include "cxplat.h"
#include <ntddk.h>

// TODO(issue #90): convert these to macros or inline functions
void
cxplat_initialize_rundown_protection(_Out_ cxplat_rundown_reference_t* rundown_reference)
{
ExInitializeRundownProtection(rundown_reference);
}

void
cxplat_reinitialize_rundown_protection(_Inout_ cxplat_rundown_reference_t* rundown_reference)
{
ExReInitializeRundownProtection(rundown_reference);
}

void
cxplat_wait_for_rundown_protection_release(_Inout_ cxplat_rundown_reference_t* rundown_reference)
{
ExWaitForRundownProtectionRelease(rundown_reference);
}

int
cxplat_acquire_rundown_protection(_Inout_ cxplat_rundown_reference_t* rundown_reference)
{
return (int)ExAcquireRundownProtection(rundown_reference);
}

void
cxplat_release_rundown_protection(_Inout_ cxplat_rundown_reference_t* rundown_reference)
{
ExReleaseRundownProtection(rundown_reference);
}

Loading

0 comments on commit 1d9a9f4

Please sign in to comment.