Skip to content

Commit 5aa9f9f

Browse files
committed
Extend UMF to support IPC handles
1 parent e4402d6 commit 5aa9f9f

File tree

9 files changed

+522
-3
lines changed

9 files changed

+522
-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: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
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 =
24+
umfMemoryTrackerGetAllocInfo(umfMemoryTrackerGet(), ptr, &allocInfo);
25+
if (ret != UMF_RESULT_SUCCESS) {
26+
return ret;
27+
}
28+
29+
// We cannot use umfPoolGetMemoryProvider function because it returns
30+
// upstream provider but we need tracking one
31+
umf_memory_provider_handle_t provider = allocInfo.pool->provider;
32+
assert(provider);
33+
34+
size_t providerIPCHandleSize;
35+
ret = umfMemoryProviderGetIPCHandleSize(provider, &providerIPCHandleSize);
36+
if (ret != UMF_RESULT_SUCCESS) {
37+
return ret;
38+
}
39+
40+
ipcHandleSize = sizeof(umf_ipc_data_t) + providerIPCHandleSize;
41+
umf_ipc_data_t *ipcData = malloc(ipcHandleSize);
42+
if (!ipcData) {
43+
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
44+
}
45+
46+
ret =
47+
umfMemoryProviderGetIPCHandle(provider, allocInfo.base, allocInfo.size,
48+
(void *)ipcData->providerData);
49+
if (ret != UMF_RESULT_SUCCESS) {
50+
free(ipcData);
51+
return ret;
52+
}
53+
54+
ipcData->size = allocInfo.size;
55+
ipcData->offset = (uintptr_t)ptr - (uintptr_t)allocInfo.base;
56+
57+
*umfIPCHandle = ipcData;
58+
*size = ipcHandleSize;
59+
60+
return ret;
61+
}
62+
63+
umf_result_t umfPutIPCHandle(umf_ipc_handle_t umfIPCHandle) {
64+
umf_result_t ret = UMF_RESULT_SUCCESS;
65+
66+
// TODO: Just return SUCCESS because current tracking memory provider
67+
// implementation does nothing in Put function. Tracking memory
68+
// provider relies on IPC cache and actually Put IPC handle back
69+
// to upstream memory provider when umfMemoryProviderFree is called.
70+
// To support incapsulation we should not take into account
71+
// implementation details of tracking memory provider and find the
72+
// approrpiate pool, get memory provider of that pool and call
73+
// umfMemoryProviderPutIPCHandle(hProvider,
74+
// umfIPCHandle->providerData);
75+
free(umfIPCHandle);
76+
77+
return ret;
78+
}
79+
80+
umf_result_t umfOpenIPCHandle(umf_memory_pool_handle_t hPool,
81+
umf_ipc_handle_t umfIPCHandle, void **ptr) {
82+
83+
// We cannot use umfPoolGetMemoryProvider function because it returns
84+
// upstream provider but we need tracking one
85+
umf_memory_provider_handle_t hProvider = hPool->provider;
86+
void *base = NULL;
87+
88+
umf_result_t ret = umfMemoryProviderOpenIPCHandle(
89+
hProvider, (void *)umfIPCHandle->providerData, &base);
90+
if (ret != UMF_RESULT_SUCCESS) {
91+
return ret;
92+
}
93+
*ptr = (void *)((uintptr_t)base + umfIPCHandle->offset);
94+
95+
return UMF_RESULT_SUCCESS;
96+
}
97+
98+
umf_result_t umfCloseIPCHandle(void *ptr) {
99+
umf_alloc_info_t allocInfo;
100+
umf_result_t ret =
101+
umfMemoryTrackerGetAllocInfo(umfMemoryTrackerGet(), ptr, &allocInfo);
102+
if (ret != UMF_RESULT_SUCCESS) {
103+
return ret;
104+
}
105+
106+
// We cannot use umfPoolGetMemoryProvider function because it returns
107+
// upstream provider but we need tracking one
108+
umf_memory_provider_handle_t hProvider = allocInfo.pool->provider;
109+
110+
return umfMemoryProviderCloseIPCHandle(hProvider, allocInfo.base);
111+
}

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
@@ -133,6 +133,38 @@ umf_result_t umfMemoryProviderPurgeForce(umf_memory_provider_handle_t hProvider,
133133
return res;
134134
}
135135

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

0 commit comments

Comments
 (0)