Skip to content

Commit

Permalink
Merge pull request #759 from ldorau/Check_if_the_provider_supports_th…
Browse files Browse the repository at this point in the history
…e_free_operation

Clear tracker for the current pool on destroy
  • Loading branch information
ldorau authored Oct 2, 2024
2 parents fa0e22d + 2766a21 commit 3e4f65f
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 34 deletions.
8 changes: 6 additions & 2 deletions src/memory_pool.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,12 @@ static umf_result_t umfPoolCreateInternal(const umf_memory_pool_ops_t *ops,
assert(ops->version == UMF_VERSION_CURRENT);

if (!(flags & UMF_POOL_CREATE_FLAG_DISABLE_TRACKING)) {
// wrap provider with memory tracking provider
ret = umfTrackingMemoryProviderCreate(provider, pool, &pool->provider);
// Wrap provider with memory tracking provider.
// Check if the provider supports the free() operation.
bool upstreamDoesNotFree = (umfMemoryProviderFree(provider, NULL, 0) ==
UMF_RESULT_ERROR_NOT_SUPPORTED);
ret = umfTrackingMemoryProviderCreate(provider, pool, &pool->provider,
upstreamDoesNotFree);
if (ret != UMF_RESULT_SUCCESS) {
goto err_provider_create;
}
Expand Down
76 changes: 48 additions & 28 deletions src/provider/provider_tracking.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ typedef struct umf_tracking_memory_provider_t {
umf_memory_tracker_handle_t hTracker;
umf_memory_pool_handle_t pool;
critnib *ipcCache;

// the upstream provider does not support the free() operation
bool upstreamDoesNotFree;
} umf_tracking_memory_provider_t;

typedef struct umf_tracking_memory_provider_t umf_tracking_memory_provider_t;
Expand Down Expand Up @@ -392,9 +395,11 @@ static umf_result_t trackingInitialize(void *params, void **ret) {
return UMF_RESULT_SUCCESS;
}

#ifndef NDEBUG
static void check_if_tracker_is_empty(umf_memory_tracker_handle_t hTracker,
umf_memory_pool_handle_t pool) {
// TODO clearing the tracker is a temporary solution and should be removed.
// The tracker should be cleared using the provider's free() operation.
static void clear_tracker_for_the_pool(umf_memory_tracker_handle_t hTracker,
umf_memory_pool_handle_t pool,
bool upstreamDoesNotFree) {
uintptr_t rkey;
void *rvalue;
size_t n_items = 0;
Expand All @@ -403,39 +408,55 @@ static void check_if_tracker_is_empty(umf_memory_tracker_handle_t hTracker,
while (1 == critnib_find((critnib *)hTracker->map, last_key, FIND_G, &rkey,
&rvalue)) {
tracker_value_t *value = (tracker_value_t *)rvalue;
if (value->pool == pool || pool == NULL) {
n_items++;
if (value->pool != pool && pool != NULL) {
last_key = rkey;
continue;
}

n_items++;

void *removed_value = critnib_remove(hTracker->map, rkey);
assert(removed_value == rvalue);
umf_ba_free(hTracker->tracker_allocator, removed_value);

last_key = rkey;
}

if (n_items) {
// Do not assert if we are running in the proxy library,
// because it may need those resources till
// the very end of exiting the application.
if (!utils_is_running_in_proxy_lib()) {
if (pool) {
LOG_ERR("tracking provider of pool %p is not empty! "
"(%zu items left)",
(void *)pool, n_items);
} else {
LOG_ERR("tracking provider is not empty! (%zu items "
"left)",
n_items);
}
#ifndef NDEBUG
// print error messages only if provider supports the free() operation
if (n_items && !upstreamDoesNotFree) {
if (pool) {
LOG_ERR(
"tracking provider of pool %p is not empty! (%zu items left)",
(void *)pool, n_items);
} else {
LOG_ERR("tracking provider is not empty! (%zu items left)",
n_items);
}
}
#else /* DEBUG */
(void)upstreamDoesNotFree; // unused in DEBUG build
(void)n_items; // unused in DEBUG build
#endif /* DEBUG */
}

static void clear_tracker(umf_memory_tracker_handle_t hTracker) {
clear_tracker_for_the_pool(hTracker, NULL, false);
}
#endif /* NDEBUG */

static void trackingFinalize(void *provider) {
umf_tracking_memory_provider_t *p =
(umf_tracking_memory_provider_t *)provider;

critnib_delete(p->ipcCache);
#ifndef NDEBUG
check_if_tracker_is_empty(p->hTracker, p->pool);
#endif /* NDEBUG */

// Do not clear the tracker if we are running in the proxy library,
// because it may need those resources till
// the very end of exiting the application.
if (!utils_is_running_in_proxy_lib()) {
clear_tracker_for_the_pool(p->hTracker, p->pool,
p->upstreamDoesNotFree);
}

umf_ba_global_free(provider);
}
Expand Down Expand Up @@ -661,10 +682,11 @@ umf_memory_provider_ops_t UMF_TRACKING_MEMORY_PROVIDER_OPS = {

umf_result_t umfTrackingMemoryProviderCreate(
umf_memory_provider_handle_t hUpstream, umf_memory_pool_handle_t hPool,
umf_memory_provider_handle_t *hTrackingProvider) {
umf_memory_provider_handle_t *hTrackingProvider, bool upstreamDoesNotFree) {

umf_tracking_memory_provider_t params;
params.hUpstream = hUpstream;
params.upstreamDoesNotFree = upstreamDoesNotFree;
params.hTracker = TRACKER;
if (!params.hTracker) {
LOG_ERR("failed, TRACKER is NULL");
Expand Down Expand Up @@ -739,16 +761,14 @@ void umfMemoryTrackerDestroy(umf_memory_tracker_handle_t handle) {
return;
}

// Do not destroy if we are running in the proxy library,
// Do not destroy the tracket if we are running in the proxy library,
// because it may need those resources till
// the very end of exiting the application.
if (utils_is_running_in_proxy_lib()) {
return;
}

#ifndef NDEBUG
check_if_tracker_is_empty(handle, NULL);
#endif /* NDEBUG */
clear_tracker(handle);

// We have to zero all inner pointers,
// because the tracker handle can be copied
Expand Down
3 changes: 2 additions & 1 deletion src/provider/provider_tracking.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#define UMF_MEMORY_TRACKER_INTERNAL_H 1

#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>

#include <umf/base.h>
Expand Down Expand Up @@ -53,7 +54,7 @@ umf_result_t umfMemoryTrackerGetAllocInfo(const void *ptr,
// forwards all requests to hUpstream memory Provider. hUpstream lifetime should be managed by the user of this function.
umf_result_t umfTrackingMemoryProviderCreate(
umf_memory_provider_handle_t hUpstream, umf_memory_pool_handle_t hPool,
umf_memory_provider_handle_t *hTrackingProvider);
umf_memory_provider_handle_t *hTrackingProvider, bool upstreamDoesNotFree);

void umfTrackingMemoryProviderGetUpstreamProvider(
umf_memory_provider_handle_t hTrackingProvider,
Expand Down
6 changes: 4 additions & 2 deletions test/memoryPoolAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ TEST_P(umfPoolWithCreateFlagsTest, memoryPoolWithCustomProvider) {
}

TEST_F(test, retrieveMemoryProvider) {
umf_memory_provider_handle_t provider = (umf_memory_provider_handle_t)0x1;
auto nullProvider = umf_test::wrapProviderUnique(nullProviderCreate());
umf_memory_provider_handle_t provider = nullProvider.get();

auto pool =
wrapPoolUnique(createPoolChecked(umfProxyPoolOps(), provider, nullptr));
Expand Down Expand Up @@ -258,7 +259,8 @@ TEST_P(poolInitializeTest, errorPropagation) {
}

TEST_F(test, retrieveMemoryProvidersError) {
umf_memory_provider_handle_t provider = (umf_memory_provider_handle_t)0x1;
auto nullProvider = umf_test::wrapProviderUnique(nullProviderCreate());
umf_memory_provider_handle_t provider = nullProvider.get();

auto pool =
wrapPoolUnique(createPoolChecked(umfProxyPoolOps(), provider, nullptr));
Expand Down
5 changes: 4 additions & 1 deletion test/pools/disjoint_pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,10 @@ TEST_F(test, sharedLimits) {
}
umf_result_t free(void *ptr, [[maybe_unused]] size_t size) noexcept {
::free(ptr);
numFrees++;
// umfMemoryProviderFree(provider, NULL, 0) is called inside umfPoolCreateInternal()
if (ptr != NULL && size != 0) {

Check warning on line 86 in test/pools/disjoint_pool.cpp

View workflow job for this annotation

GitHub Actions / Sanitizers / cl and clang-cl on Windows (cl, cl, ON)

Using uninitialized memory 'ptr'.: Lines: 84, 86 [D:\a\unified-memory-framework\unified-memory-framework\build\test\umf_test-disjointPool.vcxproj]

Check warning on line 86 in test/pools/disjoint_pool.cpp

View workflow job for this annotation

GitHub Actions / Sanitizers / cl and clang-cl on Windows (clang-cl, clang-cl, ON)

Using uninitialized memory 'ptr'.: Lines: 84, 86 [D:\a\unified-memory-framework\unified-memory-framework\build\test\umf_test-disjointPool.vcxproj]

Check warning on line 86 in test/pools/disjoint_pool.cpp

View workflow job for this annotation

GitHub Actions / Basic builds / Windows (windows-2019, Debug, cl, cl, ON, ON, ON)

Using uninitialized memory 'ptr'.: Lines: 84, 86 [D:\a\unified-memory-framework\unified-memory-framework\build\test\umf_test-disjointPool.vcxproj]

Check warning on line 86 in test/pools/disjoint_pool.cpp

View workflow job for this annotation

GitHub Actions / Basic builds / Windows (windows-2019, Debug, cl, cl, OFF, ON, ON)

Using uninitialized memory 'ptr'.: Lines: 84, 86 [D:\a\unified-memory-framework\unified-memory-framework\build\test\umf_test-disjointPool.vcxproj]

Check warning on line 86 in test/pools/disjoint_pool.cpp

View workflow job for this annotation

GitHub Actions / Basic builds / Windows (windows-2019, Release, cl, cl, ON, ON, ON)

Using uninitialized memory 'ptr'.: Lines: 84, 86 [D:\a\unified-memory-framework\unified-memory-framework\build\test\umf_test-disjointPool.vcxproj]

Check warning on line 86 in test/pools/disjoint_pool.cpp

View workflow job for this annotation

GitHub Actions / Basic builds / Windows (windows-2019, Release, cl, cl, OFF, ON, ON)

Using uninitialized memory 'ptr'.: Lines: 84, 86 [D:\a\unified-memory-framework\unified-memory-framework\build\test\umf_test-disjointPool.vcxproj]

Check warning on line 86 in test/pools/disjoint_pool.cpp

View workflow job for this annotation

GitHub Actions / Basic builds / Windows (windows-2022, Debug, cl, cl, ON, ON, ON)

Using uninitialized memory 'ptr'.: Lines: 84, 86 [D:\a\unified-memory-framework\unified-memory-framework\build\test\umf_test-disjointPool.vcxproj]

Check warning on line 86 in test/pools/disjoint_pool.cpp

View workflow job for this annotation

GitHub Actions / Basic builds / Windows (windows-2022, Debug, cl, cl, OFF, ON, ON)

Using uninitialized memory 'ptr'.: Lines: 84, 86 [D:\a\unified-memory-framework\unified-memory-framework\build\test\umf_test-disjointPool.vcxproj]

Check warning on line 86 in test/pools/disjoint_pool.cpp

View workflow job for this annotation

GitHub Actions / Basic builds / Windows (windows-2022, Release, cl, cl, ON, ON, ON)

Using uninitialized memory 'ptr'.: Lines: 84, 86 [D:\a\unified-memory-framework\unified-memory-framework\build\test\umf_test-disjointPool.vcxproj]

Check warning on line 86 in test/pools/disjoint_pool.cpp

View workflow job for this annotation

GitHub Actions / Basic builds / Windows (windows-2022, Release, cl, cl, OFF, ON, ON)

Using uninitialized memory 'ptr'.: Lines: 84, 86 [D:\a\unified-memory-framework\unified-memory-framework\build\test\umf_test-disjointPool.vcxproj]

Check warning on line 86 in test/pools/disjoint_pool.cpp

View workflow job for this annotation

GitHub Actions / Basic builds / Windows (windows-2022, Release, cl, cl, ON, OFF, OFF)

Using uninitialized memory 'ptr'.: Lines: 84, 86 [D:\a\unified-memory-framework\unified-memory-framework\build\test\umf_test-disjointPool.vcxproj]
numFrees++;
}
return UMF_RESULT_SUCCESS;
}
};
Expand Down

0 comments on commit 3e4f65f

Please sign in to comment.