Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
7b946b57a4fc4119d90021a4eb29dbf77fec7c65
[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   LOCK(mdp);
164   void *ret = mmalloc(mdp, n);
165   UNLOCK(mdp);
166   return ret;
167 }
168
169 void *calloc(size_t nmemb, size_t size)
170 {
171   if (!mm_initialized) {
172     if (mm_initializing)
173       return mm_fake_calloc(nmemb, size);
174     mm_legacy_constructor();
175   }
176
177   if (!__malloc_use_mmalloc) {
178     return mm_real_calloc(nmemb, size);
179   }
180
181   xbt_mheap_t mdp = GET_HEAP();
182   if (!mdp)
183     return NULL;
184
185   LOCK(mdp);
186   void *ret = mmalloc(mdp, nmemb*size);
187   UNLOCK(mdp);
188   // This was already done in the callee:
189   if(!(mdp->options & XBT_MHEAP_OPTION_MEMSET)) {
190     memset(ret, 0, nmemb * size);
191   }
192   return ret;
193 }
194
195 void *realloc(void *p, size_t s)
196 {
197   if (!mm_initialized) {
198     if (mm_initializing)
199       return mm_fake_realloc(p, s);
200     mm_legacy_constructor();
201   }
202
203   if (!__malloc_use_mmalloc) {
204     return mm_real_realloc(p, s);
205   }
206
207   xbt_mheap_t mdp = GET_HEAP();
208   if (!mdp)
209     return NULL;
210
211   LOCK(mdp);
212   void* ret = mrealloc(mdp, p, s);
213   UNLOCK(mdp);
214   return ret;
215 }
216
217 void free(void *p)
218 {
219   if (!mm_initialized) {
220     if (mm_initializing)
221       return mm_fake_free(p);
222     mm_legacy_constructor();
223   }
224
225   if (!__malloc_use_mmalloc) {
226     mm_real_free(p);
227     return;
228   }
229
230   if (!p)
231     return;
232
233   xbt_mheap_t mdp = GET_HEAP();
234   LOCK(mdp);
235   mfree(mdp, p);
236   UNLOCK(mdp);
237 }