From 279f8cb8269b56ec97b6a36b49b4b8ebdd231946 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Fri, 21 Feb 2025 10:48:11 +0100 Subject: [PATCH 1/4] Add umfFixedMemoryProviderParamsSetFlags() Add umfFixedMemoryProviderParamsSetFlags() to set flags of Fixed-size Memory Provider. Add the UMF_FIXED_FLAG_CREATE_FROM_POOL_PTR flag that makes it possible to create Fixed-size Memory Provider from a pointer belonging to a UMF memory pool. This pointer is already tracked in the UMF tracker, so we will have to remove this memory range --- include/umf/providers/provider_fixed_memory.h | 17 ++++++- src/libumf.def | 1 + src/libumf.map | 1 + src/provider/provider_fixed_memory.c | 44 +++++++++++++++++-- 4 files changed, 59 insertions(+), 4 deletions(-) diff --git a/include/umf/providers/provider_fixed_memory.h b/include/umf/providers/provider_fixed_memory.h index 2351faf312..53a8b5871b 100644 --- a/include/umf/providers/provider_fixed_memory.h +++ b/include/umf/providers/provider_fixed_memory.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Intel Corporation + * Copyright (C) 2024-2025 Intel Corporation * * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception @@ -18,6 +18,14 @@ extern "C" { #define UMF_FIXED_RESULTS_START_FROM 4000 /// @endcond +/// @brief Fixed Memory Provider flags +typedef enum umf_fixed_memory_provider_flag { + UMF_FIXED_FLAG_DEFAULT = 0, ///< the default - no flags set + UMF_FIXED_FLAG_CREATE_FROM_POOL_PTR = + (1 + << 0), ///< The Fixed Memory Provider is created from the UMF pool's pointer +} umf_fixed_memory_provider_flag_t; + struct umf_fixed_memory_provider_params_t; typedef struct umf_fixed_memory_provider_params_t @@ -41,6 +49,13 @@ umf_result_t umfFixedMemoryProviderParamsCreate( umf_result_t umfFixedMemoryProviderParamsSetMemory( umf_fixed_memory_provider_params_handle_t hParams, void *ptr, size_t size); +/// @brief Set the memory region flags in params struct. +/// @param hParams [in] handle to the parameters of the Fixed Memory Provider. +/// @param flags [in] flags for the memory region. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfFixedMemoryProviderParamsSetFlags( + umf_fixed_memory_provider_params_handle_t hParams, unsigned int flags); + /// @brief Destroy parameters struct. /// @param hParams [in] handle to the parameters of the Fixed Memory Provider. /// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. diff --git a/src/libumf.def b/src/libumf.def index ce8820a8fa..c86b9c5c6e 100644 --- a/src/libumf.def +++ b/src/libumf.def @@ -134,5 +134,6 @@ EXPORTS umfFixedMemoryProviderOps umfFixedMemoryProviderParamsCreate umfFixedMemoryProviderParamsDestroy + umfFixedMemoryProviderParamsSetFlags umfLevelZeroMemoryProviderParamsSetFreePolicy umfLevelZeroMemoryProviderParamsSetDeviceOrdinal diff --git a/src/libumf.map b/src/libumf.map index 6582fd0f8d..7e8c0fb6f9 100644 --- a/src/libumf.map +++ b/src/libumf.map @@ -132,6 +132,7 @@ UMF_0.11 { umfFixedMemoryProviderOps; umfFixedMemoryProviderParamsCreate; umfFixedMemoryProviderParamsDestroy; + umfFixedMemoryProviderParamsSetFlags; umfLevelZeroMemoryProviderParamsSetFreePolicy; umfLevelZeroMemoryProviderParamsSetDeviceOrdinal; } UMF_0.10; diff --git a/src/provider/provider_fixed_memory.c b/src/provider/provider_fixed_memory.c index eeeb8b7025..56f51a579d 100644 --- a/src/provider/provider_fixed_memory.c +++ b/src/provider/provider_fixed_memory.c @@ -27,15 +27,20 @@ #define TLS_MSG_BUF_LEN 1024 typedef struct fixed_memory_provider_t { - void *base; // base address of memory - size_t size; // size of the memory region - coarse_t *coarse; // coarse library handle + void *base; // base address of memory + size_t size; // size of the memory region + unsigned int flags; // flags of the memory region + coarse_t *coarse; // coarse library handle + + // used only when the UMF_FIXED_FLAG_CREATE_FROM_POOL_PTR flag is set + size_t ptr_orig_size; // original size of the memory region in the tracker } fixed_memory_provider_t; // Fixed Memory provider settings struct typedef struct umf_fixed_memory_provider_params_t { void *ptr; size_t size; + unsigned int flags; } umf_fixed_memory_provider_params_t; typedef struct fixed_last_native_error_t { @@ -83,6 +88,7 @@ static umf_result_t fixed_allocation_merge_cb(void *provider, void *lowPtr, static umf_result_t fixed_initialize(void *params, void **provider) { umf_result_t ret; + size_t ptr_orig_size = 0; if (params == NULL) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; @@ -91,6 +97,15 @@ static umf_result_t fixed_initialize(void *params, void **provider) { umf_fixed_memory_provider_params_t *in_params = (umf_fixed_memory_provider_params_t *)params; + if (in_params->flags & UMF_FIXED_FLAG_CREATE_FROM_POOL_PTR) { + umf_memory_pool_handle_t pool = umfPoolByPtr(in_params->ptr); + if (pool == NULL) { + LOG_ERR("The UMF_FIXED_FLAG_CREATE_FROM_POOL_PTR flag is set, but " + "the given pointer does not belong to any UMF pool"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + } + fixed_memory_provider_t *fixed_provider = umf_ba_global_alloc(sizeof(*fixed_provider)); if (!fixed_provider) { @@ -122,6 +137,8 @@ static umf_result_t fixed_initialize(void *params, void **provider) { fixed_provider->base = in_params->ptr; fixed_provider->size = in_params->size; + fixed_provider->flags = in_params->flags; + fixed_provider->ptr_orig_size = ptr_orig_size; // add the entire memory as a single block ret = coarse_add_memory_fixed(coarse, fixed_provider->base, @@ -333,5 +350,26 @@ umf_result_t umfFixedMemoryProviderParamsSetMemory( hParams->ptr = ptr; hParams->size = size; + hParams->flags = 0; + + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfFixedMemoryProviderParamsSetFlags( + umf_fixed_memory_provider_params_handle_t hParams, unsigned int flags) { + if (hParams == NULL) { + LOG_ERR("Memory Provider params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + if ((flags & UMF_FIXED_FLAG_CREATE_FROM_POOL_PTR) && + (umfPoolByPtr(hParams->ptr) == NULL)) { + LOG_ERR("Cannot set the UMF_FIXED_FLAG_CREATE_FROM_POOL_PTR, because " + "the given pointer does not belong to any UMF pool"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->flags = flags; + return UMF_RESULT_SUCCESS; } From b4d91c3588472f7ad6b16153a15334a1f3eb39a2 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Fri, 21 Feb 2025 09:13:05 +0100 Subject: [PATCH 2/4] Add umfPoolGetTrackingProvider() Add umfPoolGetTrackingProvider() to get the tracking provider of the original memory pool. Signed-off-by: Lukasz Dorau --- src/memory_pool.c | 16 ++++++++++++++++ src/memory_pool_internal.h | 4 ++++ src/provider/provider_fixed_memory.c | 11 +++++++++++ 3 files changed, 31 insertions(+) diff --git a/src/memory_pool.c b/src/memory_pool.c index ef2c0fa66b..436bb4f2ec 100644 --- a/src/memory_pool.c +++ b/src/memory_pool.c @@ -136,6 +136,22 @@ umf_result_t umfPoolGetMemoryProvider(umf_memory_pool_handle_t hPool, return UMF_RESULT_SUCCESS; } +umf_result_t +umfPoolGetTrackingProvider(umf_memory_pool_handle_t hPool, + umf_memory_provider_handle_t *hProvider) { + if (!hPool || !hProvider) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + if (hPool->flags & UMF_POOL_CREATE_FLAG_DISABLE_TRACKING) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + *hProvider = umfMemoryProviderGetPriv(hPool->provider); + + return UMF_RESULT_SUCCESS; +} + umf_result_t umfPoolCreate(const umf_memory_pool_ops_t *ops, umf_memory_provider_handle_t provider, void *params, umf_pool_create_flags_t flags, diff --git a/src/memory_pool_internal.h b/src/memory_pool_internal.h index ab3378163d..977756db66 100644 --- a/src/memory_pool_internal.h +++ b/src/memory_pool_internal.h @@ -36,6 +36,10 @@ typedef struct umf_memory_pool_t { void *tag; } umf_memory_pool_t; +umf_result_t +umfPoolGetTrackingProvider(umf_memory_pool_handle_t hPool, + umf_memory_provider_handle_t *hProvider); + #ifdef __cplusplus } #endif diff --git a/src/provider/provider_fixed_memory.c b/src/provider/provider_fixed_memory.c index 56f51a579d..269e5c11f6 100644 --- a/src/provider/provider_fixed_memory.c +++ b/src/provider/provider_fixed_memory.c @@ -20,6 +20,7 @@ #include "base_alloc_global.h" #include "coarse.h" #include "libumf.h" +#include "memory_pool_internal.h" #include "utils_common.h" #include "utils_concurrency.h" #include "utils_log.h" @@ -34,6 +35,8 @@ typedef struct fixed_memory_provider_t { // used only when the UMF_FIXED_FLAG_CREATE_FROM_POOL_PTR flag is set size_t ptr_orig_size; // original size of the memory region in the tracker + umf_memory_provider_handle_t + trackingProvider; // tracking provider of the original memory pool } fixed_memory_provider_t; // Fixed Memory provider settings struct @@ -89,6 +92,7 @@ static umf_result_t fixed_allocation_merge_cb(void *provider, void *lowPtr, static umf_result_t fixed_initialize(void *params, void **provider) { umf_result_t ret; size_t ptr_orig_size = 0; + umf_memory_provider_handle_t trackingProvider = NULL; if (params == NULL) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; @@ -104,6 +108,12 @@ static umf_result_t fixed_initialize(void *params, void **provider) { "the given pointer does not belong to any UMF pool"); return UMF_RESULT_ERROR_INVALID_ARGUMENT; } + + ret = umfPoolGetTrackingProvider(pool, &trackingProvider); + if (ret != UMF_RESULT_SUCCESS) { + LOG_ERR("cannot get the tracking provider of the pool %p", pool); + return ret; + } } fixed_memory_provider_t *fixed_provider = @@ -139,6 +149,7 @@ static umf_result_t fixed_initialize(void *params, void **provider) { fixed_provider->size = in_params->size; fixed_provider->flags = in_params->flags; fixed_provider->ptr_orig_size = ptr_orig_size; + fixed_provider->trackingProvider = trackingProvider; // add the entire memory as a single block ret = coarse_add_memory_fixed(coarse, fixed_provider->base, From 719dd6fce9a4f043e05343f90f0615f9ea352c5c Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 20 Feb 2025 10:50:32 +0100 Subject: [PATCH 3/4] Add trackerShrinkEntry() and trackerGrowEntry() Add trackerShrinkEntry() that shrinks (or removes) an entry in the tracker and returns the totalSize of the original entry. Add trackerGrowEntry() that grows (or adds) an entry in the tracker to its original size. Signed-off-by: Lukasz Dorau --- src/provider/provider_fixed_memory.c | 24 ++++++ src/provider/provider_tracking.c | 111 +++++++++++++++++++++++++++ src/provider/provider_tracking.h | 6 ++ 3 files changed, 141 insertions(+) diff --git a/src/provider/provider_fixed_memory.c b/src/provider/provider_fixed_memory.c index 269e5c11f6..1955c0ef3b 100644 --- a/src/provider/provider_fixed_memory.c +++ b/src/provider/provider_fixed_memory.c @@ -21,6 +21,7 @@ #include "coarse.h" #include "libumf.h" #include "memory_pool_internal.h" +#include "provider_tracking.h" #include "utils_common.h" #include "utils_concurrency.h" #include "utils_log.h" @@ -114,6 +115,15 @@ static umf_result_t fixed_initialize(void *params, void **provider) { LOG_ERR("cannot get the tracking provider of the pool %p", pool); return ret; } + + ret = trackerShrinkEntry(trackingProvider, in_params->ptr, + in_params->size, &ptr_orig_size); + if (ret != UMF_RESULT_SUCCESS) { + LOG_ERR( + "cannot shrink the allocation %p in the tracker to size %zu", + in_params->ptr, in_params->size); + return ret; + } } fixed_memory_provider_t *fixed_provider = @@ -173,6 +183,20 @@ static umf_result_t fixed_initialize(void *params, void **provider) { static void fixed_finalize(void *provider) { fixed_memory_provider_t *fixed_provider = provider; coarse_delete(fixed_provider->coarse); + + if (fixed_provider->trackingProvider && + (fixed_provider->ptr_orig_size >= fixed_provider->size)) { + umf_result_t ret = trackerGrowEntry( + fixed_provider->trackingProvider, fixed_provider->base, + fixed_provider->size, fixed_provider->ptr_orig_size); + if (ret != UMF_RESULT_SUCCESS) { + LOG_ERR("cannot grow the allocation %p in the tracker (from size " + "%zu to size %zu)", + fixed_provider->base, fixed_provider->size, + fixed_provider->ptr_orig_size); + } + } + umf_ba_global_free(fixed_provider); } diff --git a/src/provider/provider_tracking.c b/src/provider/provider_tracking.c index 62145d5d77..fd9634d879 100644 --- a/src/provider/provider_tracking.c +++ b/src/provider/provider_tracking.c @@ -267,6 +267,58 @@ static umf_result_t trackingAllocationSplit(void *hProvider, void *ptr, return ret; } +// shrink (or remove) an entry in the tracker and return the totalSize of the original entry +umf_result_t trackerShrinkEntry(void *hProvider, void *ptr, size_t shrinkSize, + size_t *totalSize) { + umf_result_t ret = UMF_RESULT_SUCCESS; + umf_tracking_memory_provider_t *provider = + (umf_tracking_memory_provider_t *)hProvider; + + int r = utils_mutex_lock(&provider->hTracker->splitMergeMutex); + if (r) { + return UMF_RESULT_ERROR_UNKNOWN; + } + + tracker_alloc_info_t *value = (tracker_alloc_info_t *)critnib_get( + provider->hTracker->alloc_segments_map, (uintptr_t)ptr); + if (!value) { + LOG_ERR("region for shrinking is not found in the tracker"); + ret = UMF_RESULT_ERROR_INVALID_ARGUMENT; + goto err; + } + if (shrinkSize > value->size) { + LOG_ERR("requested size %zu to shrink exceeds the tracked size %zu", + shrinkSize, value->size); + ret = UMF_RESULT_ERROR_INVALID_ARGUMENT; + goto err; + } + + if (shrinkSize < value->size) { + void *highPtr = (void *)(((uintptr_t)ptr) + shrinkSize); + size_t secondSize = value->size - shrinkSize; + ret = umfMemoryTrackerAdd(provider->hTracker, provider->pool, highPtr, + secondSize); + if (ret != UMF_RESULT_SUCCESS) { + LOG_ERR("failed to add the new shrunk region to the tracker, ptr = " + "%p, size = %zu, ret = %d", + highPtr, secondSize, ret); + goto err; + } + } + + *totalSize = value->size; + + void *erasedValue = + critnib_remove(provider->hTracker->alloc_segments_map, (uintptr_t)ptr); + assert(erasedValue == value); + umf_ba_free(provider->hTracker->alloc_info_allocator, erasedValue); + +err: + utils_mutex_unlock(&provider->hTracker->splitMergeMutex); + + return ret; +} + static umf_result_t trackingAllocationMerge(void *hProvider, void *lowPtr, void *highPtr, size_t totalSize) { umf_result_t ret = UMF_RESULT_ERROR_UNKNOWN; @@ -353,6 +405,65 @@ static umf_result_t trackingAllocationMerge(void *hProvider, void *lowPtr, return ret; } +// grow (or add) an entry in the tracker to its original size +umf_result_t trackerGrowEntry(void *hProvider, void *ptr, size_t growSize, + size_t origSize) { + umf_result_t ret = UMF_RESULT_SUCCESS; + umf_tracking_memory_provider_t *provider = + (umf_tracking_memory_provider_t *)hProvider; + + if (growSize > origSize) { + LOG_ERR("Invalid grow size %zu (larger than the original size %zu)", + growSize, origSize); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + int r = utils_mutex_lock(&provider->hTracker->splitMergeMutex); + if (r) { + return UMF_RESULT_ERROR_UNKNOWN; + } + + void *highPtr = (void *)(((uintptr_t)ptr) + growSize); + tracker_alloc_info_t *highValue = NULL; + + if (growSize < origSize) { + highValue = (tracker_alloc_info_t *)critnib_get( + provider->hTracker->alloc_segments_map, (uintptr_t)highPtr); + if (!highValue) { + LOG_ERR("cannot find the tracker entry to grow %p", highPtr); + ret = UMF_RESULT_ERROR_INVALID_ARGUMENT; + goto err; + } + if (growSize + highValue->size != origSize) { + LOG_ERR("Grow size plus the current size does not equal the " + "original size"); + ret = UMF_RESULT_ERROR_INVALID_ARGUMENT; + goto err; + } + } + + ret = + umfMemoryTrackerAdd(provider->hTracker, provider->pool, ptr, origSize); + if (ret != UMF_RESULT_SUCCESS) { + LOG_ERR("failed to add the new grown region to the tracker, ptr = %p, " + "size = %zu, ret = %d", + ptr, origSize, ret); + goto err; + } + + if (growSize < origSize) { + void *erasedhighValue = critnib_remove( + provider->hTracker->alloc_segments_map, (uintptr_t)highPtr); + assert(erasedhighValue == highValue); + umf_ba_free(provider->hTracker->alloc_info_allocator, erasedhighValue); + } + +err: + utils_mutex_unlock(&provider->hTracker->splitMergeMutex); + + return ret; +} + static umf_result_t trackingFree(void *hProvider, void *ptr, size_t size) { umf_result_t ret; umf_result_t ret_remove = UMF_RESULT_ERROR_UNKNOWN; diff --git a/src/provider/provider_tracking.h b/src/provider/provider_tracking.h index 9e868cf311..f791ed190f 100644 --- a/src/provider/provider_tracking.h +++ b/src/provider/provider_tracking.h @@ -55,6 +55,12 @@ void umfTrackingMemoryProviderGetUpstreamProvider( umf_memory_provider_handle_t hTrackingProvider, umf_memory_provider_handle_t *hUpstream); +umf_result_t trackerShrinkEntry(void *hProvider, void *ptr, size_t shrinkSize, + size_t *totalSize); + +umf_result_t trackerGrowEntry(void *hProvider, void *ptr, size_t growSize, + size_t origSize); + #ifdef __cplusplus } #endif From d6d8f6031113673ca69490a87f5f990f1d85d6bc Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Fri, 21 Feb 2025 10:46:38 +0100 Subject: [PATCH 4/4] Add tests for pool from pointer Signed-off-by: Lukasz Dorau --- test/provider_fixed_memory.cpp | 225 ++++++++++++++++++++++++++++++++- 1 file changed, 223 insertions(+), 2 deletions(-) diff --git a/test/provider_fixed_memory.cpp b/test/provider_fixed_memory.cpp index 7f976a1f5d..f1f913fe0b 100644 --- a/test/provider_fixed_memory.cpp +++ b/test/provider_fixed_memory.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2024 Intel Corporation +// Copyright (C) 2024-2025 Intel Corporation // Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception @@ -11,10 +11,12 @@ #endif #include +#include #include using umf_test::test; +#define FIXED_BUFFER_SIZE (10 * utils_get_page_size()) #define INVALID_PTR ((void *)0x01) typedef enum purge_t { @@ -59,7 +61,7 @@ struct FixedProviderTest test::SetUp(); // Allocate a memory buffer to use with the fixed memory provider - memory_size = utils_get_page_size() * 10; // Allocate 10 pages + memory_size = FIXED_BUFFER_SIZE; // Allocate 10 pages memory_buffer = malloc(memory_size); ASSERT_NE(memory_buffer, nullptr); @@ -391,3 +393,222 @@ TEST_P(FixedProviderTest, split) { umf_result = umfMemoryProviderFree(provider.get(), ptr2, size); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); } + +TEST_P(FixedProviderTest, params_set_flags_negative) { + umf_result_t umf_result; + + // Create provider parameters + umf_fixed_memory_provider_params_handle_t params = nullptr; + umf_result = + umfFixedMemoryProviderParamsCreate(¶ms, memory_buffer, memory_size); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(params, nullptr); + + // params is NULL + umf_result = umfFixedMemoryProviderParamsSetFlags( + NULL, UMF_FIXED_FLAG_CREATE_FROM_POOL_PTR); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + // the pointer does not belong to any UMF pool + umf_result = umfFixedMemoryProviderParamsSetFlags( + params, UMF_FIXED_FLAG_CREATE_FROM_POOL_PTR); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + umfFixedMemoryProviderParamsDestroy(params); +} + +TEST_P(FixedProviderTest, pool_from_ptr_negative_wrong_ptr) { + umf_result_t umf_result; + size_t size_of_first_alloc; + size_t size_of_pool_from_ptr; + void *ptr_for_pool = nullptr; + + umf_memory_pool_handle_t proxyFixedPool = nullptr; + umf_result = umfPoolCreate(umfProxyPoolOps(), provider.get(), nullptr, 0, + &proxyFixedPool); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + size_of_first_alloc = FIXED_BUFFER_SIZE - (2 * page_size); + ptr_for_pool = umfPoolMalloc(proxyFixedPool, size_of_first_alloc); + ASSERT_NE(ptr_for_pool, nullptr); + + // Create provider parameters + size_of_pool_from_ptr = size_of_first_alloc; // whole size + umf_fixed_memory_provider_params_handle_t params = nullptr; + umf_result = umfFixedMemoryProviderParamsCreate(¶ms, ptr_for_pool, + size_of_pool_from_ptr); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(params, nullptr); + + umf_result = umfFixedMemoryProviderParamsSetFlags( + params, UMF_FIXED_FLAG_CREATE_FROM_POOL_PTR); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = umfPoolFree(proxyFixedPool, ptr_for_pool); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + // the pointer (ptr_for_pool) does not belong to any UMF pool + umf_memory_provider_handle_t providerFromPtr = nullptr; + umf_result = umfMemoryProviderCreate(umfFixedMemoryProviderOps(), params, + &providerFromPtr); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); + ASSERT_EQ(providerFromPtr, nullptr); + + umfFixedMemoryProviderParamsDestroy(params); + umfPoolDestroy(proxyFixedPool); +} + +TEST_P(FixedProviderTest, pool_from_ptr_negative_shrink_size_too_big) { + umf_result_t umf_result; + size_t size_of_first_alloc; + size_t size_of_pool_from_ptr; + void *ptr_for_pool = nullptr; + + umf_memory_pool_handle_t proxyFixedPool = nullptr; + umf_result = umfPoolCreate(umfProxyPoolOps(), provider.get(), nullptr, 0, + &proxyFixedPool); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + size_of_first_alloc = FIXED_BUFFER_SIZE - (2 * page_size); + ptr_for_pool = umfPoolMalloc(proxyFixedPool, size_of_first_alloc); + ASSERT_NE(ptr_for_pool, nullptr); + + // Create provider parameters + size_of_pool_from_ptr = size_of_first_alloc + 1; // size too big + umf_fixed_memory_provider_params_handle_t params = nullptr; + umf_result = umfFixedMemoryProviderParamsCreate(¶ms, ptr_for_pool, + size_of_pool_from_ptr); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(params, nullptr); + + umf_result = umfFixedMemoryProviderParamsSetFlags( + params, UMF_FIXED_FLAG_CREATE_FROM_POOL_PTR); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_memory_provider_handle_t providerFromPtr = nullptr; + umf_result = umfMemoryProviderCreate(umfFixedMemoryProviderOps(), params, + &providerFromPtr); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); + ASSERT_EQ(providerFromPtr, nullptr); + + umfFixedMemoryProviderParamsDestroy(params); + + umf_result = umfPoolFree(proxyFixedPool, ptr_for_pool); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umfPoolDestroy(proxyFixedPool); +} + +TEST_P(FixedProviderTest, pool_from_ptr_whole_size_success) { + umf_result_t umf_result; + size_t size_of_first_alloc; + size_t size_of_pool_from_ptr; + void *ptr_for_pool = nullptr; + void *ptr = nullptr; + + umf_memory_pool_handle_t proxyFixedPool = nullptr; + umf_result = umfPoolCreate(umfProxyPoolOps(), provider.get(), nullptr, 0, + &proxyFixedPool); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + size_of_first_alloc = FIXED_BUFFER_SIZE - (2 * page_size); + ptr_for_pool = umfPoolMalloc(proxyFixedPool, size_of_first_alloc); + ASSERT_NE(ptr_for_pool, nullptr); + + // Create provider parameters + size_of_pool_from_ptr = size_of_first_alloc; // whole size + umf_fixed_memory_provider_params_handle_t params = nullptr; + umf_result = umfFixedMemoryProviderParamsCreate(¶ms, ptr_for_pool, + size_of_pool_from_ptr); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(params, nullptr); + + umf_result = umfFixedMemoryProviderParamsSetFlags( + params, UMF_FIXED_FLAG_CREATE_FROM_POOL_PTR); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_memory_provider_handle_t providerFromPtr = nullptr; + umf_result = umfMemoryProviderCreate(umfFixedMemoryProviderOps(), params, + &providerFromPtr); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(providerFromPtr, nullptr); + + umf_memory_pool_handle_t poolFromPtr = nullptr; + umf_result = umfPoolCreate(umfProxyPoolOps(), providerFromPtr, nullptr, 0, + &poolFromPtr); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + ptr = umfPoolMalloc(poolFromPtr, size_of_pool_from_ptr); + ASSERT_NE(ptr, nullptr); + + memset(ptr, 0xFF, size_of_pool_from_ptr); + + umf_result = umfPoolFree(poolFromPtr, ptr); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umfPoolDestroy(poolFromPtr); + umfMemoryProviderDestroy(providerFromPtr); + umfFixedMemoryProviderParamsDestroy(params); + + umf_result = umfPoolFree(proxyFixedPool, ptr_for_pool); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umfPoolDestroy(proxyFixedPool); +} + +TEST_P(FixedProviderTest, pool_from_ptr_half_size_success) { + umf_result_t umf_result; + size_t size_of_first_alloc; + size_t size_of_pool_from_ptr; + void *ptr_for_pool = nullptr; + void *ptr = nullptr; + + umf_memory_pool_handle_t proxyFixedPool = nullptr; + umf_result = umfPoolCreate(umfProxyPoolOps(), provider.get(), nullptr, 0, + &proxyFixedPool); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + size_of_first_alloc = FIXED_BUFFER_SIZE - (2 * page_size); + ptr_for_pool = umfPoolMalloc(proxyFixedPool, size_of_first_alloc); + ASSERT_NE(ptr_for_pool, nullptr); + + // Create provider parameters + size_of_pool_from_ptr = size_of_first_alloc / 2; // half size + umf_fixed_memory_provider_params_handle_t params = nullptr; + umf_result = umfFixedMemoryProviderParamsCreate(¶ms, ptr_for_pool, + size_of_pool_from_ptr); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(params, nullptr); + + umf_result = umfFixedMemoryProviderParamsSetFlags( + params, UMF_FIXED_FLAG_CREATE_FROM_POOL_PTR); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_memory_provider_handle_t providerFromPtr = nullptr; + umf_result = umfMemoryProviderCreate(umfFixedMemoryProviderOps(), params, + &providerFromPtr); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(providerFromPtr, nullptr); + + umf_memory_pool_handle_t poolFromPtr = nullptr; + umf_result = umfPoolCreate(umfProxyPoolOps(), providerFromPtr, nullptr, 0, + &poolFromPtr); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + ptr = umfPoolMalloc(poolFromPtr, size_of_pool_from_ptr); + ASSERT_NE(ptr, nullptr); + + memset(ptr, 0xFF, size_of_pool_from_ptr); + + umf_result = umfPoolFree(poolFromPtr, ptr); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umfPoolDestroy(poolFromPtr); + umfMemoryProviderDestroy(providerFromPtr); + umfFixedMemoryProviderParamsDestroy(params); + + umf_result = umfPoolFree(proxyFixedPool, ptr_for_pool); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umfPoolDestroy(proxyFixedPool); +}