Logo AND Algorithmique Numérique Distribuée

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