29
29
#include "ink_resource.h"
30
30
#include "ink_stack_trace.h"
32
volatile int64_t resource_allocated_mem = 0;
33
32
volatile int res_track_memory = RES_TRACK_MEMORY_DEFAULT;
37
#define FENCE_POST_SIZE 16
39
// TODO: Move this to ink_align.h
40
#define ADJUST(mem,x) (((char*) (mem)) + x)
41
// TODO: Use INK_ALIGN instead
42
#define ROUND(x,l) (((x) + ((l) - 1L)) & ~((l) - 1L))
45
#define MAKE_MAGIC(m) (((char*) (m)) - 1)
46
#define CHECK_MAGIC(m,c) ((char*) (m) == MAKE_MAGIC (c))
49
typedef struct ResMemInfo ResMemInfo;
50
typedef struct Resource Resource;
56
unsigned int fence_post:1;
61
static unsigned int res_hash(const char *s);
62
Resource *res_lookup(const char *path);
65
static const int res_extra_space = ROUND(sizeof(ResMemInfo), sizeof(double));
66
static volatile Resource *res_table[TSIZE];
68
static const char fence_post_pattern[FENCE_POST_SIZE] = {
69
(char) 0xde, (char) 0xad, (char) 0xbe, (char) 0xef,
70
(char) 0xde, (char) 0xad, (char) 0xbe, (char) 0xef,
71
(char) 0xde, (char) 0xad, (char) 0xbe, (char) 0xef,
72
(char) 0xde, (char) 0xad, (char) 0xbe, (char) 0xef,
76
volatile int res_zorch_mem = 0;
77
volatile int res_fence_post = 0;
79
#define res_memadd(_x_) \
80
ink_atomic_increment64(&resource_allocated_mem, (int64_t) (_x_));
82
#define res_memsub(_x_) \
83
ink_atomic_increment64(&resource_allocated_mem, (int64_t) -(_x_));
88
res_zorch_mem = (getenv("ZORCH_MEM") != NULL);
89
res_fence_post = (getenv("FENCE_POST") != NULL);
92
fprintf(stderr, "memory zorching enabled\n");
96
fprintf(stderr, "memory fence posting enabled\n");
102
static int dummy_var = _xres_init();
105
/* INKqa03012 - Digital OSF seems to issue some bad frees in
106
* the iostream destructor. These variables and the the exit_cb()
107
* let us know if exit has been called. If exit has been, called
108
* we will refrain from issuing warnings regarding bad frees
110
static int exit_called = 0;
116
static int unused = atexit(exit_cb);
119
/*-------------------------------------------------------------------------
120
-------------------------------------------------------------------------*/
122
#define res_inc(res,delta) \
123
ink_atomic_increment64 (&res->value, delta); \
126
#define res_check(res) \
127
if (res && !CHECK_MAGIC ((res)->magic, (res))) { \
128
fprintf (stderr, "FATAL: resource table is corrupt [%d]\n", __LINE__); \
132
/*-------------------------------------------------------------------------
133
-------------------------------------------------------------------------*/
137
res_hash(const char *s)
139
#if !defined(linux) && !defined(freebsd) && !defined(__i386__)
140
#define HASH_ONE(h,one) ((h << 3) + (one) + (h >> 29))
141
#define WORD_HAS_NULLBYTE(w) ((((w) - 0x01010101) ^ (w)) & 0x80808080)
146
ink_assert(!((uintptr_t) s & 3));
149
ibp = *(unsigned int *) s;
151
if (WORD_HAS_NULLBYTE(ibp)) {
157
*(unsigned int *) &t[0] = ibp;
160
h = HASH_ONE(h, *(unsigned int *) &t[0]);
163
*(unsigned int *) &t[0] = ibp;
165
h = HASH_ONE(h, *(unsigned int *) &t[0]);
168
h = HASH_ONE(h, ibp);
172
h = HASH_ONE(h, ibp);
178
#undef WORD_HAS_NULLBYTE
180
unsigned int h = 0, g;
184
if ((g = h & 0xf0000000))
185
h = (h ^ (g >> 24)) ^ g;
191
/*-------------------------------------------------------------------------
192
-------------------------------------------------------------------------*/
195
res_lookup(const char *path)
197
unsigned int hash_val;
201
hash_val = res_hash(path) % TSIZE;
204
old = (Resource *) res_table[hash_val];
209
if ((path == node->path) || (strcmp(path, node->path) == 0)) {
215
if (old == res_table[hash_val]) {
216
node = (Resource *) _xmalloc(sizeof(Resource), NULL);
217
node->magic = MAKE_MAGIC(node);
224
if (ink_atomic_cas_ptr((pvvoidp) & res_table[hash_val], old, node))
231
return NULL; // DEC compiler complains
235
/*-------------------------------------------------------------------------
236
-------------------------------------------------------------------------*/
239
res_stat(const char *path, int64_t value)
244
res = res_lookup(path);
254
#if defined(linux) || defined(freebsd)
255
static const int magic_array_offset = 0;
257
#error "I do not know about this platform."
261
/*-------------------------------------------------------------------------
262
-------------------------------------------------------------------------*/
265
_xcheck_fence_post(char *mem, unsigned int size)
267
if (memcmp(mem, fence_post_pattern, FENCE_POST_SIZE) != 0) {
270
if (memcmp(mem + size - FENCE_POST_SIZE, fence_post_pattern, FENCE_POST_SIZE) != 0) {
277
_xvalidate(void *ptr, char *file, int line)
281
info = (ResMemInfo *) ADJUST(ptr, -res_extra_space);
282
if (!CHECK_MAGIC(info->magic, info)) {
283
info = (ResMemInfo *) ADJUST(info, -magic_array_offset);
285
if (!CHECK_MAGIC(info->magic, info)) {
286
ink_debug_assert(!"bad pointer");
289
res_check(info->res);
291
char *mem = (char *) info;
293
if (info->fence_post) {
294
mem -= FENCE_POST_SIZE;
295
if (_xcheck_fence_post(mem, info->size + res_extra_space + FENCE_POST_SIZE * 2)) {
296
fprintf(stderr, "MEMORY: free: fence-post mangled [%s]\n", info->res ? info->res->path : "<unknown>");
303
/*-------------------------------------------------------------------------
304
-------------------------------------------------------------------------*/
310
// fprintf (stderr, "WARNING: freeing NULL pointer\n");
314
info = (ResMemInfo *) ADJUST(ptr, -res_extra_space);
315
if (!CHECK_MAGIC(info->magic, info)) {
316
info = (ResMemInfo *) ADJUST(info, -magic_array_offset);
319
if (CHECK_MAGIC(info->magic, info)) {
323
res_check(info->res);
324
res_inc(info->res, -((int64_t) info->size));
329
if (info->fence_post) {
330
mem -= FENCE_POST_SIZE;
331
if (_xcheck_fence_post(mem, info->size + res_extra_space + FENCE_POST_SIZE * 2)) {
332
fprintf(stderr, "MEMORY: free: fence-post mangled [%s]\n", info->res ? info->res->path : "<unknown>");
338
memset(info, 0x81, info->size + res_extra_space);
341
memset(info, 0, res_extra_space);
346
/* This is a bad free. Let it leak. Issue a
347
* warning if we are not in an exit routine
350
if (exit_called == 0) {
351
fprintf(stderr, "WARNING: freeing bad pointer\n");
352
ink_debug_assert(!"WARNING: freeing bad pointer");
359
_xfree_null(void *ptr)
365
/*-------------------------------------------------------------------------
366
-------------------------------------------------------------------------*/
369
_xmalloc(unsigned int size, const char *path)
376
extra = res_extra_space;
378
fence_post = res_fence_post;
381
extra += FENCE_POST_SIZE * 2;
384
mem = (char *) malloc(size + extra);
386
if (unlikely(mem == NULL)) {
387
fprintf(stderr, "FATAL: _xmalloc could not allocate %u + %u bytes [%s]\n",
388
size, extra, path ? path : "memory/anonymous");
394
memcpy(mem, fence_post_pattern, FENCE_POST_SIZE);
395
memcpy(mem + size + extra - FENCE_POST_SIZE, fence_post_pattern, FENCE_POST_SIZE);
396
mem += FENCE_POST_SIZE;
399
memset(mem, 0, res_extra_space);
401
info = (ResMemInfo *) mem;
402
info->magic = MAKE_MAGIC(mem);
404
info->fence_post = fence_post;
406
if (res_track_memory) {
407
info->res = res_stat(path, size);
408
res_check(info->res);
413
mem = mem + res_extra_space;
418
/*-------------------------------------------------------------------------
419
-------------------------------------------------------------------------*/
422
_xstrdup(const char *str, int64_t length, const char *path)
426
if (unlikely(str == NULL)) {
431
length = (int) strlen(str);
434
newstr = (char *) _xmalloc(length + 1, path);
435
strncpy(newstr, str, length);
436
newstr[length] = '\0';
441
/*-------------------------------------------------------------------------
442
-------------------------------------------------------------------------*/
445
_xrealloc(void *ptr, unsigned int size, const char *path)
448
return _xmalloc(size, path);
455
info = (ResMemInfo *) ADJUST(ptr, -res_extra_space);
456
if (!CHECK_MAGIC(info->magic, info)) {
457
info = (ResMemInfo *) ADJUST(info, -magic_array_offset);
461
res_check(info->res);
462
res_inc(info->res, -((int64_t) info->size));
466
extra = res_extra_space;
468
if (info->fence_post) {
469
mem -= FENCE_POST_SIZE;
470
if (_xcheck_fence_post(mem, info->size + res_extra_space + FENCE_POST_SIZE * 2)) {
471
fprintf(stderr, "MEMORY: realloc: fence-post mangled [%s] [%s]\n",
472
info->res ? info->res->path : "<unknown>", path);
477
memset(info, 0, res_extra_space);
479
fence_post = res_fence_post;
482
extra += FENCE_POST_SIZE * 2;
485
mem = (char *) realloc(mem, size + extra);
486
if (unlikely(mem == NULL)) {
487
fprintf(stderr, "FATAL: could not reallocate %u + %u bytes [%s]\n",
488
size, extra, path ? path : "memory/anonymous");
494
memcpy(mem, fence_post_pattern, FENCE_POST_SIZE);
495
memcpy(mem + size + extra - FENCE_POST_SIZE, fence_post_pattern, FENCE_POST_SIZE);
496
mem += FENCE_POST_SIZE;
499
memset(mem, 0, res_extra_space);
501
info = (ResMemInfo *) mem;
502
info->magic = MAKE_MAGIC(mem);
504
info->fence_post = fence_post;
506
if (res_track_memory) {
507
info->res = res_stat(path, size);
508
res_check(info->res);
513
mem = mem + res_extra_space;
519
/*-------------------------------------------------------------------------
520
-------------------------------------------------------------------------*/
523
_xtrack(void *ptr, const char *path)
525
if (unlikely(ptr == NULL)) {
526
fprintf(stderr, "WARNING: cannot track NULL pointer\n");
531
info = (ResMemInfo *) ADJUST(ptr, -res_extra_space);
532
if (!CHECK_MAGIC(info->magic, info)) {
533
info = (ResMemInfo *) ADJUST(info, -magic_array_offset);
536
if (!CHECK_MAGIC(info->magic, info)) {
541
res_check(info->res);
542
res_inc(info->res, -((int64_t) info->size));
545
if (res_track_memory) {
546
info->res = res_stat(path, info->size);
547
res_check(info->res);
557
xdump_snap_baseline()
562
for (i = 0; i < TSIZE; i++) {
563
res = (Resource *) res_table[i];
566
res->baseline = res->value;
573
xdump_to_file_baseline_rel(FILE * fp)
579
struct timeval timestamp;
580
char time_string[32], *time_str;
583
ink_gethrtimeofday(×tamp, NULL);
584
time_str = ctime((time_t *) & timestamp.tv_sec);
586
length_to_write = squid_timestamp_to_buf(time_string, 32, timestamp.tv_sec, timestamp.tv_usec);
587
time_string[length_to_write] = '\0';
589
fprintf(fp, "PID: %d %s %s", getpid(), time_string, time_str);
590
fprintf(fp, " value | delta | location\n");
591
fprintf(fp, "rel. to base| | \n");
592
fprintf(fp, "------------|------------|-----------------------------------------------\n");
594
for (i = 0; i < TSIZE; i++) {
595
res = (Resource *) res_table[i];
599
value = res->value - res->baseline;
600
diff = res->value - res->snapshot;
602
fprintf(fp, " % 10d | % 10d | %s\n", (int) value, (int) diff, res->path);
605
res->snapshot = res->value;
611
/*-------------------------------------------------------------------------
612
-------------------------------------------------------------------------*/
615
xdump_to_file(FILE * fp)
621
struct timeval timestamp;
622
char time_string[32], *time_str;
625
ink_gethrtimeofday(×tamp, NULL);
626
time_str = ctime((time_t *) & timestamp.tv_sec);
628
length_to_write = squid_timestamp_to_buf(time_string, 32, timestamp.tv_sec, timestamp.tv_usec);
629
time_string[length_to_write] = '\0';
631
fprintf(fp, "PID: %d %s %s", getpid(), time_string, time_str);
632
fprintf(fp, " value | delta | location\n");
633
fprintf(fp, "------------|------------|-----------------------------------------------\n");
635
for (i = 0; i < TSIZE; i++) {
636
res = (Resource *) res_table[i];
639
if (strncmp(res->path, "memory/IOBuffer/", strlen("memory/IOBuffer/"))
642
diff = value - res->snapshot;
644
fprintf(fp, " % 10d | % 10d | %s\n", (int) value, (int) diff, res->path);
646
res->snapshot = res->value;
652
fprintf(fp, " value | delta | location\n");
653
fprintf(fp, "------------|------------|-----------------------------------------------\n");
654
for (i = 0; i < TSIZE; i++) {
655
res = (Resource *) res_table[i];
658
if (strncmp(res->path, "memory/IOBuffer/", strlen("memory/IOBuffer/"))
661
diff = value - res->snapshot;
663
fprintf(fp, " % 10d | % 10d | %s\n", (int) value, (int) diff, res->path);
665
res->snapshot = res->value;
672
/*-------------------------------------------------------------------------
673
-------------------------------------------------------------------------*/
678
ink_stack_trace_dump();
679
xdump_to_file(stderr);
682
/*-------------------------------------------------------------------------
683
-------------------------------------------------------------------------*/
691
for (i = 0; i < TSIZE; i++) {
692
res = (Resource *) res_table[i];
695
res->snapshot = res->value;
702
#else /* TRACK_MEMORY */
704
34
/*-------------------------------------------------------------------------
705
35
-------------------------------------------------------------------------*/
714
_xfree_null(void *mem)
723
_xmalloc(unsigned int size, const char *path)
726
return ink_malloc(size);
730
_xrealloc(void *ptr, unsigned int size, const char *path)
733
return ink_realloc(ptr, size);
737
37
_xstrdup(const char *str, int length, const char *path)