Skip to content

Commit 08282c7

Browse files
committed
Implement umfPool[Set/Get]Tag
Implements #687
1 parent ee03b29 commit 08282c7

File tree

6 files changed

+157
-0
lines changed

6 files changed

+157
-0
lines changed

include/umf/memory_pool.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,22 @@ umf_memory_pool_handle_t umfPoolByPtr(const void *ptr);
170170
umf_result_t umfPoolGetMemoryProvider(umf_memory_pool_handle_t hPool,
171171
umf_memory_provider_handle_t *hProvider);
172172

173+
///
174+
/// @brief Set a custom tag on the memory pool that can be later retrieved using umfPoolGetTag.
175+
/// @param hPool specified memory pool
176+
/// @param tag tag to be set
177+
/// @param oldTag [out][optional] previous tag set on the memory pool
178+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
179+
umf_result_t umfPoolSetTag(umf_memory_pool_handle_t hPool, void *tag,
180+
void **oldTag);
181+
182+
///
183+
/// @brief Retrieve the tag associated with the memory pool or NULL if no tag is set.
184+
/// @param hPool specified memory pool
185+
/// @param tag [out] tag associated with the memory pool
186+
/// @return UMF_RESULT_SUCCESS on success.
187+
umf_result_t umfPoolGetTag(umf_memory_pool_handle_t hPool, void **tag);
188+
173189
#ifdef __cplusplus
174190
}
175191
#endif

src/libumf.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,12 @@ EXPORTS
104104
umfPoolFree
105105
umfPoolGetIPCHandleSize
106106
umfPoolGetLastAllocationError
107+
umfPoolGetTag
107108
umfPoolGetMemoryProvider
108109
umfPoolMalloc
109110
umfPoolMallocUsableSize
110111
umfPoolRealloc
112+
umfPoolSetTag
111113
umfProxyPoolOps
112114
umfPutIPCHandle
113115
umfScalablePoolOps

src/libumf.map

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,11 @@ UMF_1.0 {
9999
umfPoolGetIPCHandleSize;
100100
umfPoolGetLastAllocationError;
101101
umfPoolGetMemoryProvider;
102+
umfPoolGetTag;
102103
umfPoolMalloc;
103104
umfPoolMallocUsableSize;
104105
umfPoolRealloc;
106+
umfPoolSetTag;
105107
umfProxyPoolOps;
106108
umfPutIPCHandle;
107109
umfScalablePoolOps;

src/memory_pool.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ static umf_result_t umfPoolCreateInternal(const umf_memory_pool_ops_t *ops,
5555

5656
pool->flags = flags;
5757
pool->ops = *ops;
58+
pool->tag = NULL;
59+
60+
if (NULL == utils_mutex_init(&pool->lock)) {
61+
LOG_ERR("Failed to initialize mutex for pool");
62+
ret = UMF_RESULT_ERROR_UNKNOWN;
63+
goto err_lock_init;
64+
}
5865

5966
ret = ops->initialize(pool->provider, params, &pool->pool_priv);
6067
if (ret != UMF_RESULT_SUCCESS) {
@@ -66,6 +73,8 @@ static umf_result_t umfPoolCreateInternal(const umf_memory_pool_ops_t *ops,
6673
return UMF_RESULT_SUCCESS;
6774

6875
err_pool_init:
76+
utils_mutex_destroy_not_free(&pool->lock);
77+
err_lock_init:
6978
if (!(flags & UMF_POOL_CREATE_FLAG_DISABLE_TRACKING)) {
7079
umfMemoryProviderDestroy(pool->provider);
7180
}
@@ -90,6 +99,8 @@ void umfPoolDestroy(umf_memory_pool_handle_t hPool) {
9099
umfMemoryProviderDestroy(hUpstreamProvider);
91100
}
92101

102+
utils_mutex_destroy_not_free(&hPool->lock);
103+
93104
LOG_INFO("Memory pool destroyed: %p", (void *)hPool);
94105

95106
// TODO: this free keeps memory in base allocator, so it can lead to OOM in some scenarios (it should be optimized)
@@ -175,3 +186,24 @@ umf_result_t umfPoolGetLastAllocationError(umf_memory_pool_handle_t hPool) {
175186
UMF_CHECK((hPool != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT);
176187
return hPool->ops.get_last_allocation_error(hPool->pool_priv);
177188
}
189+
190+
umf_result_t umfPoolSetTag(umf_memory_pool_handle_t hPool, void *tag,
191+
void **oldTag) {
192+
UMF_CHECK((hPool != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT);
193+
utils_mutex_lock(&hPool->lock);
194+
if (oldTag) {
195+
*oldTag = hPool->tag;
196+
}
197+
hPool->tag = tag;
198+
utils_mutex_unlock(&hPool->lock);
199+
return UMF_RESULT_SUCCESS;
200+
}
201+
202+
umf_result_t umfPoolGetTag(umf_memory_pool_handle_t hPool, void **tag) {
203+
UMF_CHECK((hPool != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT);
204+
UMF_CHECK((tag != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT);
205+
utils_mutex_lock(&hPool->lock);
206+
*tag = hPool->tag;
207+
utils_mutex_unlock(&hPool->lock);
208+
return UMF_RESULT_SUCCESS;
209+
}

src/memory_pool_internal.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ extern "C" {
2222
#endif
2323

2424
#include "base_alloc.h"
25+
#include "utils_concurrency.h"
2526

2627
typedef struct umf_memory_pool_t {
2728
void *pool_priv;
@@ -30,6 +31,9 @@ typedef struct umf_memory_pool_t {
3031

3132
// Memory provider used by the pool.
3233
umf_memory_provider_handle_t provider;
34+
35+
utils_mutex_t lock;
36+
void *tag;
3337
} umf_memory_pool_t;
3438

3539
#ifdef __cplusplus

test/memoryPoolAPI.cpp

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,107 @@ TEST_F(test, BasicPoolByPtrTest) {
178178
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
179179
}
180180

181+
struct tagTest : umf_test::test {
182+
void SetUp() override {
183+
test::SetUp();
184+
provider = umf_test::wrapProviderUnique(nullProviderCreate());
185+
pool = umf_test::wrapPoolUnique(
186+
createPoolChecked(umfProxyPoolOps(), provider.get(), nullptr));
187+
}
188+
189+
umf::provider_unique_handle_t provider;
190+
umf::pool_unique_handle_t pool;
191+
};
192+
193+
TEST_F(tagTest, SetAndGet) {
194+
umf_result_t ret = umfPoolSetTag(pool.get(), (void *)0x99, nullptr);
195+
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
196+
197+
void *tag;
198+
ret = umfPoolGetTag(pool.get(), &tag);
199+
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
200+
ASSERT_EQ(tag, (void *)0x99);
201+
202+
void *oldTag;
203+
ret = umfPoolSetTag(pool.get(), (void *)0x100, &oldTag);
204+
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
205+
ASSERT_EQ(oldTag, (void *)0x99);
206+
}
207+
208+
TEST_F(tagTest, SetAndGetNull) {
209+
umf_result_t ret = umfPoolSetTag(pool.get(), nullptr, nullptr);
210+
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
211+
212+
void *tag;
213+
ret = umfPoolGetTag(pool.get(), &tag);
214+
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
215+
ASSERT_EQ(tag, nullptr);
216+
}
217+
218+
TEST_F(tagTest, NoSetAndGet) {
219+
void *tag;
220+
umf_result_t ret = umfPoolGetTag(pool.get(), &tag);
221+
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
222+
ASSERT_EQ(tag, nullptr);
223+
}
224+
225+
TEST_F(tagTest, SetAndGetMt) {
226+
static constexpr size_t NUM_THREADS = 8;
227+
static constexpr size_t NUM_OPS_PER_THREAD = 16;
228+
229+
std::vector<std::thread> threads;
230+
231+
auto encodeTag = [](size_t thread, size_t op) -> void * {
232+
return reinterpret_cast<void *>(thread * NUM_OPS_PER_THREAD + op);
233+
};
234+
235+
auto decodeTag = [](void *tag) -> std::pair<size_t, size_t> {
236+
auto op = reinterpret_cast<size_t>(tag) & (NUM_OPS_PER_THREAD - 1);
237+
auto thread = reinterpret_cast<size_t>(tag) / NUM_OPS_PER_THREAD;
238+
return {thread, op};
239+
};
240+
241+
for (size_t i = 0; i < NUM_THREADS; i++) {
242+
threads.emplace_back([this, i, encodeTag, decodeTag] {
243+
for (size_t j = 0; j < NUM_OPS_PER_THREAD; j++) {
244+
void *oldTag;
245+
umf_result_t ret =
246+
umfPoolSetTag(pool.get(), encodeTag(i, j), &oldTag);
247+
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
248+
249+
void *queriedTag;
250+
ret = umfPoolGetTag(pool.get(), &queriedTag);
251+
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
252+
253+
auto [t1, op1] = decodeTag(oldTag);
254+
auto [t2, op2] = decodeTag(queriedTag);
255+
// if the tag was set by the same thread, the op part should same or higher
256+
ASSERT_TRUE(t1 != t2 || op2 >= op1);
257+
}
258+
});
259+
}
260+
261+
for (auto &thread : threads) {
262+
thread.join();
263+
}
264+
265+
void *tag;
266+
auto ret = umfPoolGetTag(pool.get(), &tag);
267+
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
268+
269+
auto [t, op] = decodeTag(tag);
270+
ASSERT_TRUE(t < NUM_THREADS);
271+
ASSERT_TRUE(op == NUM_OPS_PER_THREAD - 1);
272+
}
273+
274+
TEST_F(tagTest, SetAndGetInvalidPtr) {
275+
umf_result_t ret = umfPoolSetTag(pool.get(), nullptr, nullptr);
276+
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
277+
278+
ret = umfPoolGetTag(pool.get(), nullptr);
279+
ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT);
280+
}
281+
181282
INSTANTIATE_TEST_SUITE_P(
182283
mallocPoolTest, umfPoolTest,
183284
::testing::Values(poolCreateExtParams{&MALLOC_POOL_OPS, nullptr,

0 commit comments

Comments
 (0)