]>
Commit | Line | Data |
---|---|---|
be335c22 | 1 | |
30a4f2a8 | 2 | /* |
ef9b7ce6 | 3 | * $Id: util.c,v 1.56 1998/03/08 04:42:25 wessels Exp $ |
30a4f2a8 | 4 | * |
5 | * DEBUG: | |
6 | * AUTHOR: Harvest Derived | |
7 | * | |
42c04c16 | 8 | * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ |
30a4f2a8 | 9 | * -------------------------------------------------------- |
10 | * | |
11 | * Squid is the result of efforts by numerous individuals from the | |
12 | * Internet community. Development is led by Duane Wessels of the | |
13 | * National Laboratory for Applied Network Research and funded by | |
14 | * the National Science Foundation. | |
15 | * | |
16 | * This program is free software; you can redistribute it and/or modify | |
17 | * it under the terms of the GNU General Public License as published by | |
18 | * the Free Software Foundation; either version 2 of the License, or | |
19 | * (at your option) any later version. | |
20 | * | |
21 | * This program is distributed in the hope that it will be useful, | |
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
24 | * GNU General Public License for more details. | |
25 | * | |
26 | * You should have received a copy of the GNU General Public License | |
27 | * along with this program; if not, write to the Free Software | |
28 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
29 | * | |
30 | */ | |
c8f322d5 | 31 | #define _etext etext |
7fc9f088 | 32 | |
30a4f2a8 | 33 | /* |
34 | * Copyright (c) 1994, 1995. All rights reserved. | |
35 | * | |
36 | * The Harvest software was developed by the Internet Research Task | |
37 | * Force Research Group on Resource Discovery (IRTF-RD): | |
38 | * | |
39 | * Mic Bowman of Transarc Corporation. | |
40 | * Peter Danzig of the University of Southern California. | |
41 | * Darren R. Hardy of the University of Colorado at Boulder. | |
42 | * Udi Manber of the University of Arizona. | |
43 | * Michael F. Schwartz of the University of Colorado at Boulder. | |
44 | * Duane Wessels of the University of Colorado at Boulder. | |
45 | * | |
46 | * This copyright notice applies to software in the Harvest | |
47 | * ``src/'' directory only. Users should consult the individual | |
48 | * copyright notices in the ``components/'' subdirectories for | |
49 | * copyright information about other software bundled with the | |
50 | * Harvest source code distribution. | |
51 | * | |
52 | * TERMS OF USE | |
53 | * | |
54 | * The Harvest software may be used and re-distributed without | |
55 | * charge, provided that the software origin and research team are | |
56 | * cited in any use of the system. Most commonly this is | |
57 | * accomplished by including a link to the Harvest Home Page | |
58 | * (http://harvest.cs.colorado.edu/) from the query page of any | |
59 | * Broker you deploy, as well as in the query result pages. These | |
60 | * links are generated automatically by the standard Broker | |
61 | * software distribution. | |
62 | * | |
63 | * The Harvest software is provided ``as is'', without express or | |
64 | * implied warranty, and with no support nor obligation to assist | |
65 | * in its use, correction, modification or enhancement. We assume | |
66 | * no liability with respect to the infringement of copyrights, | |
67 | * trade secrets, or any patents, and are not responsible for | |
68 | * consequential damages. Proper use of the Harvest software is | |
69 | * entirely the responsibility of the user. | |
70 | * | |
71 | * DERIVATIVE WORKS | |
72 | * | |
73 | * Users may make derivative works from the Harvest software, subject | |
74 | * to the following constraints: | |
75 | * | |
76 | * - You must include the above copyright notice and these | |
77 | * accompanying paragraphs in all forms of derivative works, | |
78 | * and any documentation and other materials related to such | |
79 | * distribution and use acknowledge that the software was | |
80 | * developed at the above institutions. | |
81 | * | |
82 | * - You must notify IRTF-RD regarding your distribution of | |
83 | * the derivative work. | |
84 | * | |
85 | * - You must clearly notify users that your are distributing | |
86 | * a modified version and not the original Harvest software. | |
87 | * | |
88 | * - Any derivative product is also subject to these copyright | |
89 | * and use restrictions. | |
90 | * | |
91 | * Note that the Harvest software is NOT in the public domain. We | |
92 | * retain copyright, as specified above. | |
93 | * | |
94 | * HISTORY OF FREE SOFTWARE STATUS | |
95 | * | |
96 | * Originally we required sites to license the software in cases | |
97 | * where they were going to build commercial products/services | |
98 | * around Harvest. In June 1995 we changed this policy. We now | |
99 | * allow people to use the core Harvest software (the code found in | |
100 | * the Harvest ``src/'' directory) for free. We made this change | |
101 | * in the interest of encouraging the widest possible deployment of | |
102 | * the technology. The Harvest software is really a reference | |
103 | * implementation of a set of protocols and formats, some of which | |
104 | * we intend to standardize. We encourage commercial | |
105 | * re-implementations of code complying to this set of standards. | |
106 | */ | |
0d94e9fe | 107 | |
30a4f2a8 | 108 | #include "config.h" |
109 | ||
110 | #if HAVE_STDIO_H | |
090089c4 | 111 | #include <stdio.h> |
30a4f2a8 | 112 | #endif |
113 | #if HAVE_STDLIB_H | |
090089c4 | 114 | #include <stdlib.h> |
30a4f2a8 | 115 | #endif |
116 | #if HAVE_STRING_H | |
090089c4 | 117 | #include <string.h> |
30a4f2a8 | 118 | #endif |
673d7a4d | 119 | #if HAVE_CTYPE_H |
120 | #include <ctype.h> | |
121 | #endif | |
30a4f2a8 | 122 | #if HAVE_UNISTD_H |
090089c4 | 123 | #include <unistd.h> |
30a4f2a8 | 124 | #endif |
88738790 | 125 | #if HAVE_GNUMALLLOC_H |
126 | #include <gnumalloc.h> | |
127 | #elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_) | |
090089c4 | 128 | #include <malloc.h> |
983061ed | 129 | #endif |
30a4f2a8 | 130 | #if HAVE_ERRNO_H |
090089c4 | 131 | #include <errno.h> |
30a4f2a8 | 132 | #endif |
02922e76 | 133 | #if HAVE_MATH_H |
134 | #include <math.h> | |
135 | #endif | |
090089c4 | 136 | |
473471f2 | 137 | #include "util.h" |
5e2e108b | 138 | #include "snprintf.h" |
30a4f2a8 | 139 | |
f5b8bbc4 | 140 | void (*failure_notify) (const char *) = NULL; |
090089c4 | 141 | static char msg[128]; |
142 | ||
35570558 | 143 | extern int sys_nerr; |
35570558 | 144 | |
36a97e19 | 145 | #if MEM_GEN_TRACE |
146 | ||
3213655a | 147 | static FILE *tracefp = NULL; |
36a97e19 | 148 | |
149 | void | |
150 | log_trace_init(char *fn) | |
151 | { | |
3213655a | 152 | tracefp = fopen(fn, "a+"); |
153 | if (!tracefp) { | |
154 | perror("log_trace_init"); | |
155 | exit(1); | |
156 | } | |
36a97e19 | 157 | } |
158 | ||
159 | void | |
160 | log_trace_done() | |
161 | { | |
3213655a | 162 | fclose(tracefp); |
163 | tracefp = NULL; | |
36a97e19 | 164 | } |
165 | ||
166 | #endif | |
167 | ||
30a4f2a8 | 168 | #if XMALLOC_STATISTICS |
169 | #define DBG_MAXSIZE (1024*1024) | |
170 | #define DBG_GRAIN (16) | |
171 | #define DBG_MAXINDEX (DBG_MAXSIZE/DBG_GRAIN) | |
172 | #define DBG_INDEX(sz) (sz<DBG_MAXSIZE?(sz+DBG_GRAIN-1)/DBG_GRAIN:DBG_MAXINDEX) | |
173 | static int malloc_sizes[DBG_MAXINDEX + 1]; | |
174 | static int dbg_stat_init = 0; | |
175 | ||
36a97e19 | 176 | |
b8d8561b | 177 | static void |
0673c0ba | 178 | stat_init(void) |
30a4f2a8 | 179 | { |
180 | int i; | |
181 | for (i = 0; i <= DBG_MAXINDEX; i++) | |
182 | malloc_sizes[i] = 0; | |
183 | dbg_stat_init = 1; | |
184 | } | |
185 | ||
b8d8561b | 186 | static int |
187 | malloc_stat(int sz) | |
30a4f2a8 | 188 | { |
189 | if (!dbg_stat_init) | |
190 | stat_init(); | |
191 | return malloc_sizes[DBG_INDEX(sz)] += 1; | |
192 | } | |
193 | ||
b8d8561b | 194 | void |
5d3ec1a4 | 195 | malloc_statistics(void (*func) (int, int, void *), void *data) |
30a4f2a8 | 196 | { |
197 | int i; | |
198 | for (i = 0; i <= DBG_MAXSIZE; i += DBG_GRAIN) | |
199 | func(i, malloc_sizes[DBG_INDEX(i)], data); | |
200 | } | |
201 | #endif /* XMALLOC_STATISTICS */ | |
202 | ||
090089c4 | 203 | |
45e93040 | 204 | |
59272939 | 205 | #if XMALLOC_TRACE |
33ab18e8 | 206 | char *xmalloc_file = ""; |
207 | int xmalloc_line = 0; | |
208 | char *xmalloc_func = ""; | |
209 | static int xmalloc_count = 0; | |
210 | int xmalloc_trace = 0; /* Enable with -m option */ | |
211 | size_t xmalloc_total = 0; | |
59272939 | 212 | #undef xmalloc |
213 | #undef xfree | |
214 | #undef xxfree | |
215 | #undef xrealloc | |
216 | #undef xcalloc | |
217 | #undef xstrdup | |
218 | #endif | |
219 | ||
1d012b4c | 220 | #if XMALLOC_DEBUG |
68b468e5 | 221 | #define DBG_ARRY_SZ (1<<10) |
222 | #define DBG_ARRY_BKTS (1<<8) | |
33ab18e8 | 223 | static void *(*malloc_ptrs)[DBG_ARRY_SZ]; |
8c6551ac | 224 | static int malloc_size[DBG_ARRY_BKTS][DBG_ARRY_SZ]; |
59272939 | 225 | #if XMALLOC_TRACE |
33ab18e8 | 226 | static char *malloc_file[DBG_ARRY_BKTS][DBG_ARRY_SZ]; |
227 | static short malloc_line[DBG_ARRY_BKTS][DBG_ARRY_SZ]; | |
59272939 | 228 | static int malloc_count[DBG_ARRY_BKTS][DBG_ARRY_SZ]; |
229 | #endif | |
45e93040 | 230 | static int dbg_initd = 0; |
45e93040 | 231 | |
b8d8561b | 232 | static void |
0673c0ba | 233 | check_init(void) |
45e93040 | 234 | { |
33ab18e8 | 235 | int B = 0, I = 0; |
236 | /* calloc the ptrs so that we don't see them when hunting lost memory */ | |
237 | malloc_ptrs = calloc(DBG_ARRY_BKTS, sizeof(*malloc_ptrs)); | |
68b468e5 | 238 | for (B = 0; B < DBG_ARRY_BKTS; B++) { |
30a4f2a8 | 239 | for (I = 0; I < DBG_ARRY_SZ; I++) { |
240 | malloc_ptrs[B][I] = NULL; | |
241 | malloc_size[B][I] = 0; | |
59272939 | 242 | #if XMALLOC_TRACE |
243 | malloc_file[B][I] = NULL; | |
244 | malloc_line[B][I] = 0; | |
245 | malloc_count[B][I] = 0; | |
246 | #endif | |
30a4f2a8 | 247 | } |
45e93040 | 248 | } |
249 | dbg_initd = 1; | |
250 | } | |
251 | ||
b8d8561b | 252 | static void |
253 | check_free(void *s) | |
45e93040 | 254 | { |
33ab18e8 | 255 | int B, I; |
8c6551ac | 256 | B = (((int) s) >> 4) & 0xFF; |
45e93040 | 257 | for (I = 0; I < DBG_ARRY_SZ; I++) { |
8c6551ac | 258 | if (malloc_ptrs[B][I] != s) |
45e93040 | 259 | continue; |
8c6551ac | 260 | malloc_ptrs[B][I] = NULL; |
261 | malloc_size[B][I] = 0; | |
59272939 | 262 | #if XMALLOC_TRACE |
33ab18e8 | 263 | malloc_file[B][I] = NULL; |
264 | malloc_line[B][I] = 0; | |
265 | malloc_count[B][I] = 0; | |
59272939 | 266 | #endif |
45e93040 | 267 | break; |
268 | } | |
269 | if (I == DBG_ARRY_SZ) { | |
25347664 | 270 | snprintf(msg, 128, "xfree: ERROR: s=%p not found!", s); |
45e93040 | 271 | (*failure_notify) (msg); |
272 | } | |
273 | } | |
274 | ||
b8d8561b | 275 | static void |
276 | check_malloc(void *p, size_t sz) | |
45e93040 | 277 | { |
33ab18e8 | 278 | void *P, *Q; |
279 | int B, I; | |
45e93040 | 280 | if (!dbg_initd) |
281 | check_init(); | |
7fc9f088 | 282 | B = (((int) p) >> 4) & 0xFF; |
45e93040 | 283 | for (I = 0; I < DBG_ARRY_SZ; I++) { |
33ab18e8 | 284 | if (!(P = malloc_ptrs[B][I])) |
45e93040 | 285 | continue; |
8c6551ac | 286 | Q = P + malloc_size[B][I]; |
45e93040 | 287 | if (P <= p && p < Q) { |
25347664 | 288 | snprintf(msg, 128, "xmalloc: ERROR: p=%p falls in P=%p+%d", |
8c6551ac | 289 | p, P, malloc_size[B][I]); |
45e93040 | 290 | (*failure_notify) (msg); |
291 | } | |
292 | } | |
293 | for (I = 0; I < DBG_ARRY_SZ; I++) { | |
33ab18e8 | 294 | if (malloc_ptrs[B][I]) |
45e93040 | 295 | continue; |
8c6551ac | 296 | malloc_ptrs[B][I] = p; |
297 | malloc_size[B][I] = (int) sz; | |
59272939 | 298 | #if XMALLOC_TRACE |
299 | malloc_file[B][I] = xmalloc_file; | |
300 | malloc_line[B][I] = xmalloc_line; | |
301 | malloc_count[B][I] = xmalloc_count; | |
302 | #endif | |
45e93040 | 303 | break; |
304 | } | |
305 | if (I == DBG_ARRY_SZ) | |
306 | (*failure_notify) ("xmalloc: debug out of array space!"); | |
307 | } | |
308 | #endif | |
309 | ||
59272939 | 310 | #if XMALLOC_TRACE && !HAVE_MALLOCBLKSIZE |
5e5cb0fc | 311 | size_t |
312 | xmallocblksize(void *p) | |
7fc9f088 | 313 | { |
33ab18e8 | 314 | int B, I; |
7fc9f088 | 315 | B = (((int) p) >> 4) & 0xFF; |
316 | for (I = 0; I < DBG_ARRY_SZ; I++) { | |
317 | if (malloc_ptrs[B][I] == p) | |
318 | return malloc_size[B][I]; | |
319 | } | |
320 | return 0; | |
321 | } | |
322 | #endif | |
323 | ||
59272939 | 324 | #ifdef XMALLOC_TRACE |
325 | static char * | |
326 | malloc_file_name(void *p) | |
327 | { | |
33ab18e8 | 328 | int B, I; |
59272939 | 329 | B = (((int) p) >> 4) & 0xFF; |
330 | for (I = 0; I < DBG_ARRY_SZ; I++) { | |
331 | if (malloc_ptrs[B][I] == p) | |
332 | return malloc_file[B][I]; | |
333 | } | |
334 | return 0; | |
335 | } | |
336 | int | |
337 | malloc_line_number(void *p) | |
338 | { | |
33ab18e8 | 339 | int B, I; |
59272939 | 340 | B = (((int) p) >> 4) & 0xFF; |
341 | for (I = 0; I < DBG_ARRY_SZ; I++) { | |
342 | if (malloc_ptrs[B][I] == p) | |
343 | return malloc_line[B][I]; | |
344 | } | |
345 | return 0; | |
346 | } | |
347 | int | |
348 | malloc_number(void *p) | |
349 | { | |
33ab18e8 | 350 | int B, I; |
59272939 | 351 | B = (((int) p) >> 4) & 0xFF; |
352 | for (I = 0; I < DBG_ARRY_SZ; I++) { | |
353 | if (malloc_ptrs[B][I] == p) | |
354 | return malloc_count[B][I]; | |
355 | } | |
356 | return 0; | |
357 | } | |
b8d8561b | 358 | static void |
33ab18e8 | 359 | xmalloc_show_trace(void *p, int sign) |
68b468e5 | 360 | { |
e5f4e1b0 | 361 | int statMemoryAccounted(); |
0e473d70 | 362 | static size_t last_total = 0, last_accounted = 0, last_mallinfo = 0; |
0e473d70 | 363 | size_t accounted = statMemoryAccounted(); |
5e5cb0fc | 364 | size_t mi = 0; |
7fc9f088 | 365 | size_t sz; |
5e5cb0fc | 366 | #if HAVE_MALLINFO |
367 | struct mallinfo mp = mallinfo(); | |
368 | mi = mp.uordblks + mp.usmblks + mp.hblkhd; | |
369 | #endif | |
370 | sz = xmallocblksize(p) * sign; | |
33ab18e8 | 371 | xmalloc_total += sz; |
372 | xmalloc_count += sign > 0; | |
373 | if (xmalloc_trace) { | |
374 | fprintf(stderr, "%c%8p size=%5d/%d acc=%5d/%d mallinfo=%5d/%d %s:%d %s", | |
375 | sign > 0 ? '+' : '-', p, | |
376 | (int) xmalloc_total - last_total, (int) xmalloc_total, | |
377 | (int) accounted - last_accounted, (int) accounted, | |
378 | (int) mi - last_mallinfo, (int) mi, | |
379 | xmalloc_file, xmalloc_line, xmalloc_func); | |
380 | if (sign < 0) | |
381 | fprintf(stderr, " (%d %s:%d)\n", malloc_number(p), malloc_file_name(p), malloc_line_number(p)); | |
382 | else | |
383 | fprintf(stderr, " %d\n", xmalloc_count); | |
384 | } | |
385 | last_total = xmalloc_total; | |
0e473d70 | 386 | last_accounted = accounted; |
387 | last_mallinfo = mi; | |
68b468e5 | 388 | } |
7ce875eb | 389 | |
390 | short malloc_refs[DBG_ARRY_BKTS][DBG_ARRY_SZ]; | |
33ab18e8 | 391 | #define XMALLOC_LEAK_ALIGN (4) |
7ce875eb | 392 | static void |
393 | xmalloc_scan_region(void *start, int size, int depth) | |
33ab18e8 | 394 | { |
395 | int B, I; | |
396 | char *ptr = start; | |
397 | char *end = ptr + size - XMALLOC_LEAK_ALIGN; | |
7ce875eb | 398 | static int sum = 0; |
33ab18e8 | 399 | while (ptr <= end) { |
400 | void *p = *(void **) ptr; | |
401 | if (p && p != start) { | |
402 | B = (((int) p) >> 4) & 0xFF; | |
403 | for (I = 0; I < DBG_ARRY_SZ; I++) { | |
404 | if (malloc_ptrs[B][I] == p) { | |
7ce875eb | 405 | if (!malloc_refs[B][I]++) { |
406 | /* A new reference */ | |
407 | fprintf(stderr, "%*s%p %s:%d size %d allocation %d\n", | |
408 | depth, "", | |
409 | malloc_ptrs[B][I], malloc_file[B][I], | |
410 | malloc_line[B][I], malloc_size[B][I], | |
411 | malloc_count[B][I]); | |
412 | sum += malloc_size[B][I]; | |
413 | xmalloc_scan_region(malloc_ptrs[B][I], malloc_size[B][I], depth + 1); | |
414 | if (depth == 0) { | |
415 | if (sum != malloc_size[B][I]) | |
416 | fprintf(stderr, "=== %d bytes\n", sum); | |
417 | sum = 0; | |
418 | } | |
419 | #if XMALLOC_SHOW_ALL_REFERENCES | |
420 | } else { | |
421 | /* We have already scanned this pointer... */ | |
422 | fprintf(stderr, "%*s%p %s:%d size %d allocation %d ... (%d)\n", | |
423 | depth * 2, "", | |
424 | malloc_ptrs[B][I], malloc_file[B][I], | |
425 | malloc_line[B][I], malloc_size[B][I], | |
426 | malloc_count[B][I], malloc_refs[B][I]); | |
427 | #endif | |
428 | } | |
33ab18e8 | 429 | } |
430 | } | |
431 | } | |
432 | ptr += XMALLOC_LEAK_ALIGN; | |
433 | } | |
33ab18e8 | 434 | } |
7ce875eb | 435 | |
33ab18e8 | 436 | void |
437 | xmalloc_find_leaks(void) | |
438 | { | |
439 | int B, I; | |
33ab18e8 | 440 | int leak_sum = 0; |
c8f322d5 | 441 | |
7ce875eb | 442 | extern void _etext; |
443 | fprintf(stderr, "----- Memory map ----\n"); | |
444 | xmalloc_scan_region(&_etext, (void *) sbrk(0) - (void *) &_etext, 0); | |
33ab18e8 | 445 | for (B = 0; B < DBG_ARRY_BKTS; B++) { |
446 | for (I = 0; I < DBG_ARRY_SZ; I++) { | |
447 | if (malloc_ptrs[B][I] && malloc_refs[B][I] == 0) { | |
448 | /* Found a leak... */ | |
449 | fprintf(stderr, "Leak found: %p", malloc_ptrs[B][I]); | |
450 | fprintf(stderr, " %s", malloc_file[B][I]); | |
451 | fprintf(stderr, ":%d", malloc_line[B][I]); | |
7ce875eb | 452 | fprintf(stderr, " size %d", malloc_size[B][I]); |
453 | fprintf(stderr, " allocation %d\n", malloc_count[B][I]); | |
33ab18e8 | 454 | leak_sum += malloc_size[B][I]; |
455 | } | |
456 | } | |
457 | } | |
458 | if (leak_sum) { | |
459 | fprintf(stderr, "Total leaked memory: %d\n", leak_sum); | |
460 | } else { | |
461 | fprintf(stderr, "No memory leaks detected\n"); | |
462 | } | |
33ab18e8 | 463 | fprintf(stderr, "----------------------\n"); |
464 | } | |
59272939 | 465 | #endif /* XMALLOC_TRACE */ |
68b468e5 | 466 | |
090089c4 | 467 | /* |
468 | * xmalloc() - same as malloc(3). Used for portability. | |
469 | * Never returns NULL; fatal on error. | |
470 | */ | |
b8d8561b | 471 | void * |
472 | xmalloc(size_t sz) | |
090089c4 | 473 | { |
474 | static void *p; | |
475 | ||
476 | if (sz < 1) | |
477 | sz = 1; | |
36a97e19 | 478 | |
090089c4 | 479 | if ((p = malloc(sz)) == NULL) { |
480 | if (failure_notify) { | |
25347664 | 481 | snprintf(msg, 128, "xmalloc: Unable to allocate %d bytes!\n", |
090089c4 | 482 | (int) sz); |
483 | (*failure_notify) (msg); | |
484 | } else { | |
485 | perror("malloc"); | |
486 | } | |
487 | exit(1); | |
488 | } | |
1d012b4c | 489 | #if XMALLOC_DEBUG |
45e93040 | 490 | check_malloc(p, sz); |
30a4f2a8 | 491 | #endif |
492 | #if XMALLOC_STATISTICS | |
493 | malloc_stat(sz); | |
68b468e5 | 494 | #endif |
59272939 | 495 | #if XMALLOC_TRACE |
33ab18e8 | 496 | xmalloc_show_trace(p, 1); |
36a97e19 | 497 | #endif |
498 | #if MEM_GEN_TRACE | |
3213655a | 499 | if (tracefp) |
500 | fprintf(tracefp, "m:%d:%p\n", sz, p); | |
45e93040 | 501 | #endif |
090089c4 | 502 | return (p); |
503 | } | |
504 | ||
505 | /* | |
506 | * xfree() - same as free(3). Will not call free(3) if s == NULL. | |
507 | */ | |
b8d8561b | 508 | void |
509 | xfree(void *s) | |
090089c4 | 510 | { |
59272939 | 511 | #if XMALLOC_TRACE |
33ab18e8 | 512 | xmalloc_show_trace(s, -1); |
7fc9f088 | 513 | #endif |
36a97e19 | 514 | |
7fc9f088 | 515 | #if XMALLOC_DEBUG |
516 | check_free(s); | |
45e93040 | 517 | #endif |
518 | if (s != NULL) | |
090089c4 | 519 | free(s); |
36a97e19 | 520 | #if MEM_GEN_TRACE |
3213655a | 521 | if (tracefp && s) |
522 | fprintf(tracefp, "f:%p\n", s); | |
36a97e19 | 523 | #endif |
45e93040 | 524 | } |
525 | ||
526 | /* xxfree() - like xfree(), but we already know s != NULL */ | |
b8d8561b | 527 | void |
528 | xxfree(void *s) | |
45e93040 | 529 | { |
59272939 | 530 | #if XMALLOC_TRACE |
33ab18e8 | 531 | xmalloc_show_trace(s, -1); |
7fc9f088 | 532 | #endif |
533 | #if XMALLOC_DEBUG | |
534 | check_free(s); | |
45e93040 | 535 | #endif |
536 | free(s); | |
36a97e19 | 537 | #if MEM_GEN_TRACE |
3213655a | 538 | if (tracefp && s) |
539 | fprintf(tracefp, "f:%p\n", s); | |
36a97e19 | 540 | #endif |
090089c4 | 541 | } |
542 | ||
543 | /* | |
544 | * xrealloc() - same as realloc(3). Used for portability. | |
545 | * Never returns NULL; fatal on error. | |
546 | */ | |
b8d8561b | 547 | void * |
548 | xrealloc(void *s, size_t sz) | |
090089c4 | 549 | { |
550 | static void *p; | |
551 | ||
59272939 | 552 | #if XMALLOC_TRACE |
33ab18e8 | 553 | xmalloc_show_trace(s, -1); |
68b468e5 | 554 | #endif |
555 | ||
090089c4 | 556 | if (sz < 1) |
557 | sz = 1; | |
3213655a | 558 | #if XMALLOC_DEBUG |
559 | if (s != NULL) | |
560 | check_free(s); | |
561 | #endif | |
090089c4 | 562 | if ((p = realloc(s, sz)) == NULL) { |
563 | if (failure_notify) { | |
25347664 | 564 | snprintf(msg, 128, "xrealloc: Unable to reallocate %d bytes!\n", |
090089c4 | 565 | (int) sz); |
566 | (*failure_notify) (msg); | |
567 | } else { | |
568 | perror("realloc"); | |
569 | } | |
570 | exit(1); | |
571 | } | |
1d012b4c | 572 | #if XMALLOC_DEBUG |
ef9b7ce6 | 573 | fprintf(stderr, "realloc: ``mallocing'' %p\n", s); |
45e93040 | 574 | check_malloc(p, sz); |
30a4f2a8 | 575 | #endif |
576 | #if XMALLOC_STATISTICS | |
577 | malloc_stat(sz); | |
68b468e5 | 578 | #endif |
59272939 | 579 | #if XMALLOC_TRACE |
33ab18e8 | 580 | xmalloc_show_trace(p, 1); |
71a17702 | 581 | #endif |
582 | #if MEM_GEN_TRACE | |
3213655a | 583 | if (tracefp) /* new ptr, old ptr, new size */ |
584 | fprintf(tracefp, "r:%p:%p:%d\n", p, s, sz); | |
45e93040 | 585 | #endif |
090089c4 | 586 | return (p); |
587 | } | |
588 | ||
589 | /* | |
590 | * xcalloc() - same as calloc(3). Used for portability. | |
591 | * Never returns NULL; fatal on error. | |
592 | */ | |
b8d8561b | 593 | void * |
594 | xcalloc(int n, size_t sz) | |
090089c4 | 595 | { |
596 | static void *p; | |
597 | ||
598 | if (n < 1) | |
599 | n = 1; | |
600 | if (sz < 1) | |
601 | sz = 1; | |
602 | if ((p = calloc(n, sz)) == NULL) { | |
603 | if (failure_notify) { | |
25347664 | 604 | snprintf(msg, 128, "xcalloc: Unable to allocate %d blocks of %d bytes!\n", |
090089c4 | 605 | (int) n, (int) sz); |
606 | (*failure_notify) (msg); | |
607 | } else { | |
608 | perror("xcalloc"); | |
609 | } | |
610 | exit(1); | |
611 | } | |
1d012b4c | 612 | #if XMALLOC_DEBUG |
45e93040 | 613 | check_malloc(p, sz * n); |
30a4f2a8 | 614 | #endif |
615 | #if XMALLOC_STATISTICS | |
616 | malloc_stat(sz); | |
68b468e5 | 617 | #endif |
59272939 | 618 | #if XMALLOC_TRACE |
33ab18e8 | 619 | xmalloc_show_trace(p, 1); |
36a97e19 | 620 | #endif |
621 | #if MEM_GEN_TRACE | |
3213655a | 622 | if (tracefp) |
623 | fprintf(tracefp, "c:%d:%d:%p\n", n, sz, p); | |
45e93040 | 624 | #endif |
090089c4 | 625 | return (p); |
626 | } | |
627 | ||
628 | /* | |
629 | * xstrdup() - same as strdup(3). Used for portability. | |
630 | * Never returns NULL; fatal on error. | |
631 | */ | |
b8d8561b | 632 | char * |
0ee4272b | 633 | xstrdup(const char *s) |
090089c4 | 634 | { |
635 | static char *p = NULL; | |
30a4f2a8 | 636 | size_t sz; |
090089c4 | 637 | |
638 | if (s == NULL) { | |
639 | if (failure_notify) { | |
640 | (*failure_notify) ("xstrdup: tried to dup a NULL pointer!\n"); | |
641 | } else { | |
642 | fprintf(stderr, "xstrdup: tried to dup a NULL pointer!\n"); | |
643 | } | |
644 | exit(1); | |
645 | } | |
3213655a | 646 | sz = strlen(s) + 1; |
cb69b4c7 | 647 | p = xmalloc(sz); |
648 | memcpy(p, s, sz); /* copy string, including terminating character */ | |
649 | return p; | |
090089c4 | 650 | } |
651 | ||
090089c4 | 652 | /* |
4d38fc7e | 653 | * xstrerror() - strerror() wrapper |
090089c4 | 654 | */ |
0ee4272b | 655 | const char * |
0673c0ba | 656 | xstrerror(void) |
090089c4 | 657 | { |
35570558 | 658 | static char xstrerror_buf[BUFSIZ]; |
35570558 | 659 | if (errno < 0 || errno >= sys_nerr) |
090089c4 | 660 | return ("Unknown"); |
25347664 | 661 | snprintf(xstrerror_buf, BUFSIZ, "(%d) %s", errno, strerror(errno)); |
35570558 | 662 | return xstrerror_buf; |
090089c4 | 663 | } |
664 | ||
d591088d | 665 | #if NOT_NEEDED |
75cf00f4 | 666 | /* |
667 | * xbstrerror with argument for late notification */ | |
668 | ||
669 | const char * | |
670 | xbstrerror(int err) | |
671 | { | |
672 | static char xbstrerror_buf[BUFSIZ]; | |
673 | if (err < 0 || err >= sys_nerr) | |
6a54c60e | 674 | return ("Unknown"); |
25347664 | 675 | snprintf(xbstrerror_buf, BUFSIZ, "(%d) %s", err, strerror(err)); |
75cf00f4 | 676 | return xbstrerror_buf; |
677 | } | |
d591088d | 678 | #endif |
75cf00f4 | 679 | |
b8d8561b | 680 | void |
681 | Tolower(char *q) | |
673d7a4d | 682 | { |
683 | char *s = q; | |
684 | while (*s) { | |
b8d8561b | 685 | *s = tolower((unsigned char) *s); |
686 | s++; | |
673d7a4d | 687 | } |
688 | } | |
9d90e665 | 689 | |
690 | int | |
691 | tvSubMsec(struct timeval t1, struct timeval t2) | |
692 | { | |
693 | return (t2.tv_sec - t1.tv_sec) * 1000 + | |
6759a5fb | 694 | (t2.tv_usec - t1.tv_usec) / 1000; |
9d90e665 | 695 | } |
d5aa0e3b | 696 | |
88738790 | 697 | int |
698 | tvSubUsec(struct timeval t1, struct timeval t2) | |
699 | { | |
700 | return (t2.tv_sec - t1.tv_sec) * 1000000 + | |
701 | (t2.tv_usec - t1.tv_usec); | |
702 | } | |
703 | ||
260e56a3 | 704 | double |
705 | tvSubDsec(struct timeval t1, struct timeval t2) | |
706 | { | |
707 | return (double) (t2.tv_sec - t1.tv_sec) + | |
708 | (double) (t2.tv_usec - t1.tv_usec) / 1000000.0; | |
709 | } | |
710 | ||
d5aa0e3b | 711 | /* |
712 | * xstrncpy() - similar to strncpy(3) but terminates string | |
cb69b4c7 | 713 | * always with '\0' if (n != 0 and dst != NULL), |
714 | * and doesn't do padding | |
d5aa0e3b | 715 | */ |
716 | char * | |
717 | xstrncpy(char *dst, const char *src, size_t n) | |
718 | { | |
cb69b4c7 | 719 | if (!n || !dst) |
c1764328 | 720 | return dst; |
cb69b4c7 | 721 | if (src) |
722 | while (--n != 0 && *src != '\0') | |
723 | *dst++ = *src++; | |
c1764328 | 724 | *dst = '\0'; |
d5aa0e3b | 725 | return dst; |
726 | } | |
cb69b4c7 | 727 | |
728 | /* returns the number of leading white spaces in str; handy in skipping ws */ | |
729 | size_t | |
730 | xcountws(const char *str) | |
731 | { | |
732 | size_t count = 0; | |
733 | if (str) { | |
734 | while (isspace(*str)) { | |
735 | str++; | |
736 | count++; | |
737 | } | |
738 | } | |
739 | return count; | |
740 | } | |
7021844c | 741 | |
742 | /* somewhat safer calculation of %s */ | |
743 | double | |
744 | xpercent(double part, double whole) | |
745 | { | |
746 | return xdiv(100 * part, whole); | |
747 | } | |
748 | ||
02922e76 | 749 | int |
750 | xpercentInt(double part, double whole) | |
751 | { | |
ef9b7ce6 | 752 | return (int) rint(xpercent(part, whole)); |
02922e76 | 753 | } |
754 | ||
755 | ||
7021844c | 756 | /* somewhat safer division */ |
757 | double | |
758 | xdiv(double nom, double denom) | |
759 | { | |
760 | return (denom != 0.0) ? nom / denom : -1.0; | |
761 | } |