~clint-fewbar/ubuntu/precise/squid3/ignore-sighup-early

« back to all changes in this revision

Viewing changes to src/cbdata.cc

  • Committer: Bazaar Package Importer
  • Author(s): Luigi Gangitano
  • Date: 2006-11-11 10:32:06 UTC
  • Revision ID: james.westby@ubuntu.com-20061111103206-f3p0r9g0vq44rp3r
Tags: upstream-3.0.PRE5
ImportĀ upstreamĀ versionĀ 3.0.PRE5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
/*
 
3
 * $Id: cbdata.cc,v 1.75 2006/09/03 21:05:20 hno Exp $
 
4
 *
 
5
 * DEBUG: section 45    Callback Data Registry
 
6
 * ORIGINAL AUTHOR: Duane Wessels
 
7
 * Modified by Moez Mahfoudh (08/12/2000)
 
8
 * History added by Robert Collins (2002-10-25)
 
9
 *
 
10
 * SQUID Web Proxy Cache          http://www.squid-cache.org/
 
11
 * ----------------------------------------------------------
 
12
 *
 
13
 *  Squid is the result of efforts by numerous individuals from
 
14
 *  the Internet community; see the CONTRIBUTORS file for full
 
15
 *  details.   Many organizations have provided support for Squid's
 
16
 *  development; see the SPONSORS file for full details.  Squid is
 
17
 *  Copyrighted (C) 2001 by the Regents of the University of
 
18
 *  California; see the COPYRIGHT file for full details.  Squid
 
19
 *  incorporates software developed and/or copyrighted by other
 
20
 *  sources; see the CREDITS file for full details.
 
21
 *
 
22
 *  This program is free software; you can redistribute it and/or modify
 
23
 *  it under the terms of the GNU General Public License as published by
 
24
 *  the Free Software Foundation; either version 2 of the License, or
 
25
 *  (at your option) any later version.
 
26
 *  
 
27
 *  This program is distributed in the hope that it will be useful,
 
28
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
29
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
30
 *  GNU General Public License for more details.
 
31
 *  
 
32
 *  You should have received a copy of the GNU General Public License
 
33
 *  along with this program; if not, write to the Free Software
 
34
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
 
35
 *
 
36
 */
 
37
 
 
38
/*
 
39
 * These routines manage a set of registered callback data pointers.
 
40
 * One of the easiest ways to make Squid coredump is to issue a 
 
41
 * callback to for some data structure which has previously been
 
42
 * freed.  With these routines, we register (add) callback data
 
43
 * pointers, lock them just before registering the callback function,
 
44
 * validate them before issuing the callback, and then free them
 
45
 * when finished.
 
46
 */
 
47
 
 
48
#include "cbdata.h"
 
49
#include "CacheManager.h"
 
50
#include "Store.h"
 
51
#if CBDATA_DEBUG
 
52
#include "Stack.h"
 
53
#endif
 
54
#include "Generic.h"
 
55
 
 
56
#if WITH_VALGRIND
 
57
#define HASHED_CBDATA 1
 
58
#endif
 
59
 
 
60
static int cbdataCount = 0;
 
61
#if CBDATA_DEBUG
 
62
dlink_list cbdataEntries;
 
63
#endif
 
64
 
 
65
#if CBDATA_DEBUG
 
66
 
 
67
class CBDataCall
 
68
{
 
69
 
 
70
public:
 
71
    CBDataCall (char const *callLabel, char const *aFile, int aLine) : label(callLabel), file(aFile), line(aLine){}
 
72
 
 
73
    char const *label;
 
74
    char const *file;
 
75
    int line;
 
76
};
 
77
 
 
78
#endif
 
79
 
 
80
#define OFFSET_OF(TYPE, MEMBER) ((size_t) &(((TYPE) *)0)->(MEMBER))
 
81
 
 
82
class cbdata
 
83
{
 
84
    /* TODO: examine making cbdata templated on this - so we get type
 
85
     * safe access to data - RBC 20030902 */
 
86
public:
 
87
#if HASHED_CBDATA
 
88
    hash_link hash;     // Must be first
 
89
#endif
 
90
 
 
91
#if CBDATA_DEBUG
 
92
 
 
93
    void dump(StoreEntry *)const;
 
94
#endif
 
95
 
 
96
#if !HASHED_CBDATA
 
97
    void *operator new(size_t size, void *where);
 
98
    void operator delete(void *where, void *where2);
 
99
#else
 
100
    MEMPROXY_CLASS(cndata);
 
101
#endif
 
102
 
 
103
    ~cbdata();
 
104
    int valid;
 
105
    int locks;
 
106
    cbdata_type type;
 
107
#if CBDATA_DEBUG
 
108
 
 
109
    void addHistory(char const *label, char const *file, int line)
 
110
    {
 
111
        if (calls.size() > 1000)
 
112
            return;
 
113
 
 
114
        calls.push_back(new CBDataCall(label, file, line));
 
115
    }
 
116
 
 
117
    dlink_node link;
 
118
    const char *file;
 
119
    int line;
 
120
    Stack<CBDataCall*> calls;
 
121
#endif
 
122
 
 
123
    /* cookie used while debugging */
 
124
    long cookie;
 
125
    void check(int line) const {assert(cookie == ((long)this ^ Cookie));}
 
126
    static const long Cookie;
 
127
 
 
128
#if !HASHED_CBDATA
 
129
    size_t dataSize() const { return sizeof(data);}
 
130
    static long MakeOffset();
 
131
    static const long Offset;
 
132
    /* MUST be the last per-instance member */
 
133
    void *data;
 
134
#endif
 
135
 
 
136
};
 
137
 
 
138
const long cbdata::Cookie((long)0xDEADBEEF);
 
139
#if !HASHED_CBDATA
 
140
const long cbdata::Offset(MakeOffset());
 
141
 
 
142
void *
 
143
cbdata::operator new(size_t size, void *where)
 
144
{
 
145
    // assert (size == sizeof(cbdata));
 
146
    return where;
 
147
}
 
148
 
 
149
void
 
150
cbdata::operator delete(void *where, void *where2)
 
151
{
 
152
    /* Only ever invoked when placement new throws
 
153
     * an exception. Used to prevent an incorrect
 
154
     * free.
 
155
     */
 
156
}
 
157
 
 
158
long
 
159
cbdata::MakeOffset()
 
160
{
 
161
    cbdata *zero = (cbdata *)0L;
 
162
    void **dataOffset = &zero->data;
 
163
    return (long)dataOffset;
 
164
}
 
165
#else
 
166
MEMPROXY_CLASS_INLINE(cbdata)
 
167
#endif
 
168
 
 
169
static OBJH cbdataDump;
 
170
#ifdef CBDATA_DEBUG
 
171
static OBJH cbdataDumpHistory;
 
172
#endif
 
173
 
 
174
struct CBDataIndex
 
175
{
 
176
    MemAllocator *pool;
 
177
    FREE *free_func;
 
178
}
 
179
 
 
180
*cbdata_index = NULL;
 
181
int cbdata_types = 0;
 
182
 
 
183
#if HASHED_CBDATA
 
184
static hash_table *cbdata_htable = NULL;
 
185
 
 
186
static int
 
187
cbdata_cmp(const void *p1, const void *p2)
 
188
{
 
189
    return (char *) p1 - (char *) p2;
 
190
}
 
191
 
 
192
static unsigned int
 
193
cbdata_hash(const void *p, unsigned int mod)
 
194
{
 
195
    return ((unsigned long) p >> 8) % mod;
 
196
}
 
197
#endif
 
198
 
 
199
 
 
200
cbdata::~cbdata()
 
201
{
 
202
#if CBDATA_DEBUG
 
203
    CBDataCall *aCall;
 
204
 
 
205
    while ((aCall = calls.pop()))
 
206
        delete aCall;
 
207
 
 
208
#endif
 
209
 
 
210
    FREE *free_func = cbdata_index[type].free_func;
 
211
 
 
212
#if HASHED_CBDATA
 
213
    void *p = hash.key;
 
214
#else
 
215
    void *p = &data;
 
216
#endif
 
217
 
 
218
    if (free_func)
 
219
        free_func(p);
 
220
}
 
221
 
 
222
static void
 
223
cbdataInternalInitType(cbdata_type type, const char *name, int size, FREE * free_func)
 
224
{
 
225
    char *label;
 
226
    assert (type == cbdata_types + 1);
 
227
 
 
228
    cbdata_index = (CBDataIndex *)xrealloc(cbdata_index, (type + 1) * sizeof(*cbdata_index));
 
229
    memset(&cbdata_index[type], 0, sizeof(*cbdata_index));
 
230
    cbdata_types = type;
 
231
 
 
232
    label = (char *)xmalloc(strlen(name) + 20);
 
233
 
 
234
    snprintf(label, strlen(name) + 20, "cbdata %s (%d)", name, (int) type);
 
235
 
 
236
#if !HASHED_CBDATA
 
237
    assert((size_t)cbdata::Offset == (sizeof(cbdata) - ((cbdata *)NULL)->dataSize()));
 
238
    size += cbdata::Offset;
 
239
#endif
 
240
 
 
241
    cbdata_index[type].pool = memPoolCreate(label, size);
 
242
 
 
243
    cbdata_index[type].free_func = free_func;
 
244
 
 
245
#if HASHED_CBDATA
 
246
    if (!cbdata_htable)
 
247
        cbdata_htable = hash_create(cbdata_cmp, 1 << 12, cbdata_hash);
 
248
#endif
 
249
}
 
250
 
 
251
cbdata_type
 
252
cbdataInternalAddType(cbdata_type type, const char *name, int size, FREE * free_func)
 
253
{
 
254
    if (type)
 
255
        return type;
 
256
 
 
257
    type = (cbdata_type)(cbdata_types + 1);
 
258
 
 
259
    cbdataInternalInitType(type, name, size, free_func);
 
260
 
 
261
    return type;
 
262
}
 
263
 
 
264
void
 
265
cbdataRegisterWithCacheManager(CacheManager & manager)
 
266
{
 
267
    manager.registerAction("cbdata",
 
268
                           "Callback Data Registry Contents",
 
269
                           cbdataDump, 0, 1);
 
270
#if CBDATA_DEBUG
 
271
 
 
272
    manager.registerAction("cbdatahistory",
 
273
                           "Detailed call history for all current cbdata contents",
 
274
                           cbdataDumpHistory, 0, 1);
 
275
#endif
 
276
}
 
277
 
 
278
void *
 
279
#if CBDATA_DEBUG
 
280
cbdataInternalAllocDbg(cbdata_type type, const char *file, int line)
 
281
#else
 
282
cbdataInternalAlloc(cbdata_type type)
 
283
#endif
 
284
{
 
285
    cbdata *c;
 
286
    void *p;
 
287
    assert(type > 0 && type <= cbdata_types);
 
288
    /* placement new: the pool alloc gives us cbdata + user type memory space
 
289
     * and we init it with cbdata at the start of it
 
290
     */
 
291
#if HASHED_CBDATA
 
292
    c = new cbdata;
 
293
    p = cbdata_index[type].pool->alloc();
 
294
    c->hash.key = p;
 
295
    hash_join(cbdata_htable, &c->hash);
 
296
#else
 
297
    c = new (cbdata_index[type].pool->alloc()) cbdata;
 
298
    p = (void *)&c->data;
 
299
#endif
 
300
 
 
301
    c->type = type;
 
302
    c->valid = 1;
 
303
    c->locks = 0;
 
304
    c->cookie = (long) c ^ cbdata::Cookie;
 
305
    cbdataCount++;
 
306
#if CBDATA_DEBUG
 
307
 
 
308
    c->file = file;
 
309
    c->line = line;
 
310
    c->calls = Stack<CBDataCall *> ();
 
311
    c->addHistory("Alloc", file, line);
 
312
    dlinkAdd(c, &c->link, &cbdataEntries);
 
313
    debug(45, 3) ("cbdataAlloc: %p %s:%d\n", p, file, line);
 
314
#endif
 
315
 
 
316
    return p;
 
317
}
 
318
 
 
319
void *
 
320
#if CBDATA_DEBUG
 
321
cbdataInternalFreeDbg(void *p, const char *file, int line)
 
322
#else
 
323
cbdataInternalFree(void *p)
 
324
#endif
 
325
{
 
326
    cbdata *c;
 
327
#if HASHED_CBDATA
 
328
    c = (cbdata *) hash_lookup(cbdata_htable, p);
 
329
#else
 
330
    c = (cbdata *) (((char *) p) - cbdata::Offset);
 
331
#endif
 
332
#if CBDATA_DEBUG
 
333
 
 
334
    debug(45, 3) ("cbdataFree: %p %s:%d\n", p, file, line);
 
335
#else
 
336
 
 
337
    debug(45, 9) ("cbdataFree: %p\n", p);
 
338
#endif
 
339
 
 
340
    c->check(__LINE__);
 
341
    assert(c->valid);
 
342
    c->valid = 0;
 
343
#if CBDATA_DEBUG
 
344
 
 
345
    c->addHistory("Free", file, line);
 
346
#endif
 
347
 
 
348
    if (c->locks) {
 
349
        debug(45, 9) ("cbdataFree: %p has %d locks, not freeing\n",
 
350
                      p, c->locks);
 
351
        return NULL;
 
352
    }
 
353
 
 
354
    cbdataCount--;
 
355
    debug(45, 9) ("cbdataFree: Freeing %p\n", p);
 
356
#if CBDATA_DEBUG
 
357
 
 
358
    dlinkDelete(&c->link, &cbdataEntries);
 
359
#endif
 
360
 
 
361
    /* This is ugly. But: operator delete doesn't get
 
362
     * the type parameter, so we can't use that 
 
363
     * to free the memory.
 
364
     * So, we free it ourselves.
 
365
     * Note that this means a non-placement 
 
366
     * new would be a seriously bad idea.
 
367
     * Lastly, if we where a templated class,
 
368
     * we could use the normal delete operator
 
369
     * and it would Just Work. RBC 20030902
 
370
     */
 
371
    cbdata_type theType = c->type;
 
372
#if HASHED_CBDATA
 
373
    hash_remove_link(cbdata_htable, &c->hash);
 
374
    delete c;
 
375
    cbdata_index[theType].pool->free((void *)p);
 
376
#else
 
377
    c->cbdata::~cbdata();
 
378
    cbdata_index[theType].pool->free(c);
 
379
#endif
 
380
    return NULL;
 
381
}
 
382
 
 
383
void
 
384
#if CBDATA_DEBUG
 
385
cbdataInternalLockDbg(const void *p, const char *file, int line)
 
386
#else
 
387
cbdataInternalLock(const void *p)
 
388
#endif
 
389
{
 
390
    cbdata *c;
 
391
 
 
392
    if (p == NULL)
 
393
        return;
 
394
 
 
395
#if HASHED_CBDATA
 
396
    c = (cbdata *) hash_lookup(cbdata_htable, p);
 
397
#else
 
398
    c = (cbdata *) (((char *) p) - cbdata::Offset);
 
399
#endif
 
400
 
 
401
#if CBDATA_DEBUG
 
402
 
 
403
    debug(45, 3) ("cbdataLock: %p=%d %s:%d\n", p, c ? c->locks + 1 : -1, file, line);
 
404
 
 
405
    c->addHistory("Reference", file, line);
 
406
 
 
407
#else
 
408
 
 
409
    debug(45, 9) ("cbdataLock: %p=%d\n", p, c ? c->locks + 1 : -1);
 
410
 
 
411
#endif
 
412
 
 
413
    c->check(__LINE__);
 
414
 
 
415
    assert(c->locks < 65535);
 
416
 
 
417
    c->locks++;
 
418
}
 
419
 
 
420
void
 
421
#if CBDATA_DEBUG
 
422
cbdataInternalUnlockDbg(const void *p, const char *file, int line)
 
423
#else
 
424
cbdataInternalUnlock(const void *p)
 
425
#endif
 
426
{
 
427
    cbdata *c;
 
428
 
 
429
    if (p == NULL)
 
430
        return;
 
431
 
 
432
#if HASHED_CBDATA
 
433
    c = (cbdata *) hash_lookup(cbdata_htable, p);
 
434
#else
 
435
    c = (cbdata *) (((char *) p) - cbdata::Offset);
 
436
#endif
 
437
 
 
438
#if CBDATA_DEBUG
 
439
 
 
440
    debug(45, 3) ("cbdataUnlock: %p=%d %s:%d\n", p, c ? c->locks - 1 : -1, file, line);
 
441
 
 
442
    c->addHistory("Dereference", file, line);
 
443
 
 
444
#else
 
445
 
 
446
    debug(45, 9) ("cbdataUnlock: %p=%d\n", p, c ? c->locks - 1 : -1);
 
447
 
 
448
#endif
 
449
 
 
450
    c->check(__LINE__);
 
451
 
 
452
    assert(c != NULL);
 
453
 
 
454
    assert(c->locks > 0);
 
455
 
 
456
    c->locks--;
 
457
 
 
458
    if (c->valid || c->locks)
 
459
        return;
 
460
 
 
461
    cbdataCount--;
 
462
 
 
463
    debug(45, 9) ("cbdataUnlock: Freeing %p\n", p);
 
464
 
 
465
#if CBDATA_DEBUG
 
466
 
 
467
    dlinkDelete(&c->link, &cbdataEntries);
 
468
 
 
469
#endif
 
470
 
 
471
    /* This is ugly. But: operator delete doesn't get
 
472
     * the type parameter, so we can't use that 
 
473
     * to free the memory.
 
474
     * So, we free it ourselves.
 
475
     * Note that this means a non-placement 
 
476
     * new would be a seriously bad idea.
 
477
     * Lastly, if we where a templated class,
 
478
     * we could use the normal delete operator
 
479
     * and it would Just Work. RBC 20030902
 
480
     */
 
481
    cbdata_type theType = c->type;
 
482
#if HASHED_CBDATA
 
483
    hash_remove_link(cbdata_htable, &c->hash);
 
484
    delete c;
 
485
    cbdata_index[theType].pool->free((void *)p);
 
486
#else
 
487
    c->cbdata::~cbdata();
 
488
    cbdata_index[theType].pool->free(c);
 
489
#endif
 
490
}
 
491
 
 
492
int
 
493
cbdataReferenceValid(const void *p)
 
494
{
 
495
    cbdata *c;
 
496
 
 
497
    if (p == NULL)
 
498
        return 1;               /* A NULL pointer cannot become invalid */
 
499
 
 
500
    debug(45, 9) ("cbdataReferenceValid: %p\n", p);
 
501
 
 
502
#if HASHED_CBDATA
 
503
    c = (cbdata *) hash_lookup(cbdata_htable, p);
 
504
#else
 
505
    c = (cbdata *) (((char *) p) - cbdata::Offset);
 
506
#endif
 
507
 
 
508
    c->check(__LINE__);
 
509
 
 
510
    assert(c->locks > 0);
 
511
 
 
512
    return c->valid;
 
513
}
 
514
 
 
515
int
 
516
#if CBDATA_DEBUG
 
517
cbdataInternalReferenceDoneValidDbg(void **pp, void **tp, const char *file, int line)
 
518
#else
 
519
cbdataInternalReferenceDoneValid(void **pp, void **tp)
 
520
#endif
 
521
{
 
522
    void *p = (void *) *pp;
 
523
    int valid = cbdataReferenceValid(p);
 
524
    *pp = NULL;
 
525
#if CBDATA_DEBUG
 
526
 
 
527
    cbdataInternalUnlockDbg(p, file, line);
 
528
#else
 
529
 
 
530
    cbdataInternalUnlock(p);
 
531
#endif
 
532
 
 
533
    if (valid) {
 
534
        *tp = p;
 
535
        return 1;
 
536
    } else {
 
537
        *tp = NULL;
 
538
        return 0;
 
539
    }
 
540
}
 
541
 
 
542
#if CBDATA_DEBUG
 
543
void
 
544
cbdata::dump(StoreEntry *sentry) const
 
545
{
 
546
#if HASHED_CBDATA
 
547
    void *p = (void *)hash.key;
 
548
#else
 
549
    void *p = (void *)&data;
 
550
#endif
 
551
    storeAppendPrintf(sentry, "%c%p\t%d\t%d\t%20s:%-5d\n", valid ? ' ' :
 
552
                      '!', p, type, locks, file, line);
 
553
}
 
554
 
 
555
struct CBDataDumper : public unary_function<cbdata, void>
 
556
{
 
557
    CBDataDumper(StoreEntry *anEntry):where(anEntry){}
 
558
 
 
559
    void operator()(cbdata const &x)
 
560
    {
 
561
        x.dump(where);
 
562
    }
 
563
 
 
564
    StoreEntry *where;
 
565
};
 
566
 
 
567
#endif
 
568
 
 
569
static void
 
570
cbdataDump(StoreEntry * sentry)
 
571
{
 
572
    storeAppendPrintf(sentry, "%d cbdata entries\n", cbdataCount);
 
573
#if CBDATA_DEBUG
 
574
 
 
575
    storeAppendPrintf(sentry, "Pointer\tType\tLocks\tAllocated by\n");
 
576
    CBDataDumper dumper(sentry);
 
577
    for_each (cbdataEntries, dumper);
 
578
    storeAppendPrintf(sentry, "\n");
 
579
    storeAppendPrintf(sentry, "types\tsize\tallocated\ttotal\n");
 
580
 
 
581
    for (int i = 1; i < cbdata_types; i++) {
 
582
        MemAllocator *pool = cbdata_index[i].pool;
 
583
 
 
584
        if (pool) {
 
585
#if HASHED_CBDATA
 
586
            int obj_size = pool->objectSize();
 
587
#else
 
588
            int obj_size = pool->objectSize() - cbdata::Offset;
 
589
#endif
 
590
            storeAppendPrintf(sentry, "%s\t%d\t%ld\t%ld\n", pool->objectType() + 7, obj_size, (long int)pool->getMeter().inuse.level, (long int)obj_size * pool->getMeter().inuse.level);
 
591
        }
 
592
    }
 
593
 
 
594
#else
 
595
    storeAppendPrintf(sentry, "detailed allocation information only available when compiled with CBDATA_DEBUG\n");
 
596
 
 
597
#endif
 
598
 
 
599
    storeAppendPrintf(sentry, "\nsee also \"Memory utilization\" for detailed per type statistics\n");
 
600
}
 
601
 
 
602
CBDATA_CLASS_INIT(generic_cbdata);
 
603
 
 
604
#if CBDATA_DEBUG
 
605
 
 
606
struct CBDataCallDumper : public unary_function<CBDataCall, void>
 
607
{
 
608
    CBDataCallDumper (StoreEntry *anEntry):where(anEntry){}
 
609
 
 
610
    void operator()(CBDataCall const &x)
 
611
    {
 
612
        storeAppendPrintf(where, "%s\t%s\t%d\n", x.label, x.file, x.line);
 
613
    }
 
614
 
 
615
    StoreEntry *where;
 
616
};
 
617
 
 
618
struct CBDataHistoryDumper : public CBDataDumper
 
619
{
 
620
    CBDataHistoryDumper(StoreEntry *anEntry):CBDataDumper(anEntry),where(anEntry), callDumper(anEntry){}
 
621
 
 
622
    void operator()(cbdata const &x)
 
623
    {
 
624
        CBDataDumper::operator()(x);
 
625
        storeAppendPrintf(where, "\n");
 
626
        storeAppendPrintf(where, "Action\tFile\tLine\n");
 
627
        for_each (x.calls,callDumper);
 
628
        storeAppendPrintf(where, "\n");
 
629
    }
 
630
 
 
631
    StoreEntry *where;
 
632
    CBDataCallDumper callDumper;
 
633
};
 
634
 
 
635
void
 
636
cbdataDumpHistory(StoreEntry *sentry)
 
637
{
 
638
    storeAppendPrintf(sentry, "%d cbdata entries\n", cbdataCount);
 
639
    storeAppendPrintf(sentry, "Pointer\tType\tLocks\tAllocated by\n");
 
640
    CBDataHistoryDumper dumper(sentry);
 
641
    for_each (cbdataEntries, dumper);
 
642
}
 
643
 
 
644
#endif