1 /* $Id$ $Revision$ */
2 /* vim:set shiftwidth=4 ts=8: */
3
4 /*************************************************************************
5 * Copyright (c) 2011 AT&T Intellectual Property
6 * All rights reserved. This program and the accompanying materials
7 * are made available under the terms of the Eclipse Public License v1.0
8 * which accompanies this distribution, and is available at
9 * http://www.eclipse.org/legal/epl-v10.html
10 *
11 * Contributors: See CVS logs. Details at http://www.graphviz.org/
12 *************************************************************************/
13
14 #include "vmhdr.h"
15
16 #if _BLD_INSTRUMENT_ || cray
17 int _STUB_malloc;
18 #else
19
20 /* malloc compatibility functions.
21 ** These are aware of debugging/profiling and driven by the environment variables:
22 ** VMETHOD: select an allocation method by name.
23 **
24 ** VMPROFILE: if is a file name, write profile data to it.
25 ** VMTRACE: if is a file name, write trace data to it.
26 ** The pattern %p in a file name will be replaced by the process ID.
27 **
28 ** VMDEBUG:
29 ** a: abort on any warning
30 ** [decimal]: period to check arena.
31 ** 0x[hexadecimal]: address to watch.
32 **
33 ** Written by Kiem-Phong Vo, kpv@research.att.com, 01/16/94.
34 */
35
36 #ifdef HAVE_STAT_H
37 #include <stat.h>
38 #else
39 #ifdef HAVE_SYS_STAT_H
40 #include <sys/stat.h>
41 #endif
42 #endif
43
44 #if defined(S_IRUSR)&&defined(S_IWUSR)&&defined(S_IRGRP)&&defined(S_IROTH)
45 #define CREAT_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
46 #else
47 #define CREAT_MODE 0644
48 #endif
49
50 #undef malloc
51 #undef free
52 #undef realloc
53 #undef calloc
54 #undef cfree
55 #undef memalign
56 #undef valloc
57
atou(char ** sp)58 static Vmulong_t atou(char **sp)
59 {
60 char *s = *sp;
61 Vmulong_t v = 0;
62
63 if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
64 for (s += 2; *s; ++s) {
65 if (*s >= '0' && *s <= '9')
66 v = (v << 4) + (*s - '0');
67 else if (*s >= 'a' && *s <= 'f')
68 v = (v << 4) + (*s - 'a') + 10;
69 else if (*s >= 'A' && *s <= 'F')
70 v = (v << 4) + (*s - 'A') + 10;
71 else
72 break;
73 }
74 } else {
75 for (; *s; ++s) {
76 if (*s >= '0' && *s <= '9')
77 v = v * 10 + (*s - '0');
78 else
79 break;
80 }
81 }
82
83 *sp = s;
84 return v;
85 }
86
87 static int _Vmflinit = 0;
88 static Vmulong_t _Vmdbcheck = 0;
89 static Vmulong_t _Vmdbtime = 0;
90 static int _Vmpffd = -1;
91 #define VMFLINIT() \
92 { if(!_Vmflinit) vmflinit(); \
93 if(_Vmdbcheck && (++_Vmdbtime % _Vmdbcheck) == 0 && \
94 Vmregion->meth.meth == VM_MTDEBUG) \
95 vmdbcheck(Vmregion); \
96 }
97
insertpid(char * begs,char * ends)98 static char *insertpid(char *begs, char *ends)
99 {
100 int pid;
101 char *s;
102
103 if ((pid = getpid()) < 0)
104 return NIL(char *);
105
106 s = ends;
107 do {
108 if (s == begs)
109 return NIL(char *);
110 *--s = '0' + pid % 10;
111 } while ((pid /= 10) > 0);
112 while (s < ends)
113 *begs++ = *s++;
114
115 return begs;
116 }
117
createfile(char * file)118 static int createfile(char *file)
119 {
120 char buf[1024];
121 char *next, *endb;
122
123 next = buf;
124 endb = buf + sizeof(buf);
125 while (*file) {
126 if (*file == '%') {
127 switch (file[1]) {
128 case 'p':
129 if (!(next = insertpid(next, endb)))
130 return -1;
131 file += 2;
132 break;
133 default:
134 goto copy;
135 }
136 } else {
137 copy:
138 *next++ = *file++;
139 }
140
141 if (next >= endb)
142 return -1;
143 }
144
145 *next = '\0';
146 return creat(buf, CREAT_MODE);
147 }
148
pfprint(void)149 static void pfprint(void)
150 {
151 if (Vmregion->meth.meth == VM_MTPROFILE)
152 vmprofile(Vmregion, _Vmpffd);
153 }
154
vmflinit(void)155 static int vmflinit(void)
156 {
157 char *env;
158 Vmalloc_t *vm;
159 int fd;
160 Vmulong_t addr;
161 char *file;
162 int line;
163
164 /* this must be done now to avoid any inadvertent recursion (more below) */
165 _Vmflinit = 1;
166 VMFILELINE(Vmregion, file, line);
167
168 /* if getenv() calls malloc(), this may not be caught by the eventual region */
169 vm = NIL(Vmalloc_t *);
170 if ((env = getenv("VMETHOD"))) {
171 if (strcmp(env, "Vmdebug") == 0 || strcmp(env, "vmdebug") == 0)
172 vm = vmopen(Vmdcsbrk, Vmdebug, 0);
173 else if (strcmp(env, "Vmprofile") == 0
174 || strcmp(env, "vmprofile") == 0)
175 vm = vmopen(Vmdcsbrk, Vmprofile, 0);
176 else if (strcmp(env, "Vmlast") == 0 || strcmp(env, "vmlast") == 0)
177 vm = vmopen(Vmdcsbrk, Vmlast, 0);
178 else if (strcmp(env, "Vmpool") == 0 || strcmp(env, "vmpool") == 0)
179 vm = vmopen(Vmdcsbrk, Vmpool, 0);
180 else if (strcmp(env, "Vmbest") == 0 || strcmp(env, "vmbest") == 0)
181 vm = Vmheap;
182 }
183
184 if ((!vm || vm->meth.meth == VM_MTDEBUG) &&
185 (env = getenv("VMDEBUG")) && env[0]) {
186 if (vm || (vm = vmopen(Vmdcsbrk, Vmdebug, 0))) {
187 reg int setcheck = 0;
188
189 while (*env) {
190 if (*env == 'a')
191 vmset(vm, VM_DBABORT, 1);
192
193 if (*env < '0' || *env > '9')
194 env += 1;
195 else if (env[0] == '0' && (env[1] == 'x' || env[1] == 'X')) {
196 if ((addr = atou(&env)) != 0)
197 vmdbwatch((void *) addr);
198 } else {
199 _Vmdbcheck = atou(&env);
200 setcheck = 1;
201 }
202 }
203 if (!setcheck)
204 _Vmdbcheck = 1;
205 }
206 }
207
208 if ((!vm || vm->meth.meth == VM_MTPROFILE) &&
209 (env = getenv("VMPROFILE")) && env[0]) {
210 _Vmpffd = createfile(env);
211 if (!vm)
212 vm = vmopen(Vmdcsbrk, Vmprofile, 0);
213 }
214
215 /* slip in the new region now so that malloc() will work fine */
216 if (vm)
217 Vmregion = vm;
218
219 /* turn on tracing if requested */
220 if ((env = getenv("VMTRACE")) && env[0] && (fd = createfile(env)) >= 0) {
221 vmset(Vmregion, VM_TRACE, 1);
222 vmtrace(fd);
223 }
224
225 /* make sure that profile data is output upon exiting */
226 if (vm && vm->meth.meth == VM_MTPROFILE) {
227 if (_Vmpffd < 0)
228 _Vmpffd = 2;
229 /* this may wind up calling malloc(), but region is ok now */
230 atexit(pfprint);
231 } else if (_Vmpffd >= 0) {
232 close(_Vmpffd);
233 _Vmpffd = -1;
234 }
235
236 /* reset file and line number to correct values for the call */
237 Vmregion->file = file;
238 Vmregion->line = line;
239
240 return 0;
241 }
242
malloc(reg size_t size)243 void *malloc(reg size_t size)
244 {
245 VMFLINIT();
246 return (*Vmregion->meth.allocf) (Vmregion, size);
247 }
248
249 /**
250 * @param data block to be reallocated
251 * @param size new size
252 */
realloc(reg void * data,reg size_t size)253 void *realloc(reg void * data, reg size_t size)
254 {
255 VMFLINIT();
256 return (*Vmregion->meth.resizef) (Vmregion, data, size,
257 VM_RSCOPY | VM_RSMOVE);
258 }
259
free(reg void * data)260 void free(reg void * data)
261 {
262 VMFLINIT();
263 (void) (*Vmregion->meth.freef) (Vmregion, data);
264 }
265
calloc(reg size_t n_obj,reg size_t s_obj)266 void *calloc(reg size_t n_obj, reg size_t s_obj)
267 {
268 VMFLINIT();
269 return (*Vmregion->meth.resizef) (Vmregion, NIL(void *),
270 n_obj * s_obj, VM_RSZERO);
271 }
272
cfree(reg void * data)273 void cfree(reg void * data)
274 {
275 VMFLINIT();
276 (void) (*Vmregion->meth.freef) (Vmregion, data);
277 }
278
memalign(reg size_t align,reg size_t size)279 void *memalign(reg size_t align, reg size_t size)
280 {
281 VMFLINIT();
282 return (*Vmregion->meth.alignf) (Vmregion, size, align);
283 }
284
valloc(reg size_t size)285 void *valloc(reg size_t size)
286 {
287 VMFLINIT();
288 GETPAGESIZE(_Vmpagesize);
289 return (*Vmregion->meth.alignf) (Vmregion, size, _Vmpagesize);
290 }
291
292 #ifdef HAVE_MALLOC_H
293
294 #define calloc ______calloc
295 #define free ______free
296 #define malloc ______malloc
297 #define realloc ______realloc
298
299 #include <malloc.h>
300
301 /* in Windows, this is a macro defined in malloc.h and not a function */
302 #undef alloca
303
304 #ifdef HAVE_MALLOPT
mallopt(int cmd,int value)305 int mallopt(int cmd, int value)
306 {
307 VMFLINIT();
308 return 0;
309 }
310 #endif
311
312 #ifdef HAVE_MALLINFO
mallinfo(void)313 struct mallinfo mallinfo(void)
314 {
315 Vmstat_t sb;
316 struct mallinfo mi;
317
318 VMFLINIT();
319 memset(&mi, 0, sizeof(mi));
320 if (vmstat(Vmregion, &sb) >= 0) {
321 mi.arena = sb.extent;
322 mi.ordblks = sb.n_busy + sb.n_free;
323 mi.uordblks = sb.s_busy;
324 mi.fordblks = sb.s_free;
325 }
326 return mi;
327 }
328 #endif
329
330 #ifdef HAVE_MSTATS
mstats(void)331 struct mstats mstats(void)
332 {
333 Vmstat_t sb;
334 struct mstats ms;
335
336 VMFLINIT();
337 memset(&ms, 0, sizeof(ms));
338 if (vmstat(Vmregion, &sb) >= 0) {
339 ms.bytes_total = sb.extent;
340 ms.chunks_used = sb.n_busy;
341 ms.bytes_used = sb.s_busy;
342 ms.chunks_free = sb.n_free;
343 ms.bytes_free = sb.s_free;
344 }
345 return ms;
346 }
347 #endif
348
349 #endif/* HAVE_MALLOC_H */
350
351 #endif /*_BLD_INSTRUMENT_ || cray*/
352