Skip to content

Commit ae2f950

Browse files
committed
Extend UMF to support IPC handles
1 parent a0c46ee commit ae2f950

File tree

12 files changed

+687
-22
lines changed

12 files changed

+687
-22
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: 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
@@ -136,6 +136,65 @@ 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 providerIpcData [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,
162+
void *providerIpcData);
163+
164+
///
165+
/// @brief Release IPC handle retrieved with get_ipc_handle function.
166+
/// @param hProvider [in] handle to the memory provider.
167+
/// @param providerIpcData [in] pointer to the IPC opaque data structure.
168+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
169+
/// UMF_RESULT_ERROR_INVALID_ARGUMENT if providerIpcData was not created by this provider.
170+
/// UMF_RESULT_ERROR_NOT_SUPPORTED if IPC functionality is not supported by this provider.
171+
umf_result_t
172+
umfMemoryProviderPutIPCHandle(umf_memory_provider_handle_t hProvider,
173+
void *providerIpcData);
174+
175+
///
176+
/// @brief Open IPC handle.
177+
/// @param hProvider [in] handle to the memory provider.
178+
/// @param providerIpcData [in] pointer to the IPC opaque data structure.
179+
/// @param ptr [out] pointer to the memory to be used in the current process.
180+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
181+
/// UMF_RESULT_ERROR_INVALID_ARGUMENT if providerIpcData cannot be handled by the provider.
182+
/// UMF_RESULT_ERROR_NOT_SUPPORTED if IPC functionality is not supported by this provider.
183+
umf_result_t
184+
umfMemoryProviderOpenIPCHandle(umf_memory_provider_handle_t hProvider,
185+
void *providerIpcData, void **ptr);
186+
187+
///
188+
/// @brief Close an IPC memory handle.
189+
/// @param hProvider [in] handle to the memory provider.
190+
/// @param ptr [in] pointer returned by umfMemoryProviderOpenIPCHandle function.
191+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
192+
/// UMF_RESULT_ERROR_INVALID_ARGUMENT if invalid \p hProvider or \p ptr are passed.
193+
/// UMF_RESULT_ERROR_NOT_SUPPORTED if IPC functionality is not supported by this provider.
194+
umf_result_t
195+
umfMemoryProviderCloseIPCHandle(umf_memory_provider_handle_t hProvider,
196+
void *ptr);
197+
139198
///
140199
/// @brief Retrieve name of a given memory \p hProvider.
141200
/// @param hProvider handle to the memory provider

include/umf/memory_provider_ops.h

Lines changed: 61 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,61 @@ 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 providerIpcData [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 *providerIpcData);
103+
104+
///
105+
/// @brief Release IPC handle retrieved with get_ipc_handle function.
106+
/// @param provider pointer to the memory provider.
107+
/// @param providerIpcData 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 providerIpcData 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 *providerIpcData);
112+
113+
///
114+
/// @brief Open IPC handle.
115+
/// @param provider pointer to the memory provider.
116+
/// @param providerIpcData 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 providerIpcData 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 *providerIpcData,
122+
void **ptr);
123+
124+
///
125+
/// @brief Closes an IPC memory handle.
126+
/// @param provider pointer to the memory provider.
127+
/// @param ptr pointer to the memory retrieved with open_ipc_handle function.
128+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
129+
/// UMF_RESULT_ERROR_INVALID_ARGUMENT if invalid \p ptr is passed.
130+
/// UMF_RESULT_ERROR_NOT_SUPPORTED if IPC functionality is not supported by this provider.
131+
umf_result_t (*close_ipc_handle)(void *provider, void *ptr);
132+
} umf_memory_provider_ipc_ops_t;
133+
79134
///
80135
/// @brief This structure comprises function pointers used by corresponding
81136
/// umfMemoryProvider* calls. Each memory provider implementation should
@@ -180,6 +235,11 @@ typedef struct umf_memory_provider_ops_t {
180235
/// @brief Optional ops
181236
///
182237
umf_memory_provider_ext_ops_t ext;
238+
239+
///
240+
/// @brief Optional IPC ops. The API allows sharing of memory objects across different processes.
241+
///
242+
umf_memory_provider_ipc_ops_t ipc;
183243
} umf_memory_provider_ops_t;
184244

185245
#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: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
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+
#include "utils_log.h"
20+
21+
umf_result_t umfGetIPCHandle(const void *ptr, umf_ipc_handle_t *umfIPCHandle,
22+
size_t *size) {
23+
size_t ipcHandleSize = 0;
24+
umf_alloc_info_t allocInfo;
25+
umf_result_t ret = umfMemoryTrackerGetAllocInfo(ptr, &allocInfo);
26+
if (ret != UMF_RESULT_SUCCESS) {
27+
LOG_ERR("umfGetIPCHandle: cannot get alloc info for ptr = %p.", 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+
LOG_ERR("umfGetIPCHandle: cannot get IPC handle size.");
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+
LOG_ERR("umfGetIPCHandle: failed to allocate ipcData");
47+
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
48+
}
49+
50+
ret =
51+
umfMemoryProviderGetIPCHandle(provider, allocInfo.base, allocInfo.size,
52+
(void *)ipcData->providerIpcData);
53+
if (ret != UMF_RESULT_SUCCESS) {
54+
LOG_ERR("umfGetIPCHandle: failed to get IPC handle.");
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->providerIpcData);
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->providerIpcData, &base);
95+
if (ret != UMF_RESULT_SUCCESS) {
96+
LOG_ERR("umfOpenIPCHandle: memory provider failed to IPC handle.");
97+
return ret;
98+
}
99+
*ptr = (void *)((uintptr_t)base + umfIPCHandle->offset);
100+
101+
return UMF_RESULT_SUCCESS;
102+
}
103+
104+
umf_result_t umfCloseIPCHandle(void *ptr) {
105+
umf_alloc_info_t allocInfo;
106+
umf_result_t ret = umfMemoryTrackerGetAllocInfo(ptr, &allocInfo);
107+
if (ret != UMF_RESULT_SUCCESS) {
108+
LOG_ERR("umfCloseIPCHandle: cannot get alloc info for ptr = %p.", ptr);
109+
return ret;
110+
}
111+
112+
// We cannot use umfPoolGetMemoryProvider function because it returns
113+
// upstream provider but we need tracking one
114+
umf_memory_provider_handle_t hProvider = allocInfo.pool->provider;
115+
116+
return umfMemoryProviderCloseIPCHandle(hProvider, allocInfo.base);
117+
}

src/ipc_internal.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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+
// UMF representation of IPC handle. It contains UMF-specific common data
20+
// and provider-specific IPC data, stored in providerIpcData.
21+
// providerIpcData is a Flexible Array Member because its size varies
22+
// depending on the provider.
23+
typedef struct umf_ipc_data_t {
24+
size_t size; // size of base allocation
25+
uint64_t offset;
26+
char providerIpcData[];
27+
} umf_ipc_data_t;
28+
29+
#ifdef __cplusplus
30+
}
31+
#endif
32+
33+
#endif /* UMF_IPC_INTERNAL_H */

0 commit comments

Comments
 (0)