]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/cbdata.cc
Cleanup: zap CVS Id tags
[thirdparty/squid.git] / src / cbdata.cc
index be884aa270877fccca4f884d848b0b6b83534d36..5675a787f94065f6120acf9824d2a097dc3be1bc 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: cbdata.cc,v 1.57 2003/07/14 08:21:56 robertc Exp $
+ * $Id$
  *
  * DEBUG: section 45    Callback Data Registry
  * ORIGINAL AUTHOR: Duane Wessels
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
- *  
+ *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
- *  
+ *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
 
-/*
+/**
+ \defgroup CBDATAInternal Callback Data Allocator Internals
+ \ingroup CBDATAAPI
+ *
  * These routines manage a set of registered callback data pointers.
- * One of the easiest ways to make Squid coredump is to issue a 
+ * One of the easiest ways to make Squid coredump is to issue a
  * callback to for some data structure which has previously been
  * freed.  With these routines, we register (add) callback data
  * pointers, lock them just before registering the callback function,
  * when finished.
  */
 
-#include "squid.h"
+#include "cbdata.h"
+#include "CacheManager.h"
 #include "Store.h"
 #if CBDATA_DEBUG
 #include "Stack.h"
 #endif
 #include "Generic.h"
 
+#if WITH_VALGRIND
+#define HASHED_CBDATA 1
+#endif
+
 static int cbdataCount = 0;
 #if CBDATA_DEBUG
 dlink_list cbdataEntries;
@@ -63,7 +71,7 @@ class CBDataCall
 {
 
 public:
-    CBDataCall (char const *callLabel, char const *aFile, int aLine) : label(callLabel), file(aFile), line(aLine){}
+    CBDataCall (char const *callLabel, char const *aFile, int aLine) : label(callLabel), file(aFile), line(aLine) {}
 
     char const *label;
     char const *file;
@@ -72,53 +80,87 @@ public:
 
 #endif
 
+/// \ingroup CBDATAInternal
 #define OFFSET_OF(TYPE, MEMBER) ((size_t) &(((TYPE) *)0)->(MEMBER))
 
+/// \ingroup CBDATAInternal
 class cbdata
 {
-
+    /** \todo examine making cbdata templated on this - so we get type
+     * safe access to data - RBC 20030902 */
 public:
+#if HASHED_CBDATA
+    hash_link hash;    // Must be first
+#endif
+
 #if CBDATA_DEBUG
 
     void dump(StoreEntry *)const;
 #endif
 
-    void deleteSelf();
+#if !HASHED_CBDATA
+    void *operator new(size_t size, void *where);
+    void operator delete(void *where, void *where2);
+#else
+    MEMPROXY_CLASS(cndata);
+#endif
+
+    ~cbdata();
     int valid;
     int locks;
-    int type;
+    cbdata_type type;
 #if CBDATA_DEBUG
 
-    void addHistory(char const *label, char const *file, int line) const
-    {
-        if (calls->count > 1000)
+    void addHistory(char const *label, char const *file, int line) {
+        if (calls.size() > 1000)
             return;
 
-        stackPush (calls, new CBDataCall(label, file, line));
+        calls.push_back(new CBDataCall(label, file, line));
     }
 
     dlink_node link;
     const char *file;
     int line;
-    Stack *calls;
+    Stack<CBDataCall*> calls;
 #endif
 
     /* cookie used while debugging */
     long cookie;
-    /* MUST be the last per-instance member */
-    void *data;
-void check() const { assert(cookie == ((long)this ^ Cookie));}
+    void check(int line) const {assert(cookie == ((long)this ^ Cookie));}
+    static const long Cookie;
 
+#if !HASHED_CBDATA
     size_t dataSize() const { return sizeof(data);}
-
-    static const long Cookie;
     static long MakeOffset();
     static const long Offset;
+    /* MUST be the last per-instance member */
+    void *data;
+#endif
+
 };
 
 const long cbdata::Cookie((long)0xDEADBEEF);
+#if !HASHED_CBDATA
 const long cbdata::Offset(MakeOffset());
 
+void *
+cbdata::operator new(size_t size, void *where)
+{
+    // assert (size == sizeof(cbdata));
+    return where;
+}
+
+/**
+ * Only ever invoked when placement new throws
+ * an exception. Used to prevent an incorrect
+ * free.
+ */
+void
+cbdata::operator delete(void *where, void *where2)
+{
+    ; // empty.
+}
+
 long
 cbdata::MakeOffset()
 {
@@ -126,66 +168,91 @@ cbdata::MakeOffset()
     void **dataOffset = &zero->data;
     return (long)dataOffset;
 }
+#else
+MEMPROXY_CLASS_INLINE(cbdata);
+#endif
 
 static OBJH cbdataDump;
 #ifdef CBDATA_DEBUG
 static OBJH cbdataDumpHistory;
 #endif
 
-struct CBDataIndex
-{
-    MemPool *pool;
+/// \ingroup CBDATAInternal
+struct CBDataIndex {
+    MemAllocator *pool;
     FREE *free_func;
 }
-
 *cbdata_index = NULL;
+
+/// \ingroup CBDATAInternal
 int cbdata_types = 0;
 
-void
-cbdata::deleteSelf()
+#if HASHED_CBDATA
+static hash_table *cbdata_htable = NULL;
+
+static int
+cbdata_cmp(const void *p1, const void *p2)
+{
+    return (char *) p1 - (char *) p2;
+}
+
+static unsigned int
+cbdata_hash(const void *p, unsigned int mod)
+{
+    return ((unsigned long) p >> 8) % mod;
+}
+#endif
+
+
+cbdata::~cbdata()
 {
 #if CBDATA_DEBUG
     CBDataCall *aCall;
 
-    while ((aCall = (CBDataCall *)stackPop(calls)))
+    while ((aCall = calls.pop()))
         delete aCall;
 
-    stackDestroy(calls);
-
 #endif
 
     FREE *free_func = cbdata_index[type].free_func;
 
-    if (free_func)
-        free_func(&data);
+#if HASHED_CBDATA
+    void *p = hash.key;
+#else
+    void *p = &data;
+#endif
 
-    memPoolFree(cbdata_index[type].pool, this);
+    if (free_func)
+        free_func(p);
 }
 
 static void
 cbdataInternalInitType(cbdata_type type, const char *name, int size, FREE * free_func)
 {
     char *label;
+    assert (type == cbdata_types + 1);
 
-    if (type >= cbdata_types) {
-        cbdata_index = (CBDataIndex *)xrealloc(cbdata_index, (type + 1) * sizeof(*cbdata_index));
-        memset(&cbdata_index[cbdata_types], 0,
-               (type + 1 - cbdata_types) * sizeof(*cbdata_index));
-        cbdata_types = type + 1;
-    }
-
-    if (cbdata_index[type].pool)
-        return;
+    cbdata_index = (CBDataIndex *)xrealloc(cbdata_index, (type + 1) * sizeof(*cbdata_index));
+    memset(&cbdata_index[type], 0, sizeof(*cbdata_index));
+    cbdata_types = type;
 
     label = (char *)xmalloc(strlen(name) + 20);
 
     snprintf(label, strlen(name) + 20, "cbdata %s (%d)", name, (int) type);
 
+#if !HASHED_CBDATA
     assert((size_t)cbdata::Offset == (sizeof(cbdata) - ((cbdata *)NULL)->dataSize()));
+    size += cbdata::Offset;
+#endif
 
-    cbdata_index[type].pool = memPoolCreate(label, size + cbdata::Offset);
+    cbdata_index[type].pool = memPoolCreate(label, size);
 
     cbdata_index[type].free_func = free_func;
+
+#if HASHED_CBDATA
+    if (!cbdata_htable)
+        cbdata_htable = hash_create(cbdata_cmp, 1 << 12, cbdata_hash);
+#endif
 }
 
 cbdata_type
@@ -194,7 +261,7 @@ cbdataInternalAddType(cbdata_type type, const char *name, int size, FREE * free_
     if (type)
         return type;
 
-    type = (cbdata_type)cbdata_types;
+    type = (cbdata_type)(cbdata_types + 1);
 
     cbdataInternalInitType(type, name, size, free_func);
 
@@ -202,35 +269,18 @@ cbdataInternalAddType(cbdata_type type, const char *name, int size, FREE * free_
 }
 
 void
-cbdataInit(void)
+cbdataRegisterWithCacheManager(void)
 {
-    debug(45, 3) ("cbdataInit\n");
-    cachemgrRegister("cbdata",
-                     "Callback Data Registry Contents",
-                     cbdataDump, 0, 1);
+    CacheManager *manager=CacheManager::GetInstance();
+    manager->registerAction("cbdata",
+                            "Callback Data Registry Contents",
+                            cbdataDump, 0, 1);
 #if CBDATA_DEBUG
 
-    cachemgrRegister("cbdatahistory",
-                     "Detailed call history for all current cbdata contents",
-                     cbdataDumpHistory, 0, 1);
+    manager->registerAction("cbdatahistory",
+                            "Detailed call history for all current cbdata contents",
+                            cbdataDumpHistory, 0, 1);
 #endif
-#define CREATE_CBDATA(type) cbdataInternalInitType(CBDATA_##type, #type, sizeof(type), NULL)
-#define CREATE_CBDATA_FREE(type, free_func) cbdataInternalInitType(CBDATA_##type, #type, sizeof(type), free_func)
-    /* XXX
-     * most of these should be moved out to their respective module.
-     */
-    CREATE_CBDATA(ErrorState);
-    CREATE_CBDATA(FwdState);
-    CREATE_CBDATA(generic_cbdata);
-    CREATE_CBDATA(helper);
-    CREATE_CBDATA(helper_server);
-    CREATE_CBDATA(statefulhelper);
-    CREATE_CBDATA(helper_stateful_server);
-    CREATE_CBDATA_FREE(peer, peerDestroy);
-    CREATE_CBDATA(ps_state);
-    CREATE_CBDATA(RemovalPolicy);
-    CREATE_CBDATA(RemovalPolicyWalker);
-    CREATE_CBDATA(RemovalPurgeWalker);
 }
 
 void *
@@ -240,25 +290,38 @@ cbdataInternalAllocDbg(cbdata_type type, const char *file, int line)
 cbdataInternalAlloc(cbdata_type type)
 #endif
 {
-    cbdata *p;
-    assert(type > 0 && type < cbdata_types);
-    p = (cbdata *)memPoolAlloc(cbdata_index[type].pool);
-    p->type = type;
-    p->valid = 1;
-    p->locks = 0;
-    p->cookie = (long) p ^ cbdata::Cookie;
+    cbdata *c;
+    void *p;
+    assert(type > 0 && type <= cbdata_types);
+    /* placement new: the pool alloc gives us cbdata + user type memory space
+     * and we init it with cbdata at the start of it
+     */
+#if HASHED_CBDATA
+    c = new cbdata;
+    p = cbdata_index[type].pool->alloc();
+    c->hash.key = p;
+    hash_join(cbdata_htable, &c->hash);
+#else
+    c = new (cbdata_index[type].pool->alloc()) cbdata;
+    p = (void *)&c->data;
+#endif
+
+    c->type = type;
+    c->valid = 1;
+    c->locks = 0;
+    c->cookie = (long) c ^ cbdata::Cookie;
     cbdataCount++;
 #if CBDATA_DEBUG
 
-    p->file = file;
-    p->line = line;
-    p->calls = stackCreate();
-    p->addHistory("Alloc", file, line);
-    dlinkAdd(p, &p->link, &cbdataEntries);
-    debug(45, 3) ("cbdataAlloc: %p %s:%d\n", &p->data, file, line);
+    c->file = file;
+    c->line = line;
+    c->calls = Stack<CBDataCall *> ();
+    c->addHistory("Alloc", file, line);
+    dlinkAdd(c, &c->link, &cbdataEntries);
+    debugs(45, 3, "cbdataAlloc: " << p << " " << file << ":" << line);
 #endif
 
-    return (void *) &p->data;
+    return p;
 }
 
 void *
@@ -269,16 +332,21 @@ cbdataInternalFree(void *p)
 #endif
 {
     cbdata *c;
+#if HASHED_CBDATA
+    c = (cbdata *) hash_lookup(cbdata_htable, p);
+#else
     c = (cbdata *) (((char *) p) - cbdata::Offset);
+#endif
 #if CBDATA_DEBUG
 
-    debug(45, 3) ("cbdataFree: %p %s:%d\n", p, file, line);
+    debugs(45, 3, "cbdataFree: " << p << " " << file << ":" << line);
 #else
 
-    debug(45, 3) ("cbdataFree: %p\n", p);
+    debugs(45, 9, "cbdataFree: " << p);
 #endif
 
-    c->check();
+    c->check(__LINE__);
+    assert(c->valid);
     c->valid = 0;
 #if CBDATA_DEBUG
 
@@ -286,19 +354,36 @@ cbdataInternalFree(void *p)
 #endif
 
     if (c->locks) {
-        debug(45, 3) ("cbdataFree: %p has %d locks, not freeing\n",
-                      p, c->locks);
+        debugs(45, 9, "cbdataFree: " << p << " has " << c->locks << " locks, not freeing");
         return NULL;
     }
 
     cbdataCount--;
-    debug(45, 3) ("cbdataFree: Freeing %p\n", p);
+    debugs(45, 9, "cbdataFree: Freeing " << p);
 #if CBDATA_DEBUG
 
     dlinkDelete(&c->link, &cbdataEntries);
 #endif
 
-    c->deleteSelf();
+    /* This is ugly. But: operator delete doesn't get
+     * the type parameter, so we can't use that
+     * to free the memory.
+     * So, we free it ourselves.
+     * Note that this means a non-placement
+     * new would be a seriously bad idea.
+     * Lastly, if we where a templated class,
+     * we could use the normal delete operator
+     * and it would Just Work. RBC 20030902
+     */
+    cbdata_type theType = c->type;
+#if HASHED_CBDATA
+    hash_remove_link(cbdata_htable, &c->hash);
+    delete c;
+    cbdata_index[theType].pool->free((void *)p);
+#else
+    c->cbdata::~cbdata();
+    cbdata_index[theType].pool->free(c);
+#endif
     return NULL;
 }
 
@@ -314,21 +399,25 @@ cbdataInternalLock(const void *p)
     if (p == NULL)
         return;
 
+#if HASHED_CBDATA
+    c = (cbdata *) hash_lookup(cbdata_htable, p);
+#else
     c = (cbdata *) (((char *) p) - cbdata::Offset);
+#endif
 
 #if CBDATA_DEBUG
 
-    debug(45, 3) ("cbdataLock: %p=%d %s:%d\n", p, c ? c->locks + 1 : -1, file, line);
+    debugs(45, 3, "cbdataLock: " << p << "=" << (c ? c->locks + 1 : -1) << " " << file << ":" << line);
 
     c->addHistory("Reference", file, line);
 
 #else
 
-    debug(45, 3) ("cbdataLock: %p=%d\n", p, c ? c->locks + 1 : -1);
+    debugs(45, 9, "cbdataLock: " << p << "=" << (c ? c->locks + 1 : -1));
 
 #endif
 
-    c->check();
+    c->check(__LINE__);
 
     assert(c->locks < 65535);
 
@@ -347,21 +436,25 @@ cbdataInternalUnlock(const void *p)
     if (p == NULL)
         return;
 
+#if HASHED_CBDATA
+    c = (cbdata *) hash_lookup(cbdata_htable, p);
+#else
     c = (cbdata *) (((char *) p) - cbdata::Offset);
+#endif
 
 #if CBDATA_DEBUG
 
-    debug(45, 3) ("cbdataUnlock: %p=%d %s:%d\n", p, c ? c->locks - 1 : -1, file, line);
+    debugs(45, 3, "cbdataUnlock: " << p << "=" << (c ? c->locks - 1 : -1) << " " << file << ":" << line);
 
     c->addHistory("Dereference", file, line);
 
 #else
 
-    debug(45, 3) ("cbdataUnlock: %p=%d\n", p, c ? c->locks - 1 : -1);
+    debugs(45, 9, "cbdataUnlock: " << p << "=" << (c ? c->locks - 1 : -1));
 
 #endif
 
-    c->check();
+    c->check(__LINE__);
 
     assert(c != NULL);
 
@@ -374,7 +467,7 @@ cbdataInternalUnlock(const void *p)
 
     cbdataCount--;
 
-    debug(45, 3) ("cbdataUnlock: Freeing %p\n", p);
+    debugs(45, 9, "cbdataUnlock: Freeing " << p);
 
 #if CBDATA_DEBUG
 
@@ -382,7 +475,25 @@ cbdataInternalUnlock(const void *p)
 
 #endif
 
-    c->deleteSelf();
+    /* This is ugly. But: operator delete doesn't get
+     * the type parameter, so we can't use that
+     * to free the memory.
+     * So, we free it ourselves.
+     * Note that this means a non-placement
+     * new would be a seriously bad idea.
+     * Lastly, if we where a templated class,
+     * we could use the normal delete operator
+     * and it would Just Work. RBC 20030902
+     */
+    cbdata_type theType = c->type;
+#if HASHED_CBDATA
+    hash_remove_link(cbdata_htable, &c->hash);
+    delete c;
+    cbdata_index[theType].pool->free((void *)p);
+#else
+    c->cbdata::~cbdata();
+    cbdata_index[theType].pool->free(c);
+#endif
 }
 
 int
@@ -393,11 +504,15 @@ cbdataReferenceValid(const void *p)
     if (p == NULL)
         return 1;              /* A NULL pointer cannot become invalid */
 
-    debug(45, 3) ("cbdataReferenceValid: %p\n", p);
+    debugs(45, 9, "cbdataReferenceValid: " << p);
 
+#if HASHED_CBDATA
+    c = (cbdata *) hash_lookup(cbdata_htable, p);
+#else
     c = (cbdata *) (((char *) p) - cbdata::Offset);
+#endif
 
-    c->check();
+    c->check(__LINE__);
 
     assert(c->locks > 0);
 
@@ -435,16 +550,19 @@ cbdataInternalReferenceDoneValid(void **pp, void **tp)
 void
 cbdata::dump(StoreEntry *sentry) const
 {
+#if HASHED_CBDATA
+    void *p = (void *)hash.key;
+#else
+    void *p = (void *)&data;
+#endif
     storeAppendPrintf(sentry, "%c%p\t%d\t%d\t%20s:%-5d\n", valid ? ' ' :
-                      '!', &data, type, locks, file, line);
+                      '!', p, type, locks, file, line);
 }
 
-struct CBDataDumper : public unary_function<cbdata, void>
-{
-    CBDataDumper(StoreEntry *anEntry):where(anEntry){}
+struct CBDataDumper : public unary_function<cbdata, void> {
+    CBDataDumper(StoreEntry *anEntry):where(anEntry) {}
 
-    void operator()(cbdata const &x)
-    {
+    void operator()(cbdata const &x) {
         x.dump(where);
     }
 
@@ -466,11 +584,15 @@ cbdataDump(StoreEntry * sentry)
     storeAppendPrintf(sentry, "types\tsize\tallocated\ttotal\n");
 
     for (int i = 1; i < cbdata_types; i++) {
-        MemPool *pool = cbdata_index[i].pool;
+        MemAllocator *pool = cbdata_index[i].pool;
 
         if (pool) {
-            int obj_size = pool->obj_size - cbdata::Offset;
-            storeAppendPrintf(sentry, "%s\t%d\t%d\t%d\n", pool->label + 7, obj_size, pool->meter.inuse.level, obj_size * pool->meter.inuse.level);
+#if HASHED_CBDATA
+            int obj_size = pool->objectSize();
+#else
+            int obj_size = pool->objectSize() - cbdata::Offset;
+#endif
+            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);
         }
     }
 
@@ -482,39 +604,28 @@ cbdataDump(StoreEntry * sentry)
     storeAppendPrintf(sentry, "\nsee also \"Memory utilization\" for detailed per type statistics\n");
 }
 
-#if CBDATA_DEBUG
+CBDATA_CLASS_INIT(generic_cbdata);
 
-template <class T>
-T& for_each(Stack const &collection, T& visitor)
-{
-    for (size_t index = 0; index < collection.count; ++index)
-        visitor(*(typename T::argument_type const *)collection.items[index]);
+#if CBDATA_DEBUG
 
-    return visitor;
-};
+struct CBDataCallDumper : public unary_function<CBDataCall, void> {
+    CBDataCallDumper (StoreEntry *anEntry):where(anEntry) {}
 
-struct CBDataCallDumper : public unary_function<CBDataCall, void>
-{
-    CBDataCallDumper (StoreEntry *anEntry):where(anEntry){}
-
-    void operator()(CBDataCall const &x)
-    {
+    void operator()(CBDataCall const &x) {
         storeAppendPrintf(where, "%s\t%s\t%d\n", x.label, x.file, x.line);
     }
 
     StoreEntry *where;
 };
 
-struct CBDataHistoryDumper : public CBDataDumper
-{
-    CBDataHistoryDumper(StoreEntry *anEntry):CBDataDumper(anEntry),where(anEntry), callDumper(anEntry){}
+struct CBDataHistoryDumper : public CBDataDumper {
+    CBDataHistoryDumper(StoreEntry *anEntry):CBDataDumper(anEntry),where(anEntry), callDumper(anEntry) {}
 
-    void operator()(cbdata const &x)
-    {
+    void operator()(cbdata const &x) {
         CBDataDumper::operator()(x);
         storeAppendPrintf(where, "\n");
         storeAppendPrintf(where, "Action\tFile\tLine\n");
-        for_each (*x.calls,callDumper);
+        for_each (x.calls,callDumper);
         storeAppendPrintf(where, "\n");
     }