Skip to content

Commit 441c851

Browse files
committed
Add support for MAP_SHARED to OS memory provider for Linux only
Signed-off-by: Lukasz Dorau <lukasz.dorau@intel.com>
1 parent 92f3cd6 commit 441c851

File tree

7 files changed

+210
-13
lines changed

7 files changed

+210
-13
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ More detailed documentation is available here: https://oneapi-src.github.io/unif
137137
#### OS memory provider
138138

139139
A memory provider that provides memory from an operating system.
140+
It supports two types of memory mappings
141+
1) private memory mapping (`UMF_MEM_MAP_PRIVATE`)
142+
2) shared memory mapping (`UMF_MEM_MAP_SHARED` - supported on Linux only yet)
140143

141144
##### Requirements
142145

benchmark/ubench.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ UBENCH_EX(simple, glibc_malloc) {
107107

108108
static umf_os_memory_provider_params_t UMF_OS_MEMORY_PROVIDER_PARAMS = {
109109
/* .protection = */ UMF_PROTECTION_READ | UMF_PROTECTION_WRITE,
110+
/* .flag */ UMF_MEM_MAP_PRIVATE,
110111

111112
// NUMA config
112113
/* .nodemask = */ NULL,

include/umf/providers/provider_os_memory.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ typedef enum umf_mem_protection_flags_t {
2929
/// @endcond
3030
} umf_mem_protection_flags_t;
3131

32+
/// @brief Memory flags
33+
typedef enum umf_memory_flags_t {
34+
UMF_MEM_NONE = 0, ///< No flag
35+
UMF_MEM_MAP_PRIVATE = (1 << 0), ///< private memory mapping
36+
UMF_MEM_MAP_SHARED =
37+
(1 << 1), ///< shared memory mapping (supported on Linux only)
38+
} umf_memory_flags_t;
39+
3240
/// @brief Memory binding mode
3341
/// Specifies how memory is bound to NUMA nodes on systems that support NUMA.
3442
/// Not every mode is supported on every system.
@@ -61,6 +69,8 @@ typedef enum umf_numa_mode_t {
6169
typedef struct umf_os_memory_provider_params_t {
6270
/// Combination of 'umf_mem_protection_flags_t' flags
6371
unsigned protection;
72+
/// 'umf_memory_flags_t' flag
73+
unsigned flag;
6474

6575
// NUMA config
6676
/// ordered list of numa nodes
@@ -91,6 +101,7 @@ static inline umf_os_memory_provider_params_t
91101
umfOsMemoryProviderParamsDefault(void) {
92102
umf_os_memory_provider_params_t params = {
93103
UMF_PROTECTION_READ | UMF_PROTECTION_WRITE, /* protection */
104+
UMF_MEM_MAP_PRIVATE, /* flag */
94105
NULL, /* numa_list */
95106
0, /* numa_list_len */
96107
UMF_NUMA_MODE_DEFAULT, /* numa_mode */

src/provider/provider_os_memory.c

Lines changed: 77 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <string.h>
1616

1717
#include "base_alloc_global.h"
18+
#include "critnib.h"
1819
#include "provider_os_memory_internal.h"
1920
#include "utils_log.h"
2021

@@ -24,8 +25,15 @@
2425

2526
#define NODESET_STR_BUF_LEN 1024
2627

28+
// maximum size of file used for memory mapping
29+
#define MAX_SIZE_FD (1ULL << 44)
30+
2731
typedef struct os_memory_provider_t {
2832
unsigned protection; // combination of OS-specific protection flags
33+
unsigned flag; // memory mapping flag
34+
int fd; // file descriptor for memory mapping
35+
size_t size_fd; // size of file used for memory mapping
36+
critnib *ptr_off; // a critnib storing (ptr, fd_offset) pairs
2937

3038
// NUMA config
3139
hwloc_bitmap_t nodeset;
@@ -191,6 +199,28 @@ static umf_result_t translate_params(umf_os_memory_provider_params_t *in_params,
191199
return result;
192200
}
193201

202+
result = os_translate_memory_flag(in_params->flag, &provider->flag);
203+
if (result != UMF_RESULT_SUCCESS) {
204+
LOG_ERR("incorrect memory flag: %u", in_params->flag);
205+
return result;
206+
}
207+
208+
provider->fd = os_create_memory_fd(provider->flag);
209+
if (provider->fd == -1) {
210+
LOG_PERR("creating a file descriptor for memory mapping failed");
211+
return UMF_RESULT_ERROR_UNKNOWN;
212+
}
213+
214+
provider->size_fd = 0; // will be increased during each allocation
215+
216+
errno = 0;
217+
if (provider->fd > 0 && os_set_file_size(provider->fd, MAX_SIZE_FD)) {
218+
LOG_PDEBUG("setting file size %llu failed", MAX_SIZE_FD);
219+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
220+
}
221+
222+
LOG_DEBUG("size of the memory mapped file set to %llu", MAX_SIZE_FD);
223+
194224
// NUMA config
195225
int emptyNodeset = in_params->numa_list_len == 0;
196226
result = translate_numa_mode(in_params->numa_mode, emptyNodeset,
@@ -258,10 +288,19 @@ static umf_result_t os_initialize(void *params, void **provider) {
258288
}
259289
}
260290

291+
os_provider->ptr_off = critnib_new();
292+
if (!os_provider->ptr_off) {
293+
LOG_ERR("creating IPC cache failed");
294+
ret = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
295+
goto err_free_nodeset_str_buf;
296+
}
297+
261298
*provider = os_provider;
262299

263300
return UMF_RESULT_SUCCESS;
264301

302+
err_free_nodeset_str_buf:
303+
umf_ba_global_free(os_provider->nodeset_str_buf);
265304
err_destroy_hwloc_topology:
266305
hwloc_topology_destroy(os_provider->topo);
267306
err_free_os_provider:
@@ -276,6 +315,9 @@ static void os_finalize(void *provider) {
276315
}
277316

278317
os_memory_provider_t *os_provider = provider;
318+
319+
critnib_delete(os_provider->ptr_off);
320+
279321
if (os_provider->nodeset_str_buf) {
280322
umf_ba_global_free(os_provider->nodeset_str_buf);
281323
}
@@ -331,7 +373,8 @@ static inline void assert_is_page_aligned(uintptr_t ptr, size_t page_size) {
331373
}
332374

333375
static int os_mmap_aligned(void *hint_addr, size_t length, size_t alignment,
334-
size_t page_size, int prot, void **out_addr) {
376+
size_t page_size, int prot, int flag, int fd,
377+
void **out_addr, size_t *fd_size) {
335378
assert(out_addr);
336379

337380
size_t extended_length = length;
@@ -344,8 +387,20 @@ static int os_mmap_aligned(void *hint_addr, size_t length, size_t alignment,
344387
extended_length += alignment;
345388
}
346389

347-
void *ptr = os_mmap(hint_addr, extended_length, prot);
390+
size_t fd_offset = 0;
391+
392+
if (fd > 0) {
393+
fd_offset = *fd_size;
394+
*fd_size += extended_length;
395+
if (*fd_size > MAX_SIZE_FD) {
396+
LOG_ERR("cannot grow a file size beyond %llu", MAX_SIZE_FD);
397+
return -1;
398+
}
399+
}
400+
401+
void *ptr = os_mmap(hint_addr, extended_length, prot, flag, fd, fd_offset);
348402
if (ptr == NULL) {
403+
LOG_PDEBUG("memory mapping failed");
349404
return -1;
350405
}
351406

@@ -411,15 +466,16 @@ static umf_result_t os_alloc(void *provider, size_t size, size_t alignment,
411466
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
412467
}
413468

414-
int protection = os_provider->protection;
469+
size_t fd_offset = os_provider->size_fd; // needed for critnib_insert()
415470

416471
void *addr = NULL;
417472
errno = 0;
418-
ret = os_mmap_aligned(NULL, size, alignment, page_size, protection, &addr);
473+
ret = os_mmap_aligned(NULL, size, alignment, page_size,
474+
os_provider->protection, os_provider->flag,
475+
os_provider->fd, &addr, &os_provider->size_fd);
419476
if (ret) {
420477
os_store_last_native_error(UMF_OS_RESULT_ERROR_ALLOC_FAILED, errno);
421478
LOG_PERR("memory allocation failed");
422-
423479
return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC;
424480
}
425481

@@ -429,7 +485,6 @@ static umf_result_t os_alloc(void *provider, size_t size, size_t alignment,
429485
LOG_ERR("allocated address 0x%llx is not aligned to %zu (0x%zx) "
430486
"bytes",
431487
(unsigned long long)addr, alignment, alignment);
432-
433488
goto err_unmap;
434489
}
435490

@@ -460,6 +515,16 @@ static umf_result_t os_alloc(void *provider, size_t size, size_t alignment,
460515
}
461516
}
462517

518+
if (os_provider->fd > 0) {
519+
ret = critnib_insert(os_provider->ptr_off, (uintptr_t)addr,
520+
(void *)(uintptr_t)fd_offset, 0 /* update */);
521+
if (ret) {
522+
LOG_DEBUG("inserting a value to the IPC cache failed (addr=%p, "
523+
"offset=%zu)",
524+
addr, fd_offset);
525+
}
526+
}
527+
463528
*resultPtr = addr;
464529

465530
return UMF_RESULT_SUCCESS;
@@ -474,6 +539,12 @@ static umf_result_t os_free(void *provider, void *ptr, size_t size) {
474539
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
475540
}
476541

542+
os_memory_provider_t *os_provider = (os_memory_provider_t *)provider;
543+
544+
if (os_provider->fd > 0) {
545+
critnib_remove(os_provider->ptr_off, (uintptr_t)ptr);
546+
}
547+
477548
errno = 0;
478549
int ret = os_munmap(ptr, size);
479550
// ignore error when size == 0

src/provider/provider_os_memory_internal.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,14 @@ umf_result_t os_translate_flags(unsigned in_flags, unsigned max,
2828
umf_result_t os_translate_mem_protection_flags(unsigned in_protection,
2929
unsigned *out_protection);
3030

31-
void *os_mmap(void *hint_addr, size_t length, int prot);
31+
umf_result_t os_translate_memory_flag(unsigned in_flag, unsigned *out_flag);
32+
33+
int os_create_memory_fd(unsigned translated_memory_flag);
34+
35+
int os_set_file_size(int fd, size_t size);
36+
37+
void *os_mmap(void *hint_addr, size_t length, int prot, int flag, int fd,
38+
size_t fd_offset);
3239

3340
int os_munmap(void *addr, size_t length);
3441

src/provider/provider_os_memory_linux.c

Lines changed: 83 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,17 @@
66
*/
77

88
#include <assert.h>
9+
#include <errno.h>
910
#include <string.h>
1011
#include <sys/mman.h>
12+
#include <sys/syscall.h>
1113
#include <unistd.h>
1214

13-
#include "provider_os_memory_internal.h"
1415
#include <umf/providers/provider_os_memory.h>
1516

17+
#include "provider_os_memory_internal.h"
18+
#include "utils_log.h"
19+
1620
umf_result_t os_translate_mem_protection_one_flag(unsigned in_protection,
1721
unsigned *out_protection) {
1822
switch (in_protection) {
@@ -32,6 +36,74 @@ umf_result_t os_translate_mem_protection_one_flag(unsigned in_protection,
3236
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
3337
}
3438

39+
umf_result_t os_translate_memory_flag(unsigned in_flag, unsigned *out_flag) {
40+
switch (in_flag) {
41+
case UMF_MEM_MAP_PRIVATE:
42+
*out_flag = MAP_PRIVATE;
43+
return UMF_RESULT_SUCCESS;
44+
case UMF_MEM_MAP_SHARED:
45+
#ifdef __APPLE__
46+
return UMF_RESULT_ERROR_NOT_SUPPORTED; // not supported on MacOSX
47+
#else
48+
*out_flag = MAP_SHARED;
49+
return UMF_RESULT_SUCCESS;
50+
#endif
51+
}
52+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
53+
}
54+
55+
int os_create_memory_fd(unsigned translated_memory_flag) {
56+
#ifdef __APPLE__
57+
(void)translated_memory_flag; // unused
58+
return 0; // ignored on MacOSX
59+
#else
60+
// fd is created only for MAP_SHARED
61+
if (translated_memory_flag != MAP_SHARED) {
62+
return 0;
63+
}
64+
65+
int fd = -1;
66+
67+
#ifdef __NR_memfd_secret
68+
// SYS_memfd_secret is supported since Linux 5.14
69+
fd = syscall(SYS_memfd_secret, 0);
70+
if (fd == -1) {
71+
LOG_PDEBUG("memfd_secret()");
72+
}
73+
if (fd > 0) {
74+
LOG_DEBUG("file descriptor created using memfd_secret()");
75+
return fd;
76+
}
77+
// syscall(SYS_memfd_secret) can fail with errno == ENOTSYS (function not implemented).
78+
// We should try to call syscall(SYS_memfd_create) in this case.
79+
#endif /* __NR_memfd_secret */
80+
81+
#ifdef __NR_memfd_create
82+
// SYS_memfd_create is supported since Linux 3.17, glibc 2.27
83+
fd = syscall(SYS_memfd_create, "fd_name", 0);
84+
if (fd == -1) {
85+
LOG_PDEBUG("memfd_create()");
86+
}
87+
if (fd > 0) {
88+
LOG_DEBUG("file descriptor created using memfd_create()");
89+
}
90+
#endif /* __NR_memfd_create */
91+
92+
return fd;
93+
94+
#endif /* __APPLE__ */
95+
}
96+
97+
int os_set_file_size(int fd, size_t size) {
98+
#ifdef __APPLE__
99+
(void)fd; // unused
100+
(void)size; // unused
101+
return 0; // ignored on MacOSX
102+
#else
103+
return ftruncate(fd, size);
104+
#endif /* __APPLE__ */
105+
}
106+
35107
umf_result_t os_translate_mem_protection_flags(unsigned in_protection,
36108
unsigned *out_protection) {
37109
// translate protection - combination of 'umf_mem_protection_flags_t' flags
@@ -51,13 +123,19 @@ static int os_translate_purge_advise(umf_purge_advise_t advise) {
51123
return -1;
52124
}
53125

54-
void *os_mmap(void *hint_addr, size_t length, int prot) {
55-
// MAP_ANONYMOUS - the mapping is not backed by any file
56-
void *ptr =
57-
mmap(hint_addr, length, prot, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
126+
void *os_mmap(void *hint_addr, size_t length, int prot, int flag, int fd,
127+
size_t fd_offset) {
128+
fd = (fd == 0) ? -1 : fd;
129+
if (fd == -1) {
130+
// MAP_ANONYMOUS - the mapping is not backed by any file
131+
flag |= MAP_ANONYMOUS;
132+
}
133+
134+
void *ptr = mmap(hint_addr, length, prot, flag, fd, fd_offset);
58135
if (ptr == MAP_FAILED) {
59136
return NULL;
60137
}
138+
61139
return ptr;
62140
}
63141

src/provider/provider_os_memory_windows.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,33 @@ umf_result_t os_translate_mem_protection_flags(unsigned in_protection,
5454
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
5555
}
5656

57-
void *os_mmap(void *hint_addr, size_t length, int prot) {
57+
umf_result_t os_translate_memory_flag(unsigned in_flag, unsigned *out_flag) {
58+
switch (in_flag) {
59+
case UMF_MEM_MAP_PRIVATE:
60+
*out_flag = 0; // ignored on Windows
61+
return UMF_RESULT_SUCCESS;
62+
case UMF_MEM_MAP_SHARED:
63+
return UMF_RESULT_ERROR_NOT_SUPPORTED; // not supported on Windows yet
64+
}
65+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
66+
}
67+
68+
int os_create_memory_fd(unsigned translated_memory_flag) {
69+
(void)translated_memory_flag; // unused
70+
return 0; // ignored on Windows
71+
}
72+
73+
int os_set_file_size(int fd, size_t size) {
74+
(void)fd; // unused
75+
(void)size; // unused
76+
return 0; // ignored on Windows
77+
}
78+
79+
void *os_mmap(void *hint_addr, size_t length, int prot, int flag, int fd,
80+
size_t fd_offset) {
81+
(void)flag; // ignored on Windows
82+
(void)fd; // ignored on Windows
83+
(void)fd_offset; // ignored on Windows
5884
return VirtualAlloc(hint_addr, length, MEM_RESERVE | MEM_COMMIT, prot);
5985
}
6086

0 commit comments

Comments
 (0)