Skip to content

Commit be1cda1

Browse files
committed
Extend UMF to support IPC handles
1 parent be3cf23 commit be1cda1

File tree

9 files changed

+520
-3
lines changed

9 files changed

+520
-3
lines changed

include/umf/ipc.h

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
*
3+
* Copyright (C) 2023 Intel Corporation
4+
*
5+
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
6+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
*
8+
*/
9+
10+
#ifndef UMF_IPC_H
11+
#define UMF_IPC_H 1
12+
13+
#include <umf/base.h>
14+
#include <umf/memory_pool.h>
15+
16+
#ifdef __cplusplus
17+
extern "C" {
18+
#endif
19+
20+
typedef struct umf_ipc_data_t *umf_ipc_handle_t;
21+
22+
///
23+
/// @brief Creates an IPC handle for the specified UMF allocation.
24+
/// @param ptr pointer to the allocated memory.
25+
/// @param ipcHandle [out] returned IPC handle.
26+
/// @param size [out] size of IPC handle in bytes.
27+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
28+
umf_result_t umfGetIPCHandle(const void *ptr, umf_ipc_handle_t *ipcHandle,
29+
size_t *size);
30+
31+
///
32+
/// @brief Release IPC handle retrieved by umfGetIPCHandle.
33+
/// @param ipcHandle IPC handle.
34+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
35+
umf_result_t umfPutIPCHandle(umf_ipc_handle_t ipcHandle);
36+
37+
///
38+
/// @brief Open IPC handle retrieved by umfGetIPCHandle.
39+
/// @param hPool [in] Pool handle where to open the the IPC handle.
40+
/// @param ipcHandle [in] IPC handle.
41+
/// @param ptr [out] pointer to the memory in the current process.
42+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
43+
umf_result_t umfOpenIPCHandle(umf_memory_pool_handle_t hPool,
44+
umf_ipc_handle_t ipcHandle, void **ptr);
45+
46+
///
47+
/// @brief Close IPC handle.
48+
/// @param ptr [in] pointer to the memory.
49+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
50+
umf_result_t umfCloseIPCHandle(void *ptr);
51+
52+
#ifdef __cplusplus
53+
}
54+
#endif
55+
56+
#endif /* UMF_IPC_H */

include/umf/memory_provider.h

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,64 @@ UMF_EXPORT umf_result_t umfMemoryProviderPurgeLazy(
136136
UMF_EXPORT umf_result_t umfMemoryProviderPurgeForce(
137137
umf_memory_provider_handle_t hProvider, void *ptr, size_t size);
138138

139+
///
140+
/// @brief Retrieve the size of opaque data structure required to store IPC data.
141+
/// \param hProvider [in] handle to the memory provider.
142+
/// \param size [out] pointer to the size.
143+
/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
144+
/// UMF_RESULT_ERROR_NOT_SUPPORTED if IPC functionality is not supported by this provider.
145+
umf_result_t
146+
umfMemoryProviderGetIPCHandleSize(umf_memory_provider_handle_t hProvider,
147+
size_t *size);
148+
149+
///
150+
/// @brief Retrieve an IPC memory handle for the specified allocation.
151+
/// \param hProvider [in] handle to the memory provider.
152+
/// \param ptr [in] beginning of the virtual memory range returned by
153+
/// umfMemoryProviderAlloc function.
154+
/// \param size [in] size of the memory address range.
155+
/// \param ipcData [out] pointer to the preallocated opaque data structure to store IPC handle.
156+
/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
157+
/// UMF_RESULT_ERROR_INVALID_ARGUMENT if ptr was not allocated by this provider.
158+
/// UMF_RESULT_ERROR_NOT_SUPPORTED if IPC functionality is not supported by this provider.
159+
umf_result_t
160+
umfMemoryProviderGetIPCHandle(umf_memory_provider_handle_t hProvider,
161+
const void *ptr, size_t size, void *ipcData);
162+
163+
///
164+
/// @brief Release IPC handle retrieved with get_ipc_handle function.
165+
/// @param hProvider [in] handle to the memory provider.
166+
/// @param ipcData [in] pointer to the IPC opaque data structure.
167+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
168+
/// UMF_RESULT_ERROR_INVALID_ARGUMENT if ipcData was not created by this provider.
169+
/// UMF_RESULT_ERROR_NOT_SUPPORTED if IPC functionality is not supported by this provider.
170+
umf_result_t
171+
umfMemoryProviderPutIPCHandle(umf_memory_provider_handle_t hProvider,
172+
void *ipcData);
173+
174+
///
175+
/// @brief Open IPC handle.
176+
/// @param hProvider [in] handle to the memory provider.
177+
/// @param ipcData [in] pointer to the IPC opaque data structure.
178+
/// @param ptr [out] pointer to the memory to be used in the current process.
179+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
180+
/// UMF_RESULT_ERROR_INVALID_ARGUMENT if ipcData cannot be handled by the provider.
181+
/// UMF_RESULT_ERROR_NOT_SUPPORTED if IPC functionality is not supported by this provider.
182+
umf_result_t
183+
umfMemoryProviderOpenIPCHandle(umf_memory_provider_handle_t hProvider,
184+
void *ipcData, void **ptr);
185+
186+
///
187+
/// @brief Close an IPC memory handle.
188+
/// @param hProvider [in] handle to the memory provider.
189+
/// @param ptr [in] pointer returned by umfMemoryProviderOpenIPCHandle function.
190+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
191+
/// UMF_RESULT_ERROR_INVALID_ARGUMENT if invalid \p hProvider or \p ptr are passed.
192+
/// UMF_RESULT_ERROR_NOT_SUPPORTED if IPC functionality is not supported by this provider.
193+
umf_result_t
194+
umfMemoryProviderCloseIPCHandle(umf_memory_provider_handle_t hProvider,
195+
void *ptr);
196+
139197
///
140198
/// @brief Retrieve name of a given memory \p hProvider.
141199
/// @param hProvider handle to the memory provider

include/umf/memory_provider_ops.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,54 @@ typedef struct umf_memory_provider_ops_t {
133133
///
134134
umf_result_t (*purge_force)(void *provider, void *ptr, size_t size);
135135

136+
///
137+
/// @brief Retrieve the size of opaque data structure required to store IPC data.
138+
/// @param provider pointer to the memory provider.
139+
/// @param size [out] pointer to the size.
140+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
141+
/// UMF_RESULT_ERROR_NOT_SUPPORTED if IPC functionality is not supported by this provider.
142+
umf_result_t (*get_ipc_handle_size)(void *provider, size_t *size);
143+
144+
///
145+
/// @brief Retrieve an IPC memory handle for the specified allocation.
146+
/// @param provider pointer to the memory provider.
147+
/// @param ptr beginning of the virtual memory range.
148+
/// @param size size of the memory address range.
149+
/// @param ipcData [out] pointer to the preallocated opaque data structure to store IPC handle.
150+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
151+
/// UMF_RESULT_ERROR_INVALID_ARGUMENT if ptr was not allocated by this provider.
152+
/// UMF_RESULT_ERROR_NOT_SUPPORTED if IPC functionality is not supported by this provider.
153+
umf_result_t (*get_ipc_handle)(void *provider, const void *ptr, size_t size,
154+
void *ipcData);
155+
156+
///
157+
/// @brief Release IPC handle retrieved with get_ipc_handle function.
158+
/// @param provider pointer to the memory provider.
159+
/// @param ipcData pointer to the IPC opaque data structure.
160+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
161+
/// UMF_RESULT_ERROR_INVALID_ARGUMENT if ipcData was not created by this provider.
162+
/// UMF_RESULT_ERROR_NOT_SUPPORTED if IPC functionality is not supported by this provider.
163+
umf_result_t (*put_ipc_handle)(void *provider, void *ipcData);
164+
165+
///
166+
/// @brief Open IPC handle.
167+
/// @param provider pointer to the memory provider.
168+
/// @param ipcData pointer to the IPC opaque data structure.
169+
/// @param ptr [out] pointer to the memory to be used in the current process.
170+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
171+
/// UMF_RESULT_ERROR_INVALID_ARGUMENT if ipcData cannot be handled by the provider.
172+
/// UMF_RESULT_ERROR_NOT_SUPPORTED if IPC functionality is not supported by this provider.
173+
umf_result_t (*open_ipc_handle)(void *provider, void *ipcData, void **ptr);
174+
175+
///
176+
/// @brief Closes an IPC memory handle.
177+
/// @param provider pointer to the memory provider.
178+
/// @param ptr pointer to the memory retrieved with open_ipc_handle function.
179+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
180+
/// UMF_RESULT_ERROR_INVALID_ARGUMENT if invalid \p ptr is passed.
181+
/// UMF_RESULT_ERROR_NOT_SUPPORTED if IPC functionality is not supported by this provider.
182+
umf_result_t (*close_ipc_handle)(void *provider, void *ptr);
183+
136184
///
137185
/// @brief Retrieve name of a given memory \p provider.
138186
/// @param provider pointer to the memory provider

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ set(UMF_LIBS umf_utils)
1111
set(UMF_SOURCES
1212
base_alloc/base_alloc.c
1313
base_alloc/base_alloc_linear.c
14+
ipc.c
1415
memory_pool.c
1516
memory_provider.c
1617
memory_provider_get_last_failed.c

src/ipc.c

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
*
3+
* Copyright (C) 2023 Intel Corporation
4+
*
5+
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
6+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
*
8+
*/
9+
10+
#include "umf/ipc.h"
11+
12+
#include "ipc_internal.h"
13+
#include "memory_pool_internal.h"
14+
#include "provider/provider_tracking.h"
15+
16+
#include <assert.h>
17+
#include <stdlib.h>
18+
19+
umf_result_t
20+
umfGetIPCHandle(const void *ptr, umf_ipc_handle_t *umfIPCHandle, size_t *size) {
21+
size_t ipcHandleSize = 0;
22+
umf_alloc_info_t allocInfo;
23+
umf_result_t ret = umfMemoryTrackerGetAllocInfo(ptr, &allocInfo);
24+
if (ret != UMF_RESULT_SUCCESS) {
25+
return ret;
26+
}
27+
28+
// We cannot use umfPoolGetMemoryProvider function because it returns
29+
// upstream provider but we need tracking one
30+
umf_memory_provider_handle_t provider = allocInfo.pool->provider;
31+
assert(provider);
32+
33+
size_t providerIPCHandleSize;
34+
ret = umfMemoryProviderGetIPCHandleSize(provider, &providerIPCHandleSize);
35+
if (ret != UMF_RESULT_SUCCESS) {
36+
return ret;
37+
}
38+
39+
ipcHandleSize = sizeof(umf_ipc_data_t) + providerIPCHandleSize;
40+
umf_ipc_data_t *ipcData = malloc(ipcHandleSize);
41+
if (!ipcData) {
42+
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
43+
}
44+
45+
ret =
46+
umfMemoryProviderGetIPCHandle(provider, allocInfo.base, allocInfo.size,
47+
(void *)ipcData->providerData);
48+
if (ret != UMF_RESULT_SUCCESS) {
49+
free(ipcData);
50+
return ret;
51+
}
52+
53+
ipcData->size = allocInfo.size;
54+
ipcData->offset = (uintptr_t)ptr - (uintptr_t)allocInfo.base;
55+
56+
*umfIPCHandle = ipcData;
57+
*size = ipcHandleSize;
58+
59+
return ret;
60+
}
61+
62+
umf_result_t umfPutIPCHandle(umf_ipc_handle_t umfIPCHandle) {
63+
umf_result_t ret = UMF_RESULT_SUCCESS;
64+
65+
// TODO: Just return SUCCESS because current tracking memory provider
66+
// implementation does nothing in Put function. Tracking memory
67+
// provider relies on IPC cache and actually Put IPC handle back
68+
// to upstream memory provider when umfMemoryProviderFree is called.
69+
// To support incapsulation we should not take into account
70+
// implementation details of tracking memory provider and find the
71+
// approrpiate pool, get memory provider of that pool and call
72+
// umfMemoryProviderPutIPCHandle(hProvider,
73+
// umfIPCHandle->providerData);
74+
free(umfIPCHandle);
75+
76+
return ret;
77+
}
78+
79+
umf_result_t umfOpenIPCHandle(umf_memory_pool_handle_t hPool,
80+
umf_ipc_handle_t umfIPCHandle, void **ptr) {
81+
82+
// We cannot use umfPoolGetMemoryProvider function because it returns
83+
// upstream provider but we need tracking one
84+
umf_memory_provider_handle_t hProvider = hPool->provider;
85+
void *base = NULL;
86+
87+
umf_result_t ret = umfMemoryProviderOpenIPCHandle(
88+
hProvider, (void *)umfIPCHandle->providerData, &base);
89+
if (ret != UMF_RESULT_SUCCESS) {
90+
return ret;
91+
}
92+
*ptr = (void *)((uintptr_t)base + umfIPCHandle->offset);
93+
94+
return UMF_RESULT_SUCCESS;
95+
}
96+
97+
umf_result_t umfCloseIPCHandle(void *ptr) {
98+
umf_alloc_info_t allocInfo;
99+
umf_result_t ret =
100+
umfMemoryTrackerGetAllocInfo(ptr, &allocInfo);
101+
if (ret != UMF_RESULT_SUCCESS) {
102+
return ret;
103+
}
104+
105+
// We cannot use umfPoolGetMemoryProvider function because it returns
106+
// upstream provider but we need tracking one
107+
umf_memory_provider_handle_t hProvider = allocInfo.pool->provider;
108+
109+
return umfMemoryProviderCloseIPCHandle(hProvider, allocInfo.base);
110+
}

src/ipc_internal.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
*
3+
* Copyright (C) 2023 Intel Corporation
4+
*
5+
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
6+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
*
8+
*/
9+
10+
#ifndef UMF_IPC_INTERNAL_H
11+
#define UMF_IPC_INTERNAL_H 1
12+
13+
#include <umf/base.h>
14+
15+
#ifdef __cplusplus
16+
extern "C" {
17+
#endif
18+
19+
typedef struct umf_ipc_data_t {
20+
size_t size; // size of base allocation
21+
uint64_t offset;
22+
char providerData[];
23+
} umf_ipc_data_t;
24+
25+
#ifdef __cplusplus
26+
}
27+
#endif
28+
29+
#endif /* UMF_IPC_INTERNAL_H */

src/memory_provider.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,38 @@ umf_result_t umfMemoryProviderPurgeForce(umf_memory_provider_handle_t hProvider,
135135
return res;
136136
}
137137

138+
umf_result_t
139+
umfMemoryProviderGetIPCHandleSize(umf_memory_provider_handle_t hProvider,
140+
size_t *size) {
141+
return hProvider->ops.get_ipc_handle_size(hProvider->provider_priv, size);
142+
}
143+
144+
umf_result_t
145+
umfMemoryProviderGetIPCHandle(umf_memory_provider_handle_t hProvider,
146+
const void *ptr, size_t size, void *ipcData) {
147+
return hProvider->ops.get_ipc_handle(hProvider->provider_priv, ptr, size,
148+
ipcData);
149+
}
150+
151+
umf_result_t
152+
umfMemoryProviderPutIPCHandle(umf_memory_provider_handle_t hProvider,
153+
void *ipcData) {
154+
return hProvider->ops.put_ipc_handle(hProvider->provider_priv, ipcData);
155+
}
156+
157+
umf_result_t
158+
umfMemoryProviderOpenIPCHandle(umf_memory_provider_handle_t hProvider,
159+
void *ipcData, void **ptr) {
160+
return hProvider->ops.open_ipc_handle(hProvider->provider_priv, ipcData,
161+
ptr);
162+
}
163+
164+
umf_result_t
165+
umfMemoryProviderCloseIPCHandle(umf_memory_provider_handle_t hProvider,
166+
void *ptr) {
167+
return hProvider->ops.close_ipc_handle(hProvider->provider_priv, ptr);
168+
}
169+
138170
const char *umfMemoryProviderGetName(umf_memory_provider_handle_t hProvider) {
139171
UMF_CHECK((hProvider != NULL), NULL);
140172
return hProvider->ops.get_name(hProvider->provider_priv);

0 commit comments

Comments
 (0)