Implement preemptible work items for user mode (#1025)

* fix

* cr comments
This commit is contained in:
saxena-anurag 2022-04-28 08:03:55 -07:00 коммит произвёл GitHub
Родитель 74973a92df
Коммит 5be88a6432
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
1 изменённых файлов: 121 добавлений и 21 удалений

Просмотреть файл

@ -2,6 +2,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#include "ebpf_platform.h" #include "ebpf_platform.h"
#include "ebpf_utilities.h"
#include <intsafe.h> #include <intsafe.h>
#include <map> #include <map>
#include <mutex> #include <mutex>
@ -20,15 +21,78 @@ bool _ebpf_platform_is_preemptible = true;
extern "C" bool ebpf_fuzzing_enabled = false; extern "C" bool ebpf_fuzzing_enabled = false;
// Thread pool related globals.
static TP_CALLBACK_ENVIRON _callback_environment;
static PTP_POOL _pool = nullptr;
static PTP_CLEANUP_GROUP _cleanup_group = nullptr;
static ebpf_result_t
_initialize_thread_pool()
{
ebpf_result_t result = EBPF_SUCCESS;
bool cleanup_group_created = false;
bool return_value;
InitializeThreadpoolEnvironment(&_callback_environment);
_pool = CreateThreadpool(nullptr);
if (_pool == nullptr) {
result = win32_error_code_to_ebpf_result(GetLastError());
goto Exit;
}
SetThreadpoolThreadMaximum(_pool, 1);
return_value = SetThreadpoolThreadMinimum(_pool, 1);
if (!return_value) {
result = win32_error_code_to_ebpf_result(GetLastError());
goto Exit;
}
_cleanup_group = CreateThreadpoolCleanupGroup();
if (_cleanup_group == nullptr) {
result = win32_error_code_to_ebpf_result(GetLastError());
goto Exit;
}
cleanup_group_created = true;
SetThreadpoolCallbackPool(&_callback_environment, _pool);
SetThreadpoolCallbackCleanupGroup(&_callback_environment, _cleanup_group, nullptr);
Exit:
if (result != EBPF_SUCCESS) {
if (cleanup_group_created) {
CloseThreadpoolCleanupGroup(_cleanup_group);
}
if (_pool) {
CloseThreadpool(_pool);
_pool = nullptr;
}
}
return result;
}
static void
_clean_up_thread_pool()
{
if (!_pool) {
return;
}
CloseThreadpoolCleanupGroupMembers(_cleanup_group, false, nullptr);
CloseThreadpoolCleanupGroup(_cleanup_group);
CloseThreadpool(_pool);
}
ebpf_result_t ebpf_result_t
ebpf_platform_initiate() ebpf_platform_initiate()
{ {
return EBPF_SUCCESS; return _initialize_thread_pool();
} }
void void
ebpf_platform_terminate() ebpf_platform_terminate()
{} {
_clean_up_thread_pool();
}
ebpf_result_t ebpf_result_t
ebpf_get_code_integrity_state(_Out_ ebpf_code_integrity_state_t* state) ebpf_get_code_integrity_state(_Out_ ebpf_code_integrity_state_t* state)
@ -364,7 +428,9 @@ ebpf_lock_destroy(_In_ ebpf_lock_t* lock)
} }
_Requires_lock_not_held_(*lock) _Acquires_lock_(*lock) _IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_saves_ _Requires_lock_not_held_(*lock) _Acquires_lock_(*lock) _IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_saves_
_IRQL_raises_(DISPATCH_LEVEL) ebpf_lock_state_t ebpf_lock_lock(_In_ ebpf_lock_t* lock) _IRQL_raises_(DISPATCH_LEVEL)
ebpf_lock_state_t
ebpf_lock_lock(_In_ ebpf_lock_t* lock)
{ {
AcquireSRWLockExclusive(reinterpret_cast<PSRWLOCK>(lock)); AcquireSRWLockExclusive(reinterpret_cast<PSRWLOCK>(lock));
return 0; return 0;
@ -446,9 +512,7 @@ ebpf_is_non_preemptible_work_item_supported()
bool bool
ebpf_is_preemptible_work_item_supported() ebpf_is_preemptible_work_item_supported()
{ {
// TODO: (Issue# 854) Add support for creating threads to queue preemptible work items in user mode. return true;
// https://github.com/microsoft/ebpf-for-windows/issues/854
return false;
} }
uint32_t uint32_t
@ -491,12 +555,34 @@ ebpf_queue_non_preemptible_work_item(_In_ ebpf_non_preemptible_work_item_t* work
return false; return false;
} }
typedef struct _ebpf_preemptible_work_item
{
PTP_WORK work;
void (*work_item_routine)(_In_opt_ const void* work_item_context);
void* work_item_context;
} ebpf_preemptible_work_item_t;
static void
_ebpf_preemptible_routine(_Inout_ PTP_CALLBACK_INSTANCE instance, _In_opt_ PVOID parameter, _Inout_ PTP_WORK work)
{
UNREFERENCED_PARAMETER(instance);
UNREFERENCED_PARAMETER(work);
if (parameter == nullptr) {
return;
}
ebpf_preemptible_work_item_t* work_item = (ebpf_preemptible_work_item_t*)parameter;
work_item->work_item_routine(work_item->work_item_context);
ebpf_free(work_item->work_item_context);
ebpf_free(work_item);
}
void void
ebpf_queue_preemptible_work_item(_In_ ebpf_preemptible_work_item_t* work_item) ebpf_queue_preemptible_work_item(_In_ ebpf_preemptible_work_item_t* work_item)
{ {
UNREFERENCED_PARAMETER(work_item); SubmitThreadpoolWork(work_item->work);
// TODO: (Issue# 854) Add support for creating threads to queue preemptible work items in user mode.
// https://github.com/microsoft/ebpf-for-windows/issues/854
} }
ebpf_result_t ebpf_result_t
@ -505,12 +591,26 @@ ebpf_allocate_preemptible_work_item(
_In_ void (*work_item_routine)(_In_opt_ const void* work_item_context), _In_ void (*work_item_routine)(_In_opt_ const void* work_item_context),
_In_opt_ void* work_item_context) _In_opt_ void* work_item_context)
{ {
UNREFERENCED_PARAMETER(work_item); ebpf_result_t result = EBPF_SUCCESS;
UNREFERENCED_PARAMETER(work_item_routine); *work_item = (ebpf_preemptible_work_item_t*)ebpf_allocate(sizeof(ebpf_preemptible_work_item_t));
UNREFERENCED_PARAMETER(work_item_context); if (*work_item == nullptr) {
// TODO: (Issue# 854) Add support for creating threads to queue preemptible work items in user mode. return EBPF_NO_MEMORY;
// https://github.com/microsoft/ebpf-for-windows/issues/854 }
return EBPF_OPERATION_NOT_SUPPORTED;
(*work_item)->work = CreateThreadpoolWork(_ebpf_preemptible_routine, *work_item, &_callback_environment);
if ((*work_item)->work == nullptr) {
result = win32_error_code_to_ebpf_result(GetLastError());
goto Done;
}
(*work_item)->work_item_routine = work_item_routine;
(*work_item)->work_item_context = work_item_context;
Done:
if (result != EBPF_SUCCESS) {
ebpf_free(*work_item);
*work_item = nullptr;
}
return result;
} }
typedef struct _ebpf_timer_work_item typedef struct _ebpf_timer_work_item
@ -538,11 +638,11 @@ ebpf_allocate_timer_work_item(
{ {
*work_item = (ebpf_timer_work_item_t*)ebpf_allocate(sizeof(ebpf_timer_work_item_t)); *work_item = (ebpf_timer_work_item_t*)ebpf_allocate(sizeof(ebpf_timer_work_item_t));
if (*work_item == NULL) if (*work_item == nullptr)
goto Error; goto Error;
(*work_item)->threadpool_timer = CreateThreadpoolTimer(_ebpf_timer_callback, *work_item, NULL); (*work_item)->threadpool_timer = CreateThreadpoolTimer(_ebpf_timer_callback, *work_item, nullptr);
if ((*work_item)->threadpool_timer == NULL) if ((*work_item)->threadpool_timer == nullptr)
goto Error; goto Error;
(*work_item)->work_item_routine = work_item_routine; (*work_item)->work_item_routine = work_item_routine;
@ -551,8 +651,8 @@ ebpf_allocate_timer_work_item(
return EBPF_SUCCESS; return EBPF_SUCCESS;
Error: Error:
if (*work_item != NULL) { if (*work_item != nullptr) {
if ((*work_item)->threadpool_timer != NULL) if ((*work_item)->threadpool_timer != nullptr)
CloseThreadpoolTimer((*work_item)->threadpool_timer); CloseThreadpoolTimer((*work_item)->threadpool_timer);
ebpf_free(*work_item); ebpf_free(*work_item);
@ -697,7 +797,7 @@ Done:
uint32_t uint32_t
ebpf_result_to_win32_error_code(ebpf_result_t result) ebpf_result_to_win32_error_code(ebpf_result_t result)
{ {
static uint32_t (*RtlNtStatusToDosError)(NTSTATUS Status) = NULL; static uint32_t (*RtlNtStatusToDosError)(NTSTATUS Status) = nullptr;
if (!RtlNtStatusToDosError) { if (!RtlNtStatusToDosError) {
HMODULE ntdll = LoadLibrary(L"ntdll.dll"); HMODULE ntdll = LoadLibrary(L"ntdll.dll");
if (!ntdll) { if (!ntdll) {