Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'wifi_clean' into 'master'
[simgrid.git] / src / xbt / mmalloc / mm_legacy.c
1 /* Copyright (c) 2010-2022. The SimGrid Team. All rights reserved.          */
2
3 /* This program is free software; you can redistribute it and/or modify it
4  * under the terms of the license (GNU LGPL) which comes with this package. */
5
6 /* Redefine the classical malloc/free/realloc functions so that they fit well in the mmalloc framework */
7 #define _GNU_SOURCE
8
9 #include "mmprivate.h"
10
11 #include <dlfcn.h>
12 #include <math.h>
13 #include <stdlib.h>
14
15 /* ***** Whether to use `mmalloc` of the underlying malloc ***** */
16
17 static int __malloc_use_mmalloc;
18 int mmalloc_pagesize = 0;
19
20 int malloc_use_mmalloc(void)
21 {
22   return __malloc_use_mmalloc;
23 }
24
25 /* ***** Current heap ***** */
26
27 /* The mmalloc() package can use a single implicit malloc descriptor
28    for mmalloc/mrealloc/mfree operations which do not supply an explicit
29    descriptor.  This allows mmalloc() to provide
30    backwards compatibility with the non-mmap'd version. */
31 xbt_mheap_t __mmalloc_default_mdp = NULL;
32
33 /* The heap we are currently using. */
34 static xbt_mheap_t __mmalloc_current_heap = NULL;
35
36 xbt_mheap_t mmalloc_get_current_heap(void)
37 {
38   return __mmalloc_current_heap;
39 }
40
41 /* Override the malloc-like functions if MC is activated at compile time */
42 /* ***** Temporary allocator
43  *
44  * This is used before we have found the real malloc implementation with dlsym.
45  */
46
47 static size_t fake_alloc_index;
48 static uint64_t buffer[mmalloc_preinit_buffer_size];
49 uint64_t* mmalloc_preinit_buffer = buffer;
50
51 /* Fake implementations, they are used to fool dlsym:
52  * dlsym used calloc and falls back to some other mechanism
53  * if this fails.
54  */
55 static void* mm_fake_malloc(size_t n)
56 {
57   mmalloc_preinit_buffer = buffer;
58
59   // How many uint64_t do w need?
60   size_t count = n / sizeof(uint64_t);
61   if (n % sizeof(uint64_t))
62     count++;
63   // Check that we have enough available memory:
64   if (fake_alloc_index + count >= mmalloc_preinit_buffer_size) {
65     puts("mmalloc is not initialized yet, but the static buffer used as malloc replacement is already exhausted. "
66          "Please increase `mmalloc_preinit_buffer_size` in mm_legacy.c\n");
67     exit(127);
68   }
69   // Allocate it:
70   uint64_t* res = buffer + fake_alloc_index;
71   fake_alloc_index += count;
72   return res;
73 }
74
75 static void* mm_fake_calloc(size_t nmemb, size_t size)
76 {
77   // This is fresh .bss data, we don't need to clear it:
78   size_t n = nmemb * size;
79   return mm_fake_malloc(n);
80 }
81
82 static void* mm_fake_realloc(XBT_ATTRIB_UNUSED void* p, size_t s)
83 {
84   return mm_fake_malloc(s);
85 }
86
87 static void mm_fake_free(XBT_ATTRIB_UNUSED void* p)
88 {
89   // Nothing to do
90 }
91
92 /* Function signatures for the main malloc functions: */
93 typedef void* (*mm_malloc_t)(size_t size);
94 typedef void  (*mm_free_t)(void*);
95 typedef void* (*mm_calloc_t)(size_t nmemb, size_t size);
96 typedef void* (*mm_realloc_t)(void *ptr, size_t size);
97
98 /* Function pointers to the real/next implementations: */
99 static mm_malloc_t mm_real_malloc;
100 static mm_free_t mm_real_free;
101 static mm_calloc_t mm_real_calloc;
102 static mm_realloc_t mm_real_realloc;
103
104 static int mm_initializing;
105 static int mm_initialized;
106
107 /** Constructor functions used to initialize the malloc implementation
108  */
109 XBT_ATTRIB_CONSTRUCTOR(101) static void mm_legacy_constructor()
110 {
111   if (mm_initialized)
112     return;
113   mm_initializing = 1;
114   __malloc_use_mmalloc = getenv(MC_ENV_SOCKET_FD) ? 1 : 0;
115   if (__malloc_use_mmalloc) {
116     __mmalloc_current_heap = mmalloc_preinit();
117   } else {
118 #if HAVE_DLFUNC
119     mm_real_realloc  = (void *(*)(void *, size_t))dlfunc(RTLD_NEXT, "realloc");
120     mm_real_malloc   = (void *(*)(size_t))dlfunc(RTLD_NEXT, "malloc");
121     mm_real_free     = (void (*)(void *))dlfunc(RTLD_NEXT, "free");
122     mm_real_calloc   = (void *(*)(size_t, size_t))dlfunc(RTLD_NEXT, "calloc");
123 #else
124     mm_real_realloc  = dlsym(RTLD_NEXT, "realloc");
125     mm_real_malloc   = dlsym(RTLD_NEXT, "malloc");
126     mm_real_free     = dlsym(RTLD_NEXT, "free");
127     mm_real_calloc   = dlsym(RTLD_NEXT, "calloc");
128 #endif
129   }
130   mmalloc_pagesize = getpagesize();
131
132   mm_initializing = 0;
133   mm_initialized = 1;
134 }
135
136 /* ***** malloc/free implementation
137  *
138  * They call either the underlying/native/RTLD_NEXT implementation (non MC mode)
139  * or the mm implementation (MC mode).
140  *
141  * If we are initializing the malloc subsystem, we call the fake/dummy `malloc`
142  * implementation. This is necessary because `dlsym` calls `malloc` and friends.
143  */
144
145 #define GET_HEAP() __mmalloc_current_heap
146
147 void *malloc(size_t n)
148 {
149   if (!mm_initialized) {
150     if (mm_initializing)
151       return mm_fake_malloc(n);
152     mm_legacy_constructor();
153   }
154
155   if (!__malloc_use_mmalloc) {
156     return mm_real_malloc(n);
157   }
158
159   xbt_mheap_t mdp = GET_HEAP();
160   if (!mdp)
161     return NULL;
162
163   return mmalloc(mdp, n);
164 }
165
166 void *calloc(size_t nmemb, size_t size)
167 {
168   if (!mm_initialized) {
169     if (mm_initializing)
170       return mm_fake_calloc(nmemb, size);
171     mm_legacy_constructor();
172   }
173
174   if (!__malloc_use_mmalloc) {
175     return mm_real_calloc(nmemb, size);
176   }
177
178   xbt_mheap_t mdp = GET_HEAP();
179   if (!mdp)
180     return NULL;
181
182   void *ret = mmalloc(mdp, nmemb*size);
183   // This was already done in the callee:
184   if(!(mdp->options & XBT_MHEAP_OPTION_MEMSET)) {
185     memset(ret, 0, nmemb * size);
186   }
187   return ret;
188 }
189
190 void *realloc(void *p, size_t s)
191 {
192   if (!mm_initialized) {
193     if (mm_initializing)
194       return mm_fake_realloc(p, s);
195     mm_legacy_constructor();
196   }
197
198   if (!__malloc_use_mmalloc) {
199     return mm_real_realloc(p, s);
200   }
201
202   xbt_mheap_t mdp = GET_HEAP();
203   if (!mdp)
204     return NULL;
205
206   return mrealloc(mdp, p, s);
207 }
208
209 void free(void *p)
210 {
211   if (!mm_initialized) {
212     if (mm_initializing)
213       return mm_fake_free(p);
214     mm_legacy_constructor();
215   }
216
217   if (!__malloc_use_mmalloc) {
218     mm_real_free(p);
219     return;
220   }
221
222   if (!p)
223     return;
224
225   xbt_mheap_t mdp = GET_HEAP();
226   mfree(mdp, p);
227 }