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
17int _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
58static 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
87static int _Vmflinit = 0;
88static Vmulong_t _Vmdbcheck = 0;
89static Vmulong_t _Vmdbtime = 0;
90static 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
98static 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
118static 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
149static void pfprint(void)
150{
151 if (Vmregion->meth.meth == VM_MTPROFILE)
152 vmprofile(Vmregion, _Vmpffd);
153}
154
155static 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
243void *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 */
253void *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
260void free(reg void * data)
261{
262 VMFLINIT();
263 (void) (*Vmregion->meth.freef) (Vmregion, data);
264}
265
266void *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
273void cfree(reg void * data)
274{
275 VMFLINIT();
276 (void) (*Vmregion->meth.freef) (Vmregion, data);
277}
278
279void *memalign(reg size_t align, reg size_t size)
280{
281 VMFLINIT();
282 return (*Vmregion->meth.alignf) (Vmregion, size, align);
283}
284
285void *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
305int mallopt(int cmd, int value)
306{
307 VMFLINIT();
308 return 0;
309}
310#endif
311
312#ifdef HAVE_MALLINFO
313struct 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
331struct 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