Skip to content

Commit b3b2ec8

Browse files
committed
Add support for MAP_SHARED to OS memory provider for Linux only
Signed-off-by: Lukasz Dorau <[email protected]>
1 parent 26ffbe8 commit b3b2ec8

File tree

7 files changed

+169
-12
lines changed

7 files changed

+169
-12
lines changed

README.md

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

132132
A memory provider that provides memory from an operating system.
133+
It supports two types of memory mappings
134+
1) private memory mapping (`UMF_MEM_MAP_PRIVATE`)
135+
2) shared memory mapping (`UMF_MEM_MAP_SHARED` - supported on Linux only yet)
133136

134137
##### Requirements
135138

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
/// Points to a bit mask of nodes containing up to maxnode bits, depending on
@@ -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, /* nodemask */
95106
0, /* maxnode */
96107
UMF_NUMA_MODE_DEFAULT, /* numa_mode */

src/provider/provider_os_memory.c

Lines changed: 64 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

@@ -26,6 +27,10 @@
2627

2728
typedef struct os_memory_provider_t {
2829
unsigned protection; // combination of OS-specific protection flags
30+
unsigned flag; // memory mapping flag
31+
int fd; // file descriptor for memory mapping
32+
size_t size_fd; // size of file used for memory mapping
33+
critnib *ptr_off; // a critnib storing (ptr, fd_offset) pairs
2934

3035
// NUMA config
3136
hwloc_bitmap_t nodeset;
@@ -192,6 +197,20 @@ static umf_result_t translate_params(umf_os_memory_provider_params_t *in_params,
192197
return result;
193198
}
194199

200+
result = os_translate_memory_flag(in_params->flag, &provider->flag);
201+
if (result != UMF_RESULT_SUCCESS) {
202+
LOG_ERR("incorrect memory flag: %u", in_params->flag);
203+
return result;
204+
}
205+
206+
provider->fd = os_create_memory_fd(in_params->flag);
207+
if (provider->fd == -1) {
208+
LOG_PERR("creating a file descriptor for memory mapping failed");
209+
return UMF_RESULT_ERROR_UNKNOWN;
210+
}
211+
212+
provider->size_fd = 0; // will be increased during each allocation
213+
195214
// NUMA config
196215
int emptyNodeset = (!in_params->maxnode || !in_params->nodemask);
197216
result = translate_numa_mode(in_params->numa_mode, emptyNodeset,
@@ -259,10 +278,19 @@ static umf_result_t os_initialize(void *params, void **provider) {
259278
}
260279
}
261280

281+
os_provider->ptr_off = critnib_new();
282+
if (!os_provider->ptr_off) {
283+
LOG_ERR("creating IPC cache failed");
284+
ret = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
285+
goto err_free_nodeset_str_buf;
286+
}
287+
262288
*provider = os_provider;
263289

264290
return UMF_RESULT_SUCCESS;
265291

292+
err_free_nodeset_str_buf:
293+
umf_ba_global_free(os_provider->nodeset_str_buf);
266294
err_destroy_hwloc_topology:
267295
hwloc_topology_destroy(os_provider->topo);
268296
err_free_os_provider:
@@ -277,6 +305,9 @@ static void os_finalize(void *provider) {
277305
}
278306

279307
os_memory_provider_t *os_provider = provider;
308+
309+
critnib_delete(os_provider->ptr_off);
310+
280311
if (os_provider->nodeset_str_buf) {
281312
umf_ba_global_free(os_provider->nodeset_str_buf);
282313
}
@@ -332,7 +363,8 @@ static inline void assert_is_page_aligned(uintptr_t ptr, size_t page_size) {
332363
}
333364

334365
static int os_mmap_aligned(void *hint_addr, size_t length, size_t alignment,
335-
size_t page_size, int prot, void **out_addr) {
366+
size_t page_size, int prot, int flag, int fd,
367+
void **out_addr, size_t *fd_size) {
336368
assert(out_addr);
337369

338370
size_t extended_length = length;
@@ -345,7 +377,17 @@ static int os_mmap_aligned(void *hint_addr, size_t length, size_t alignment,
345377
extended_length += alignment;
346378
}
347379

348-
void *ptr = os_mmap(hint_addr, extended_length, prot);
380+
size_t fd_offset = 0;
381+
382+
if (fd > 0) {
383+
fd_offset = *fd_size;
384+
*fd_size += extended_length;
385+
if (os_set_file_size(fd, *fd_size)) {
386+
return -1;
387+
}
388+
}
389+
390+
void *ptr = os_mmap(hint_addr, extended_length, prot, flag, fd, fd_offset);
349391
if (ptr == NULL) {
350392
return -1;
351393
}
@@ -412,15 +454,16 @@ static umf_result_t os_alloc(void *provider, size_t size, size_t alignment,
412454
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
413455
}
414456

415-
int protection = os_provider->protection;
457+
size_t fd_offset = os_provider->size_fd; // needed for critnib_insert()
416458

417459
void *addr = NULL;
418460
errno = 0;
419-
ret = os_mmap_aligned(NULL, size, alignment, page_size, protection, &addr);
461+
ret = os_mmap_aligned(NULL, size, alignment, page_size,
462+
os_provider->protection, os_provider->flag,
463+
os_provider->fd, &addr, &os_provider->size_fd);
420464
if (ret) {
421465
os_store_last_native_error(UMF_OS_RESULT_ERROR_ALLOC_FAILED, errno);
422466
LOG_PERR("memory allocation failed");
423-
424467
return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC;
425468
}
426469

@@ -430,7 +473,6 @@ static umf_result_t os_alloc(void *provider, size_t size, size_t alignment,
430473
LOG_ERR("allocated address 0x%llx is not aligned to %zu (0x%zx) "
431474
"bytes",
432475
(unsigned long long)addr, alignment, alignment);
433-
434476
goto err_unmap;
435477
}
436478

@@ -461,6 +503,16 @@ static umf_result_t os_alloc(void *provider, size_t size, size_t alignment,
461503
}
462504
}
463505

506+
if (os_provider->fd > 0) {
507+
ret = critnib_insert(os_provider->ptr_off, (uintptr_t)addr,
508+
(void *)(uintptr_t)fd_offset, 0 /* update */);
509+
if (ret) {
510+
LOG_DEBUG("inserting a value to the IPC cache failed (addr=%p, "
511+
"offset=%zu)",
512+
addr, fd_offset);
513+
}
514+
}
515+
464516
*resultPtr = addr;
465517

466518
return UMF_RESULT_SUCCESS;
@@ -475,6 +527,12 @@ static umf_result_t os_free(void *provider, void *ptr, size_t size) {
475527
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
476528
}
477529

530+
os_memory_provider_t *os_provider = (os_memory_provider_t *)provider;
531+
532+
if (os_provider->fd > 0) {
533+
critnib_remove(os_provider->ptr_off, (uintptr_t)ptr);
534+
}
535+
478536
errno = 0;
479537
int ret = os_munmap(ptr, size);
480538
// 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 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: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
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

1315
#include "provider_os_memory_internal.h"
@@ -32,6 +34,49 @@ umf_result_t os_translate_mem_protection_one_flag(unsigned in_protection,
3234
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
3335
}
3436

37+
umf_result_t os_translate_memory_flag(unsigned in_flag, unsigned *out_flag) {
38+
switch (in_flag) {
39+
case UMF_MEM_MAP_PRIVATE:
40+
*out_flag = MAP_PRIVATE;
41+
return UMF_RESULT_SUCCESS;
42+
case UMF_MEM_MAP_SHARED:
43+
#ifdef __APPLE__
44+
return UMF_RESULT_ERROR_NOT_SUPPORTED; // not supported on MacOSX
45+
#else
46+
*out_flag = MAP_SHARED;
47+
return UMF_RESULT_SUCCESS;
48+
#endif
49+
}
50+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
51+
}
52+
53+
int os_create_memory_fd(unsigned flag) {
54+
// fd is created only for UMF_MEM_MAP_SHARED
55+
if (flag != UMF_MEM_MAP_SHARED) {
56+
return 0;
57+
}
58+
59+
#ifdef __APPLE__
60+
return 0; // ignored on MacOSX
61+
#else
62+
#ifdef __NR_memfd_secret // SYS_memfd_secret is supported since Linux 5.14
63+
return syscall(SYS_memfd_secret, 0);
64+
#else // SYS_memfd_create is supported since Linux 3.17, glibc 2.27
65+
return syscall(SYS_memfd_create, "fd_name", 0);
66+
#endif /* __NR_memfd_secret */
67+
#endif /* __APPLE__ */
68+
}
69+
70+
int os_set_file_size(int fd, size_t size) {
71+
#ifdef __APPLE__
72+
(void)fd; // unused
73+
(void)size; // unused
74+
return 0; // ignored on MacOSX
75+
#else
76+
return ftruncate(fd, size);
77+
#endif /* __APPLE__ */
78+
}
79+
3580
umf_result_t os_translate_mem_protection_flags(unsigned in_protection,
3681
unsigned *out_protection) {
3782
// translate protection - combination of 'umf_mem_protection_flags_t' flags
@@ -51,13 +96,19 @@ static int os_translate_purge_advise(umf_purge_advise_t advise) {
5196
return -1;
5297
}
5398

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);
99+
void *os_mmap(void *hint_addr, size_t length, int prot, int flag, int fd,
100+
size_t fd_offset) {
101+
fd = (fd == 0) ? -1 : fd;
102+
if (fd == -1) {
103+
// MAP_ANONYMOUS - the mapping is not backed by any file
104+
flag |= MAP_ANONYMOUS;
105+
}
106+
107+
void *ptr = mmap(hint_addr, length, prot, flag, fd, fd_offset);
58108
if (ptr == MAP_FAILED) {
59109
return NULL;
60110
}
111+
61112
return ptr;
62113
}
63114

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 flag) {
69+
(void)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)