Skip to content

Commit c02f556

Browse files
committed
Extend UMF to support IPC handles
1 parent 41803fe commit c02f556

File tree

9 files changed

+508
-2
lines changed

9 files changed

+508
-2
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+
enum 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+
enum 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+
enum 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+
enum 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: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,63 @@ umf_result_t umfMemoryProviderPurgeLazy(umf_memory_provider_handle_t hProvider,
136136
umf_result_t umfMemoryProviderPurgeForce(umf_memory_provider_handle_t hProvider,
137137
void *ptr, size_t size);
138138

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

77
set(UMF_SOURCES
8+
ipc.c
89
memory_pool.c
910
memory_provider.c
1011
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+
enum umf_result_t
20+
umfGetIPCHandle(const void *ptr, umf_ipc_handle_t *umfIPCHandle, size_t *size) {
21+
size_t ipcHandleSize = 0;
22+
struct umf_alloc_info_t allocInfo;
23+
enum 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(struct umf_ipc_data_t) + providerIPCHandleSize;
41+
struct 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+
enum umf_result_t umfPutIPCHandle(umf_ipc_handle_t umfIPCHandle) {
64+
enum 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+
enum 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+
enum 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+
enum umf_result_t umfCloseIPCHandle(void *ptr) {
99+
struct umf_alloc_info_t allocInfo;
100+
enum 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+
struct umf_ipc_data_t {
20+
size_t size; // size of base allocation
21+
uint64_t offset;
22+
char providerData[];
23+
};
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
@@ -118,6 +118,38 @@ umf_result_t umfMemoryProviderPurgeForce(umf_memory_provider_handle_t hProvider,
118118
return res;
119119
}
120120

121+
enum umf_result_t
122+
umfMemoryProviderGetIPCHandleSize(umf_memory_provider_handle_t hProvider,
123+
size_t *size) {
124+
return hProvider->ops.get_ipc_handle_size(hProvider->provider_priv, size);
125+
}
126+
127+
enum umf_result_t
128+
umfMemoryProviderGetIPCHandle(umf_memory_provider_handle_t hProvider,
129+
const void *ptr, size_t size, void *ipcData) {
130+
return hProvider->ops.get_ipc_handle(hProvider->provider_priv, ptr, size,
131+
ipcData);
132+
}
133+
134+
enum umf_result_t
135+
umfMemoryProviderPutIPCHandle(umf_memory_provider_handle_t hProvider,
136+
void *ipcData) {
137+
return hProvider->ops.put_ipc_handle(hProvider->provider_priv, ipcData);
138+
}
139+
140+
enum umf_result_t
141+
umfMemoryProviderOpenIPCHandle(umf_memory_provider_handle_t hProvider,
142+
void *ipcData, void **ptr) {
143+
return hProvider->ops.open_ipc_handle(hProvider->provider_priv, ipcData,
144+
ptr);
145+
}
146+
147+
enum umf_result_t
148+
umfMemoryProviderCloseIPCHandle(umf_memory_provider_handle_t hProvider,
149+
void *ptr) {
150+
return hProvider->ops.close_ipc_handle(hProvider->provider_priv, ptr);
151+
}
152+
121153
const char *umfMemoryProviderGetName(umf_memory_provider_handle_t hProvider) {
122154
return hProvider->ops.get_name(hProvider->provider_priv);
123155
}

0 commit comments

Comments
 (0)