NewMadeleine

Documentation

« back to PM2 home.
nm_memalloc_helper.h
Go to the documentation of this file.
1/*
2 * NewMadeleine
3 * Copyright (C) 2025-2026 (see AUTHORS file)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at
8 * your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 */
15
16#include <stdio.h>
17#include <stdlib.h>
18#include <sys/mman.h>
19#include <errno.h>
20
21#ifndef MAP_HUGE_SHIFT
22/* If undefined, use default value. The 2MB page mmap is likely to fail on this architecture */
23#define MAP_HUGE_SHIFT 26
24#endif
25
26#define MAP_HUGE_2MB (21 << MAP_HUGE_SHIFT)
27#define HUGE_PAGE_2MB_SIZE (1 << 21)
28
29#define MAP_HUGE_1GB (30 << MAP_HUGE_SHIFT)
30#define HUGE_PAGE_1GB_SIZE (1 << 30)
31
32#define CHECK(rc,s) _memalloc_helper_check_and_exit((rc), __func__, __LINE__, (s))
33
43
44static inline void _memalloc_helper_check_and_exit(const int rc, const char*func, const int line, char*cmt)
45{
46 if (!rc)
47 {
48 fprintf(stderr, "# Error : %s at line %d in %s\n", cmt, line, func);
49 if (errno)
50 perror(NULL);
51 else
52 exit(EXIT_FAILURE);
53 }
54}
55
63static void*allocate_buffer(size_t size, alloc_type_t alloc_type)
64{
65 void*buffer;
66 switch(alloc_type)
67 {
68 case ALLOC_MALLOC:
69 {
70 buffer = malloc(size);
71 CHECK(buffer != NULL, "malloc failed");
72 }
73 break;
74 case ALLOC_CALLOC:
75 {
76 buffer = calloc(1, size);
77 CHECK(buffer != NULL, "malloc failed");
78 }
79 break;
80 case ALLOC_MEMALIGN:
81 {
82 const int ret = posix_memalign(&buffer, 64, size);
83 CHECK(ret == 0, "posix_memalign failed");
84 }
85 break;
86 case ALLOC_MMAP_4KB:
87 {
88 const size_t page_size = 4096;
89 const size_t alloc_size = (size / page_size + (size % page_size ? 1 : 0)) * page_size;
90 buffer = mmap(NULL, alloc_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
91 CHECK(buffer != MAP_FAILED, "mmap failed for 4kB page");
92 }
93 break;
94 case ALLOC_MMAP_2MB:
95 {
96 const size_t page_size = HUGE_PAGE_2MB_SIZE;
97 const size_t alloc_size = (size / page_size + (size % page_size ? 1 : 0)) * page_size;
98 buffer = mmap(NULL, alloc_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_HUGETLB | MAP_HUGE_2MB, -1, 0);
99 CHECK(buffer != MAP_FAILED, "mmap failed for 2 MB page");
100 }
101 break;
102 case ALLOC_MMAP_1GB:
103 {
104 const size_t page_size = HUGE_PAGE_1GB_SIZE;
105 const size_t alloc_size = (size / page_size + (size % page_size ? 1 : 0)) * page_size;
106 buffer = mmap(NULL, alloc_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_HUGETLB | MAP_HUGE_1GB, -1, 0);
107 CHECK(buffer != MAP_FAILED, "mmap failed for 1 GB page");
108 }
109 default:
110 CHECK(0, "Unknown alloc_type argument passed");
111 }
112 return buffer;
113}
114
120static void free_buffer(void*buffer, size_t size, alloc_type_t alloc_type)
121{
122 switch (alloc_type)
123 {
124 case ALLOC_MALLOC:
125 case ALLOC_CALLOC:
126 case ALLOC_MEMALIGN:
127 free(buffer);
128 break;
129 case ALLOC_MMAP_4KB:
130 {
131 const size_t page_size = 4096;
132 const size_t alloc_size = (size / page_size + (size % page_size ? 1 : 0)) * page_size;
133 CHECK(munmap(buffer, alloc_size ) == 0, "munmap 4kB page failed");
134 }
135 break;
136 case ALLOC_MMAP_2MB:
137 {
138 const size_t page_size = HUGE_PAGE_2MB_SIZE;
139 const size_t alloc_size = (size / page_size + (size % page_size ? 1 : 0)) * page_size;
140 CHECK(munmap(buffer, alloc_size ) == 0, "munmap 2MB page failed");
141 }
142 break;
143 case ALLOC_MMAP_1GB:
144 {
145 const size_t page_size = HUGE_PAGE_1GB_SIZE;
146 const size_t alloc_size = (size / page_size + (size % page_size ? 1 : 0)) * page_size;
147 CHECK(munmap(buffer, alloc_size ) == 0, "munmap 1GB page failed");
148 }
149 default:
150 CHECK(0, "Unknown alloc_type argument passed");
151 }
152}
static void * allocate_buffer(size_t size, alloc_type_t alloc_type)
Allocates a buffer with asked allocation method.
@ ALLOC_CALLOC
@ ALLOC_MALLOC
@ ALLOC_MEMALIGN
@ ALLOC_MMAP_4KB
@ ALLOC_MMAP_2MB
@ ALLOC_MMAP_1GB
#define MAP_HUGE_2MB
static void _memalloc_helper_check_and_exit(const int rc, const char *func, const int line, char *cmt)
#define HUGE_PAGE_1GB_SIZE
#define MAP_HUGE_1GB
static void free_buffer(void *buffer, size_t size, alloc_type_t alloc_type)
Release a buffer allocated with allocate_buffer()
#define HUGE_PAGE_2MB_SIZE
#define CHECK(rc, s)
nm_len_t size
size of the onsided data (not incuding target-side completion)