Skip to content

Commit 566169d

Browse files
authored
Merge pull request #698 from igchor/umf_helpers_provider
[umf] add extra poolMakeUnique overload to helpers
2 parents 0d992a0 + 6653648 commit 566169d

File tree

3 files changed

+98
-89
lines changed

3 files changed

+98
-89
lines changed

source/common/umf_helpers.hpp

Lines changed: 80 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <umf/memory_provider.h>
1717
#include <umf/memory_provider_ops.h>
1818

19+
#include <array>
1920
#include <functional>
2021
#include <memory>
2122
#include <stdexcept>
@@ -48,6 +49,55 @@ using provider_unique_handle_t =
4849
} \
4950
}
5051

52+
namespace detail {
53+
template <typename T, typename ArgsTuple>
54+
umf_result_t initialize(T *obj, ArgsTuple &&args) {
55+
try {
56+
auto ret = std::apply(&T::initialize,
57+
std::tuple_cat(std::make_tuple(obj),
58+
std::forward<ArgsTuple>(args)));
59+
if (ret != UMF_RESULT_SUCCESS) {
60+
delete obj;
61+
}
62+
return ret;
63+
} catch (...) {
64+
delete obj;
65+
return UMF_RESULT_ERROR_UNKNOWN;
66+
}
67+
}
68+
69+
template <typename T, typename ArgsTuple>
70+
umf_memory_pool_ops_t poolMakeUniqueOps() {
71+
umf_memory_pool_ops_t ops;
72+
73+
ops.version = UMF_VERSION_CURRENT;
74+
ops.initialize = [](umf_memory_provider_handle_t *providers,
75+
size_t numProviders, void *params, void **obj) {
76+
try {
77+
*obj = new T;
78+
} catch (...) {
79+
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
80+
}
81+
82+
return detail::initialize<T>(
83+
reinterpret_cast<T *>(*obj),
84+
std::tuple_cat(std::make_tuple(providers, numProviders),
85+
*reinterpret_cast<ArgsTuple *>(params)));
86+
};
87+
ops.finalize = [](void *obj) { delete reinterpret_cast<T *>(obj); };
88+
89+
UMF_ASSIGN_OP(ops, T, malloc, ((void *)nullptr));
90+
UMF_ASSIGN_OP(ops, T, calloc, ((void *)nullptr));
91+
UMF_ASSIGN_OP(ops, T, aligned_malloc, ((void *)nullptr));
92+
UMF_ASSIGN_OP(ops, T, realloc, ((void *)nullptr));
93+
UMF_ASSIGN_OP(ops, T, malloc_usable_size, ((size_t)0));
94+
UMF_ASSIGN_OP_NORETURN(ops, T, free);
95+
UMF_ASSIGN_OP(ops, T, get_last_allocation_error, UMF_RESULT_ERROR_UNKNOWN);
96+
97+
return ops;
98+
}
99+
} // namespace detail
100+
51101
/// @brief creates UMF memory provider based on given T type.
52102
/// T should implement all functions defined by
53103
/// umf_memory_provider_ops_t, except for finalize (it is
@@ -60,28 +110,15 @@ auto memoryProviderMakeUnique(Args &&...args) {
60110

61111
ops.version = UMF_VERSION_CURRENT;
62112
ops.initialize = [](void *params, void **obj) {
63-
auto *tuple = reinterpret_cast<decltype(argsTuple) *>(params);
64-
T *provider;
65113
try {
66-
provider = new T;
114+
*obj = new T;
67115
} catch (...) {
68116
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
69117
}
70118

71-
*obj = provider;
72-
73-
try {
74-
auto ret =
75-
std::apply(&T::initialize,
76-
std::tuple_cat(std::make_tuple(provider), *tuple));
77-
if (ret != UMF_RESULT_SUCCESS) {
78-
delete provider;
79-
}
80-
return ret;
81-
} catch (...) {
82-
delete provider;
83-
return UMF_RESULT_ERROR_UNKNOWN;
84-
}
119+
return detail::initialize<T>(
120+
reinterpret_cast<T *>(*obj),
121+
*reinterpret_cast<decltype(argsTuple) *>(params));
85122
};
86123
ops.finalize = [](void *obj) { delete reinterpret_cast<T *>(obj); };
87124

@@ -108,51 +145,42 @@ auto memoryProviderMakeUnique(Args &&...args) {
108145
template <typename T, typename... Args>
109146
auto poolMakeUnique(umf_memory_provider_handle_t *providers,
110147
size_t numProviders, Args &&...args) {
111-
umf_memory_pool_ops_t ops;
112148
auto argsTuple = std::make_tuple(std::forward<Args>(args)...);
149+
auto ops = detail::poolMakeUniqueOps<T, decltype(argsTuple)>();
113150

114-
ops.version = UMF_VERSION_CURRENT;
115-
ops.initialize = [](umf_memory_provider_handle_t *providers,
116-
size_t numProviders, void *params, void **obj) {
117-
auto *tuple = reinterpret_cast<decltype(argsTuple) *>(params);
118-
T *pool;
151+
umf_memory_pool_handle_t hPool = nullptr;
152+
auto ret = umfPoolCreate(&ops, providers, numProviders, &argsTuple, &hPool);
153+
return std::pair<umf_result_t, pool_unique_handle_t>{
154+
ret, pool_unique_handle_t(hPool, &umfPoolDestroy)};
155+
}
119156

120-
try {
121-
pool = new T;
122-
} catch (...) {
123-
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
124-
}
157+
/// @brief creates UMF memory pool based on given T type.
158+
/// This overload takes ownership of memory providers and destroys
159+
/// them after memory pool is destroyed.
160+
template <typename T, size_t N, typename... Args>
161+
auto poolMakeUnique(std::array<provider_unique_handle_t, N> providers,
162+
Args &&...args) {
163+
auto argsTuple = std::make_tuple(std::forward<Args>(args)...);
164+
auto ops = detail::poolMakeUniqueOps<T, decltype(argsTuple)>();
125165

126-
*obj = pool;
166+
std::array<umf_memory_provider_handle_t, N> provider_handles;
167+
for (size_t i = 0; i < N; i++) {
168+
provider_handles[i] = providers[i].release();
169+
}
127170

128-
try {
129-
auto ret = std::apply(
130-
&T::initialize,
131-
std::tuple_cat(std::make_tuple(pool, providers, numProviders),
132-
*tuple));
133-
if (ret != UMF_RESULT_SUCCESS) {
134-
delete pool;
135-
}
136-
return ret;
137-
} catch (...) {
138-
delete pool;
139-
return UMF_RESULT_ERROR_UNKNOWN;
171+
// capture providers and destroy them after the pool is destroyed
172+
auto poolDestructor = [provider_handles](umf_memory_pool_handle_t hPool) {
173+
umfPoolDestroy(hPool);
174+
for (auto &provider : provider_handles) {
175+
umfMemoryProviderDestroy(provider);
140176
}
141177
};
142-
ops.finalize = [](void *obj) { delete reinterpret_cast<T *>(obj); };
143-
144-
UMF_ASSIGN_OP(ops, T, malloc, ((void *)nullptr));
145-
UMF_ASSIGN_OP(ops, T, calloc, ((void *)nullptr));
146-
UMF_ASSIGN_OP(ops, T, aligned_malloc, ((void *)nullptr));
147-
UMF_ASSIGN_OP(ops, T, realloc, ((void *)nullptr));
148-
UMF_ASSIGN_OP(ops, T, malloc_usable_size, ((size_t)0));
149-
UMF_ASSIGN_OP_NORETURN(ops, T, free);
150-
UMF_ASSIGN_OP(ops, T, get_last_allocation_error, UMF_RESULT_ERROR_UNKNOWN);
151178

152179
umf_memory_pool_handle_t hPool = nullptr;
153-
auto ret = umfPoolCreate(&ops, providers, numProviders, &argsTuple, &hPool);
180+
auto ret = umfPoolCreate(&ops, provider_handles.data(),
181+
provider_handles.size(), &argsTuple, &hPool);
154182
return std::pair<umf_result_t, pool_unique_handle_t>{
155-
ret, pool_unique_handle_t(hPool, &umfPoolDestroy)};
183+
ret, pool_unique_handle_t(hPool, std::move(poolDestructor))};
156184
}
157185

158186
template <typename Type> umf_result_t &getPoolLastStatusRef() {

test/unified_malloc_framework/memoryPoolAPI.cpp

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -133,41 +133,27 @@ TEST_F(test, retrieveMemoryProviders) {
133133
ASSERT_EQ(retProviders, providers);
134134
}
135135

136-
template <typename Pool>
137-
static auto
138-
makePool(std::function<umf::provider_unique_handle_t()> makeProvider) {
139-
auto providerUnique = makeProvider();
140-
umf_memory_provider_handle_t provider = providerUnique.get();
141-
auto pool = umf::poolMakeUnique<Pool>(&provider, 1).second;
142-
auto dtor = [provider =
143-
providerUnique.release()](umf_memory_pool_handle_t hPool) {
144-
umfPoolDestroy(hPool);
145-
umfMemoryProviderDestroy(provider);
146-
};
147-
return umf::pool_unique_handle_t(pool.release(), std::move(dtor));
148-
}
149-
150-
INSTANTIATE_TEST_SUITE_P(mallocPoolTest, umfPoolTest, ::testing::Values([] {
151-
return makePool<umf_test::malloc_pool>([] {
152-
return umf_test::wrapProviderUnique(
153-
nullProviderCreate());
154-
});
155-
}));
136+
INSTANTIATE_TEST_SUITE_P(
137+
mallocPoolTest, umfPoolTest, ::testing::Values([] {
138+
return umf::poolMakeUnique<umf_test::malloc_pool, 1>(
139+
{umf_test::wrapProviderUnique(nullProviderCreate())})
140+
.second;
141+
}));
156142

157143
INSTANTIATE_TEST_SUITE_P(
158144
mallocProviderPoolTest, umfPoolTest, ::testing::Values([] {
159-
return makePool<umf_test::proxy_pool>([] {
160-
return umf::memoryProviderMakeUnique<umf_test::provider_malloc>()
161-
.second;
162-
});
145+
return umf::poolMakeUnique<umf_test::proxy_pool, 1>(
146+
{umf::memoryProviderMakeUnique<umf_test::provider_malloc>()
147+
.second})
148+
.second;
163149
}));
164150

165151
INSTANTIATE_TEST_SUITE_P(
166152
mallocMultiPoolTest, umfMultiPoolTest, ::testing::Values([] {
167-
return makePool<umf_test::proxy_pool>([] {
168-
return umf::memoryProviderMakeUnique<umf_test::provider_malloc>()
169-
.second;
170-
});
153+
return umf::poolMakeUnique<umf_test::proxy_pool, 1>(
154+
{umf::memoryProviderMakeUnique<umf_test::provider_malloc>()
155+
.second})
156+
.second;
171157
}));
172158

173159
////////////////// Negative test cases /////////////////

test/unified_malloc_framework/umf_pools/disjoint_pool.cpp

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,13 @@ static usm::DisjointPool::Config poolConfig() {
2424
}
2525

2626
static auto makePool() {
27-
auto [ret, providerUnique] =
27+
auto [ret, provider] =
2828
umf::memoryProviderMakeUnique<umf_test::provider_malloc>();
2929
EXPECT_EQ(ret, UMF_RESULT_SUCCESS);
30-
auto provider = providerUnique.release();
31-
auto [retp, pool] =
32-
umf::poolMakeUnique<usm::DisjointPool>(&provider, 1, poolConfig());
30+
auto [retp, pool] = umf::poolMakeUnique<usm::DisjointPool, 1>(
31+
{std::move(provider)}, poolConfig());
3332
EXPECT_EQ(retp, UMF_RESULT_SUCCESS);
34-
auto dtor = [provider = provider](umf_memory_pool_handle_t hPool) {
35-
umfPoolDestroy(hPool);
36-
umfMemoryProviderDestroy(provider);
37-
};
38-
return umf::pool_unique_handle_t(pool.release(), std::move(dtor));
33+
return std::move(pool);
3934
}
4035

4136
INSTANTIATE_TEST_SUITE_P(disjointPoolTests, umfPoolTest,

0 commit comments

Comments
 (0)