Skip to content

Commit 1aec34b

Browse files
committed
Split memory provider ops to mandatory and optional fields
1 parent 8b4b91e commit 1aec34b

File tree

10 files changed

+333
-86
lines changed

10 files changed

+333
-86
lines changed

include/umf/memory_provider_ops.h

Lines changed: 59 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,64 @@
1616
extern "C" {
1717
#endif
1818

19+
///
20+
/// @brief This structure comprises optional function pointers used
21+
/// by corresponding umfMemoryProvider* calls. A memory provider implementation
22+
/// can keep them NULL.
23+
///
24+
typedef struct umf_memory_provider_ext_ops_t {
25+
///
26+
/// @brief Discard physical pages within the virtual memory mapping associated at the given addr
27+
/// and \p size. This call is asynchronous and may delay purging the pages indefinitely.
28+
/// @param provider pointer to the memory provider
29+
/// @param ptr beginning of the virtual memory range
30+
/// @param size size of the virtual memory range
31+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
32+
/// UMF_RESULT_ERROR_INVALID_ALIGNMENT if ptr or size is not page-aligned.
33+
/// UMF_RESULT_ERROR_NOT_SUPPORTED if operation is not supported by this provider.
34+
///
35+
umf_result_t (*purge_lazy)(void *provider, void *ptr, size_t size);
36+
37+
///
38+
/// @brief Discard physical pages within the virtual memory mapping associated at the given addr and \p size.
39+
/// This call is synchronous and if it succeeds, pages are guaranteed to be zero-filled on the next access.
40+
/// @param provider pointer to the memory provider
41+
/// @param ptr beginning of the virtual memory range
42+
/// @param size size of the virtual memory range
43+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure
44+
/// UMF_RESULT_ERROR_INVALID_ALIGNMENT if ptr or size is not page-aligned.
45+
/// UMF_RESULT_ERROR_NOT_SUPPORTED if operation is not supported by this provider.
46+
///
47+
umf_result_t (*purge_force)(void *provider, void *ptr, size_t size);
48+
49+
///
50+
/// @brief Merges two coarse grain allocations into a single allocation that
51+
/// can be managed (freed) as a whole.
52+
/// @param hProvider handle to the memory provider
53+
/// @param lowPtr pointer to the first allocation
54+
/// @param highPtr pointer to the second allocation (should be > lowPtr)
55+
/// @param totalSize size of a new merged allocation. Should be equal
56+
/// to the sum of sizes of allocations beginning at lowPtr and highPtr
57+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure
58+
///
59+
umf_result_t (*allocation_merge)(void *hProvider, void *lowPtr,
60+
void *highPtr, size_t totalSize);
61+
62+
///
63+
/// @brief Splits a coarse grain allocation into 2 adjacent allocations that
64+
/// can be managed (freed) separately.
65+
/// @param hProvider handle to the memory provider
66+
/// @param ptr pointer to the beginning of the allocation
67+
/// @param totalSize total size of the allocation to be split
68+
/// @param firstSize size of the first new allocation, second allocation
69+
// has a size equal to totalSize - firstSize
70+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure
71+
///
72+
umf_result_t (*allocation_split)(void *hProvider, void *ptr,
73+
size_t totalSize, size_t firstSize);
74+
75+
} umf_memory_provider_ext_ops_t;
76+
1977
///
2078
/// @brief This structure comprises function pointers used by corresponding
2179
/// umfMemoryProvider* calls. Each memory provider implementation should
@@ -109,62 +167,14 @@ typedef struct umf_memory_provider_ops_t {
109167
umf_result_t (*get_min_page_size)(void *provider, void *ptr,
110168
size_t *pageSize);
111169

112-
///
113-
/// @brief Discard physical pages within the virtual memory mapping associated at the given addr
114-
/// and \p size. This call is asynchronous and may delay purging the pages indefinitely.
115-
/// @param provider pointer to the memory provider
116-
/// @param ptr beginning of the virtual memory range
117-
/// @param size size of the virtual memory range
118-
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
119-
/// UMF_RESULT_ERROR_INVALID_ALIGNMENT if ptr or size is not page-aligned.
120-
/// UMF_RESULT_ERROR_NOT_SUPPORTED if operation is not supported by this provider.
121-
///
122-
umf_result_t (*purge_lazy)(void *provider, void *ptr, size_t size);
123-
124-
///
125-
/// @brief Discard physical pages within the virtual memory mapping associated at the given addr and \p size.
126-
/// This call is synchronous and if it succeeds, pages are guaranteed to be zero-filled on the next access.
127-
/// @param provider pointer to the memory provider
128-
/// @param ptr beginning of the virtual memory range
129-
/// @param size size of the virtual memory range
130-
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure
131-
/// UMF_RESULT_ERROR_INVALID_ALIGNMENT if ptr or size is not page-aligned.
132-
/// UMF_RESULT_ERROR_NOT_SUPPORTED if operation is not supported by this provider.
133-
///
134-
umf_result_t (*purge_force)(void *provider, void *ptr, size_t size);
135-
136170
///
137171
/// @brief Retrieve name of a given memory \p provider.
138172
/// @param provider pointer to the memory provider
139173
/// @return pointer to a string containing the name of the \p provider
140174
///
141175
const char *(*get_name)(void *provider);
142176

143-
///
144-
/// @brief Splits a coarse grain allocation into 2 adjacent allocations that
145-
/// can be managed (freed) separately.
146-
/// @param hProvider handle to the memory provider
147-
/// @param ptr pointer to the beginning of the allocation
148-
/// @param totalSize total size of the allocation to be split
149-
/// @param firstSize size of the first new allocation, second allocation
150-
// has a size equal to totalSize - firstSize
151-
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure
152-
///
153-
umf_result_t (*allocation_split)(void *hProvider, void *ptr,
154-
size_t totalSize, size_t firstSize);
155-
156-
///
157-
/// @brief Merges two coarse grain allocations into a single allocation that
158-
/// can be managed (freed) as a whole.
159-
/// @param hProvider handle to the memory provider
160-
/// @param lowPtr pointer to the first allocation
161-
/// @param highPtr pointer to the second allocation (should be > lowPtr)
162-
/// @param totalSize size of a new merged allocation. Should be equal
163-
/// to the sum of sizes of allocations beginning at lowPtr and highPtr
164-
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure
165-
///
166-
umf_result_t (*allocation_merge)(void *hProvider, void *lowPtr,
167-
void *highPtr, size_t totalSize);
177+
umf_memory_provider_ext_ops_t ext;
168178
} umf_memory_provider_ops_t;
169179

170180
#ifdef __cplusplus

src/cpp_helpers.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,11 @@ template <typename T> umf_memory_provider_ops_t providerOpsBase() {
8888
UMF_ASSIGN_OP_NORETURN(ops, T, get_last_native_error);
8989
UMF_ASSIGN_OP(ops, T, get_recommended_page_size, UMF_RESULT_ERROR_UNKNOWN);
9090
UMF_ASSIGN_OP(ops, T, get_min_page_size, UMF_RESULT_ERROR_UNKNOWN);
91-
UMF_ASSIGN_OP(ops, T, purge_lazy, UMF_RESULT_ERROR_UNKNOWN);
92-
UMF_ASSIGN_OP(ops, T, purge_force, UMF_RESULT_ERROR_UNKNOWN);
9391
UMF_ASSIGN_OP(ops, T, get_name, "");
92+
UMF_ASSIGN_OP(ops.ext, T, purge_lazy, UMF_RESULT_ERROR_UNKNOWN);
93+
UMF_ASSIGN_OP(ops.ext, T, purge_force, UMF_RESULT_ERROR_UNKNOWN);
94+
UMF_ASSIGN_OP(ops.ext, T, allocation_merge, UMF_RESULT_ERROR_UNKNOWN);
95+
UMF_ASSIGN_OP(ops.ext, T, allocation_split, UMF_RESULT_ERROR_UNKNOWN);
9496
return ops;
9597
}
9698
} // namespace detail

src/memory_provider.c

Lines changed: 72 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99

1010
#include <assert.h>
11+
#include <stdbool.h>
1112
#include <stdio.h>
1213
#include <stdlib.h>
1314

@@ -24,11 +25,70 @@ typedef struct umf_memory_provider_t {
2425
void *provider_priv;
2526
} umf_memory_provider_t;
2627

28+
static umf_result_t umfDefaultPurgeLazy(void *provider, void *ptr,
29+
size_t size) {
30+
(void)provider;
31+
(void)ptr;
32+
(void)size;
33+
return UMF_RESULT_ERROR_NOT_SUPPORTED;
34+
}
35+
36+
static umf_result_t umfDefaultPurgeForce(void *provider, void *ptr,
37+
size_t size) {
38+
(void)provider;
39+
(void)ptr;
40+
(void)size;
41+
return UMF_RESULT_ERROR_NOT_SUPPORTED;
42+
}
43+
44+
static umf_result_t umfDefaultAllocationSplit(void *provider, void *ptr,
45+
size_t totalSize,
46+
size_t firstSize) {
47+
(void)provider;
48+
(void)ptr;
49+
(void)totalSize;
50+
(void)firstSize;
51+
return UMF_RESULT_ERROR_NOT_SUPPORTED;
52+
}
53+
54+
static umf_result_t umfDefaultAllocationMerge(void *provider, void *lowPtr,
55+
void *highPtr, size_t totalSize) {
56+
(void)provider;
57+
(void)lowPtr;
58+
(void)highPtr;
59+
(void)totalSize;
60+
return UMF_RESULT_ERROR_NOT_SUPPORTED;
61+
}
62+
63+
void assignOpsExtDefaults(umf_memory_provider_ops_t *ops) {
64+
if (!ops->ext.purge_lazy) {
65+
ops->ext.purge_lazy = umfDefaultPurgeLazy;
66+
}
67+
if (!ops->ext.purge_force) {
68+
ops->ext.purge_force = umfDefaultPurgeForce;
69+
}
70+
if (!ops->ext.allocation_split) {
71+
ops->ext.allocation_split = umfDefaultAllocationSplit;
72+
}
73+
if (!ops->ext.allocation_merge) {
74+
ops->ext.allocation_merge = umfDefaultAllocationMerge;
75+
}
76+
}
77+
78+
static bool validateManadatoryOpsNotNull(const umf_memory_provider_ops_t *ops) {
79+
if (!ops->alloc || !ops->free || !ops->get_recommended_page_size ||
80+
!ops->get_min_page_size || !ops->initialize || !ops->finalize ||
81+
!ops->get_last_native_error || !ops->get_name) {
82+
return false;
83+
}
84+
return true;
85+
}
86+
2787
umf_result_t umfMemoryProviderCreate(const umf_memory_provider_ops_t *ops,
2888
void *params,
2989
umf_memory_provider_handle_t *hProvider) {
3090
libumfInit();
31-
if (!ops || !hProvider) {
91+
if (!ops || !hProvider || !validateManadatoryOpsNotNull(ops)) {
3292
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
3393
}
3494

@@ -42,6 +102,8 @@ umf_result_t umfMemoryProviderCreate(const umf_memory_provider_ops_t *ops,
42102

43103
provider->ops = *ops;
44104

105+
assignOpsExtDefaults(&(provider->ops));
106+
45107
void *provider_priv;
46108
umf_result_t ret = ops->initialize(params, &provider_priv);
47109
if (ret != UMF_RESULT_SUCCESS) {
@@ -119,11 +181,16 @@ umfMemoryProviderGetMinPageSize(umf_memory_provider_handle_t hProvider,
119181
return res;
120182
}
121183

184+
const char *umfMemoryProviderGetName(umf_memory_provider_handle_t hProvider) {
185+
UMF_CHECK((hProvider != NULL), NULL);
186+
return hProvider->ops.get_name(hProvider->provider_priv);
187+
}
188+
122189
umf_result_t umfMemoryProviderPurgeLazy(umf_memory_provider_handle_t hProvider,
123190
void *ptr, size_t size) {
124191
UMF_CHECK((hProvider != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT);
125192
umf_result_t res =
126-
hProvider->ops.purge_lazy(hProvider->provider_priv, ptr, size);
193+
hProvider->ops.ext.purge_lazy(hProvider->provider_priv, ptr, size);
127194
checkErrorAndSetLastProvider(res, hProvider);
128195
return res;
129196
}
@@ -132,16 +199,11 @@ umf_result_t umfMemoryProviderPurgeForce(umf_memory_provider_handle_t hProvider,
132199
void *ptr, size_t size) {
133200
UMF_CHECK((hProvider != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT);
134201
umf_result_t res =
135-
hProvider->ops.purge_force(hProvider->provider_priv, ptr, size);
202+
hProvider->ops.ext.purge_force(hProvider->provider_priv, ptr, size);
136203
checkErrorAndSetLastProvider(res, hProvider);
137204
return res;
138205
}
139206

140-
const char *umfMemoryProviderGetName(umf_memory_provider_handle_t hProvider) {
141-
UMF_CHECK((hProvider != NULL), NULL);
142-
return hProvider->ops.get_name(hProvider->provider_priv);
143-
}
144-
145207
umf_memory_provider_handle_t umfGetLastFailedMemoryProvider(void) {
146208
return *umfGetLastFailedMemoryProviderPtr();
147209
}
@@ -160,7 +222,7 @@ umfMemoryProviderAllocationSplit(umf_memory_provider_handle_t hProvider,
160222
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
161223
}
162224

163-
umf_result_t res = hProvider->ops.allocation_split(
225+
umf_result_t res = hProvider->ops.ext.allocation_split(
164226
hProvider->provider_priv, ptr, totalSize, firstSize);
165227
checkErrorAndSetLastProvider(res, hProvider);
166228
return res;
@@ -183,7 +245,7 @@ umfMemoryProviderAllocationMerge(umf_memory_provider_handle_t hProvider,
183245
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
184246
}
185247

186-
umf_result_t res = hProvider->ops.allocation_merge(
248+
umf_result_t res = hProvider->ops.ext.allocation_merge(
187249
hProvider->provider_priv, lowPtr, highPtr, totalSize);
188250
checkErrorAndSetLastProvider(res, hProvider);
189251
return res;

src/provider/provider_level_zero.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -263,11 +263,11 @@ static struct umf_memory_provider_ops_t UMF_LEVEL_ZERO_MEMORY_PROVIDER_OPS = {
263263
.get_last_native_error = ze_memory_provider_get_last_native_error,
264264
.get_recommended_page_size = ze_memory_provider_get_recommended_page_size,
265265
.get_min_page_size = ze_memory_provider_get_min_page_size,
266-
.purge_lazy = ze_memory_provider_purge_lazy,
267-
.purge_force = ze_memory_provider_purge_force,
268266
.get_name = ze_memory_provider_get_name,
269-
.allocation_split = ze_memory_provider_allocation_split,
270-
.allocation_merge = ze_memory_provider_allocation_merge,
267+
.ext.purge_lazy = ze_memory_provider_purge_lazy,
268+
.ext.purge_force = ze_memory_provider_purge_force,
269+
.ext.allocation_merge = ze_memory_provider_allocation_merge,
270+
.ext.allocation_split = ze_memory_provider_allocation_split,
271271
};
272272

273273
umf_memory_provider_ops_t *umfLevelZeroMemoryProviderOps(void) {

src/provider/provider_os_memory.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -648,11 +648,11 @@ static umf_memory_provider_ops_t UMF_OS_MEMORY_PROVIDER_OPS = {
648648
.get_last_native_error = os_get_last_native_error,
649649
.get_recommended_page_size = os_get_recommended_page_size,
650650
.get_min_page_size = os_get_min_page_size,
651-
.purge_lazy = os_purge_lazy,
652-
.purge_force = os_purge_force,
653651
.get_name = os_get_name,
654-
.allocation_split = os_allocation_split,
655-
.allocation_merge = os_allocation_merge};
652+
.ext.purge_lazy = os_purge_lazy,
653+
.ext.purge_force = os_purge_force,
654+
.ext.allocation_merge = os_allocation_merge,
655+
.ext.allocation_split = os_allocation_split};
656656

657657
umf_memory_provider_ops_t *umfOsMemoryProviderOps(void) {
658658
return &UMF_OS_MEMORY_PROVIDER_OPS;

src/provider/provider_tracking.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -438,11 +438,11 @@ umf_memory_provider_ops_t UMF_TRACKING_MEMORY_PROVIDER_OPS = {
438438
.get_last_native_error = trackingGetLastError,
439439
.get_min_page_size = trackingGetMinPageSize,
440440
.get_recommended_page_size = trackingGetRecommendedPageSize,
441-
.purge_force = trackingPurgeForce,
442-
.purge_lazy = trackingPurgeLazy,
443441
.get_name = trackingName,
444-
.allocation_split = trackingAllocationSplit,
445-
.allocation_merge = trackingAllocationMerge};
442+
.ext.purge_force = trackingPurgeForce,
443+
.ext.purge_lazy = trackingPurgeLazy,
444+
.ext.allocation_split = trackingAllocationSplit,
445+
.ext.allocation_merge = trackingAllocationMerge};
446446

447447
umf_result_t umfTrackingMemoryProviderCreate(
448448
umf_memory_provider_handle_t hUpstream, umf_memory_pool_handle_t hPool,

test/common/provider.hpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ typedef struct provider_base_t {
5252
[[maybe_unused]] size_t *pageSize) noexcept {
5353
return UMF_RESULT_ERROR_UNKNOWN;
5454
}
55+
const char *get_name() noexcept { return "base"; }
5556
umf_result_t purge_lazy([[maybe_unused]] void *ptr,
5657
[[maybe_unused]] size_t size) noexcept {
5758
return UMF_RESULT_ERROR_UNKNOWN;
@@ -60,7 +61,18 @@ typedef struct provider_base_t {
6061
[[maybe_unused]] size_t size) noexcept {
6162
return UMF_RESULT_ERROR_UNKNOWN;
6263
}
63-
const char *get_name() noexcept { return "base"; }
64+
65+
umf_result_t allocation_merge([[maybe_unused]] void *lowPtr,
66+
[[maybe_unused]] void *highPtr,
67+
[[maybe_unused]] size_t totalSize) {
68+
return UMF_RESULT_ERROR_UNKNOWN;
69+
}
70+
71+
umf_result_t allocation_split([[maybe_unused]] void *ptr,
72+
[[maybe_unused]] size_t totalSize,
73+
[[maybe_unused]] size_t firstSize) {
74+
return UMF_RESULT_ERROR_UNKNOWN;
75+
}
6476
} provider_base_t;
6577

6678
umf_memory_provider_ops_t BASE_PROVIDER_OPS =

0 commit comments

Comments
 (0)