Logo AND Algorithmique Numérique Distribuée

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