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 | |
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 | |
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 | |
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 | |
149 | static void pfprint(void) |
150 | { |
151 | if (Vmregion->meth.meth == VM_MTPROFILE) |
152 | vmprofile(Vmregion, _Vmpffd); |
153 | } |
154 | |
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 | |
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 | */ |
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 | |
260 | void free(reg void * data) |
261 | { |
262 | VMFLINIT(); |
263 | (void) (*Vmregion->meth.freef) (Vmregion, data); |
264 | } |
265 | |
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 | |
273 | void cfree(reg void * data) |
274 | { |
275 | VMFLINIT(); |
276 | (void) (*Vmregion->meth.freef) (Vmregion, data); |
277 | } |
278 | |
279 | void *memalign(reg size_t align, reg size_t size) |
280 | { |
281 | VMFLINIT(); |
282 | return (*Vmregion->meth.alignf) (Vmregion, size, align); |
283 | } |
284 | |
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 |
305 | int mallopt(int cmd, int value) |
306 | { |
307 | VMFLINIT(); |
308 | return 0; |
309 | } |
310 | #endif |
311 | |
312 | #ifdef HAVE_MALLINFO |
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 |
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 | |