Skip to content

Commit 0fe020e

Browse files
committed
Extend UMF to support IPC handles
1 parent 22a30de commit 0fe020e

File tree

12 files changed

+671
-19
lines changed

12 files changed

+671
-19
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-2024 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: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
*
3-
* Copyright (C) 2023 Intel Corporation
3+
* Copyright (C) 2023-2024 Intel Corporation
44
*
55
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
66
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
@@ -136,6 +136,64 @@ 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+
///
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: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
*
3-
* Copyright (C) 2023 Intel Corporation
3+
* Copyright (C) 2023-2024 Intel Corporation
44
*
55
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
66
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
@@ -76,6 +76,60 @@ typedef struct umf_memory_provider_ext_ops_t {
7676

7777
} umf_memory_provider_ext_ops_t;
7878

79+
///
80+
/// @brief This structure comprises optional IPC API. The API allows sharing of
81+
/// memory objects across different processes. A memory provider implementation can keep them NULL.
82+
///
83+
typedef struct umf_memory_provider_ipc_ops_t {
84+
///
85+
/// @brief Retrieve the size of opaque data structure required to store IPC data.
86+
/// @param provider pointer to the memory provider.
87+
/// @param size [out] pointer to the size.
88+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
89+
/// UMF_RESULT_ERROR_NOT_SUPPORTED if IPC functionality is not supported by this provider.
90+
umf_result_t (*get_ipc_handle_size)(void *provider, size_t *size);
91+
92+
///
93+
/// @brief Retrieve an IPC memory handle for the specified allocation.
94+
/// @param provider pointer to the memory provider.
95+
/// @param ptr beginning of the virtual memory range.
96+
/// @param size size of the memory address range.
97+
/// @param ipcData [out] pointer to the preallocated opaque data structure to store IPC handle.
98+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
99+
/// UMF_RESULT_ERROR_INVALID_ARGUMENT if ptr was not allocated by this provider.
100+
/// UMF_RESULT_ERROR_NOT_SUPPORTED if IPC functionality is not supported by this provider.
101+
umf_result_t (*get_ipc_handle)(void *provider, const void *ptr, size_t size,
102+
void *ipcData);
103+
104+
///
105+
/// @brief Release IPC handle retrieved with get_ipc_handle function.
106+
/// @param provider pointer to the memory provider.
107+
/// @param ipcData pointer to the IPC opaque data structure.
108+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
109+
/// UMF_RESULT_ERROR_INVALID_ARGUMENT if ipcData was not created by this provider.
110+
/// UMF_RESULT_ERROR_NOT_SUPPORTED if IPC functionality is not supported by this provider.
111+
umf_result_t (*put_ipc_handle)(void *provider, void *ipcData);
112+
113+
///
114+
/// @brief Open IPC handle.
115+
/// @param provider pointer to the memory provider.
116+
/// @param ipcData pointer to the IPC opaque data structure.
117+
/// @param ptr [out] pointer to the memory to be used in the current process.
118+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
119+
/// UMF_RESULT_ERROR_INVALID_ARGUMENT if ipcData cannot be handled by the provider.
120+
/// UMF_RESULT_ERROR_NOT_SUPPORTED if IPC functionality is not supported by this provider.
121+
umf_result_t (*open_ipc_handle)(void *provider, void *ipcData, void **ptr);
122+
123+
///
124+
/// @brief Closes an IPC memory handle.
125+
/// @param provider pointer to the memory provider.
126+
/// @param ptr pointer to the memory retrieved with open_ipc_handle function.
127+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
128+
/// UMF_RESULT_ERROR_INVALID_ARGUMENT if invalid \p ptr is passed.
129+
/// UMF_RESULT_ERROR_NOT_SUPPORTED if IPC functionality is not supported by this provider.
130+
umf_result_t (*close_ipc_handle)(void *provider, void *ptr);
131+
} umf_memory_provider_ipc_ops_t;
132+
79133
///
80134
/// @brief This structure comprises function pointers used by corresponding
81135
/// umfMemoryProvider* calls. Each memory provider implementation should
@@ -180,6 +234,11 @@ typedef struct umf_memory_provider_ops_t {
180234
/// @brief Optional ops
181235
///
182236
umf_memory_provider_ext_ops_t ext;
237+
238+
///
239+
/// @brief Optional IPC ops. The API allows sharing of memory objects across different processes.
240+
///
241+
umf_memory_provider_ipc_ops_t ipc;
183242
} umf_memory_provider_ops_t;
184243

185244
#ifdef __cplusplus

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ set(BA_SOURCES
5353

5454
set(UMF_SOURCES
5555
${BA_SOURCES}
56+
ipc.c
5657
memory_pool.c
5758
memory_provider.c
5859
memory_provider_get_last_failed.c

src/ipc.c

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

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-2024 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 */

0 commit comments

Comments
 (0)