diff --git a/include/umf/providers/provider_fixed_memory.h b/include/umf/providers/provider_fixed_memory.h index 2351faf31..53a8b5871 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 ce8820a8f..c86b9c5c6 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 6582fd0f8..7e8c0fb6f 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/memory_pool.c b/src/memory_pool.c index ef2c0fa66..436bb4f2e 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 ab3378163..977756db6 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 eeeb8b702..1955c0ef3 100644 --- a/src/provider/provider_fixed_memory.c +++ b/src/provider/provider_fixed_memory.c @@ -20,6 +20,8 @@ #include "base_alloc_global.h" #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" @@ -27,15 +29,22 @@ #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 + umf_memory_provider_handle_t + trackingProvider; // tracking provider of the original memory pool } 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 +92,8 @@ 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; @@ -91,6 +102,30 @@ 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; + } + + ret = umfPoolGetTrackingProvider(pool, &trackingProvider); + if (ret != UMF_RESULT_SUCCESS) { + 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 = umf_ba_global_alloc(sizeof(*fixed_provider)); if (!fixed_provider) { @@ -122,6 +157,9 @@ 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; + fixed_provider->trackingProvider = trackingProvider; // add the entire memory as a single block ret = coarse_add_memory_fixed(coarse, fixed_provider->base, @@ -145,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); } @@ -333,5 +385,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; } diff --git a/src/provider/provider_tracking.c b/src/provider/provider_tracking.c index 62145d5d7..fd9634d87 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 9e868cf31..f791ed190 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 diff --git a/test/provider_fixed_memory.cpp b/test/provider_fixed_memory.cpp index 7f976a1f5..f1f913fe0 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); +}