cbdata.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:6k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: cbdata.c,v 1.27 1998/12/05 00:54:17 wessels Exp $
  3.  *
  4.  * DEBUG: section 45    Callback Data Registry
  5.  * AUTHOR: Duane Wessels
  6.  *
  7.  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
  8.  * ----------------------------------------------------------
  9.  *
  10.  *  Squid is the result of efforts by numerous individuals from the
  11.  *  Internet community.  Development is led by Duane Wessels of the
  12.  *  National Laboratory for Applied Network Research and funded by the
  13.  *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
  14.  *  Duane Wessels and the University of California San Diego.  Please
  15.  *  see the COPYRIGHT file for full details.  Squid incorporates
  16.  *  software developed and/or copyrighted by other sources.  Please see
  17.  *  the CREDITS file for full details.
  18.  *
  19.  *  This program is free software; you can redistribute it and/or modify
  20.  *  it under the terms of the GNU General Public License as published by
  21.  *  the Free Software Foundation; either version 2 of the License, or
  22.  *  (at your option) any later version.
  23.  *  
  24.  *  This program is distributed in the hope that it will be useful,
  25.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  26.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  27.  *  GNU General Public License for more details.
  28.  *  
  29.  *  You should have received a copy of the GNU General Public License
  30.  *  along with this program; if not, write to the Free Software
  31.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  32.  *
  33.  */
  34. /*
  35.  * These routines manage a set of registered callback data pointers.
  36.  * One of the easiest ways to make Squid coredump is to issue a 
  37.  * callback to for some data structure which has previously been
  38.  * freed.  With these routines, we register (add) callback data
  39.  * pointers, lock them just before registering the callback function,
  40.  * validate them before issuing the callback, and then free them
  41.  * when finished.
  42.  * 
  43.  * In terms of time, the sequence goes something like this:
  44.  * 
  45.  * foo = xcalloc(sizeof(foo));
  46.  * cbdataAdd(foo);
  47.  * ...
  48.  * cbdataLock(foo);
  49.  * some_blocking_operation(..., callback_func, foo);
  50.  * ...
  51.  * some_blocking_operation_completes()
  52.  * if (cbdataValid(foo))
  53.  * callback_func(..., foo)
  54.  * cbdataUnlock(foo);
  55.  * ...
  56.  * cbdataFree(foo);
  57.  * 
  58.  * The nice thing is that, we do not need to require that Unlock
  59.  * occurs before Free.  If the Free happens first, then the 
  60.  * callback data is marked invalid and the callback will never
  61.  * be made.  When we Unlock and the lock count reaches zero,
  62.  * we free the memory if it is marked invalid.
  63.  */
  64. #include "squid.h"
  65. static hash_table *htable = NULL;
  66. static int cbdataCount = 0;
  67. typedef struct _cbdata {
  68.     const void *key;
  69.     struct _cbdata *next;
  70.     int valid;
  71.     int locks;
  72.     CBDUNL *unlock_func;
  73.     int id;
  74. #if CBDATA_DEBUG
  75.     const char *file;
  76.     int line;
  77. #endif
  78. } cbdata;
  79. static HASHCMP cbdata_cmp;
  80. static HASHHASH cbdata_hash;
  81. static void cbdataReallyFree(cbdata * c);
  82. static OBJH cbdataDump;
  83. static int
  84. cbdata_cmp(const void *p1, const void *p2)
  85. {
  86.     return (char *) p1 - (char *) p2;
  87. }
  88. static unsigned int
  89. cbdata_hash(const void *p, unsigned int mod)
  90. {
  91.     return ((unsigned long) p >> 8) % mod;
  92. }
  93. void
  94. cbdataInit(void)
  95. {
  96.     debug(45, 3) ("cbdataInitn");
  97.     htable = hash_create(cbdata_cmp, 1 << 8, cbdata_hash);
  98.     cachemgrRegister("cbdata",
  99. "Callback Data Registry Contents",
  100. cbdataDump, 0, 1);
  101. }
  102. void
  103. #if CBDATA_DEBUG
  104. cbdataAddDbg(const void *p, CBDUNL * unlock_func, int id, const char *file, int line)
  105. #else
  106. cbdataAdd(const void *p, CBDUNL * unlock_func, int id)
  107. #endif
  108. {
  109.     cbdata *c;
  110.     assert(p);
  111.     debug(45, 3) ("cbdataAdd: %pn", p);
  112.     assert(htable != NULL);
  113.     assert(hash_lookup(htable, p) == NULL);
  114.     c = xcalloc(1, sizeof(cbdata));
  115.     c->key = p;
  116.     c->valid = 1;
  117.     c->unlock_func = unlock_func;
  118.     c->id = id;
  119. #if CBDATA_DEBUG
  120.     c->file = file;
  121.     c->line = line;
  122. #endif
  123.     hash_join(htable, (hash_link *) c);
  124.     cbdataCount++;
  125. }
  126. static void
  127. cbdataReallyFree(cbdata * c)
  128. {
  129.     CBDUNL *unlock_func = c->unlock_func;
  130.     void *p = (void *) c->key;
  131.     int id = c->id;
  132.     hash_remove_link(htable, (hash_link *) c);
  133.     cbdataCount--;
  134.     xfree(c);
  135.     debug(45, 3) ("cbdataReallyFree: Freeing %pn", p);
  136.     if (unlock_func)
  137. unlock_func(p, id);
  138. }
  139. void
  140. cbdataFree(void *p)
  141. {
  142.     cbdata *c = (cbdata *) hash_lookup(htable, p);
  143.     assert(p);
  144.     debug(45, 3) ("cbdataFree: %pn", p);
  145.     assert(c != NULL);
  146.     c->valid = 0;
  147.     if (c->locks) {
  148. debug(45, 3) ("cbdataFree: %p has %d locks, not freeingn",
  149.     p, c->locks);
  150. return;
  151.     }
  152.     cbdataReallyFree(c);
  153. }
  154. void
  155. cbdataLock(const void *p)
  156. {
  157.     cbdata *c;
  158.     if (p == NULL)
  159. return;
  160.     c = (cbdata *) hash_lookup(htable, p);
  161.     debug(45, 3) ("cbdataLock: %pn", p);
  162.     assert(c != NULL);
  163.     c->locks++;
  164. }
  165. void
  166. cbdataUnlock(const void *p)
  167. {
  168.     cbdata *c;
  169.     if (p == NULL)
  170. return;
  171.     c = (cbdata *) hash_lookup(htable, p);
  172.     debug(45, 3) ("cbdataUnlock: %pn", p);
  173.     assert(c != NULL);
  174.     assert(c->locks > 0);
  175.     c->locks--;
  176.     if (c->valid || c->locks)
  177. return;
  178.     cbdataReallyFree(c);
  179. }
  180. int
  181. cbdataValid(const void *p)
  182. {
  183.     cbdata *c;
  184.     /* Maybe NULL should be considered valid? */
  185.     if (p == NULL)
  186. return 0;
  187.     c = (cbdata *) hash_lookup(htable, p);
  188.     debug(45, 3) ("cbdataValid: %pn", p);
  189.     assert(c != NULL);
  190.     assert(c->locks > 0);
  191.     return c->valid;
  192. }
  193. void
  194. cbdataXfree(void *p, int unused)
  195. {
  196.     xfree(p);
  197. }
  198. static void
  199. cbdataDump(StoreEntry * sentry)
  200. {
  201.     hash_link *hptr;
  202.     cbdata *c;
  203.     storeAppendPrintf(sentry, "%d cbdata entriesn", cbdataCount);
  204.     hash_first(htable);
  205.     while ((hptr = hash_next(htable))) {
  206. c = (cbdata *) hptr;
  207. #if CBDATA_DEBUG
  208. storeAppendPrintf(sentry, "%20p %10s %d locks %s:%dn",
  209.     c->key,
  210.     c->valid ? "VALID" : "NOT VALID",
  211.     c->locks,
  212.     c->file, c->line);
  213. #else
  214. storeAppendPrintf(sentry, "%20p %10s %d locksn",
  215.     c->key,
  216.     c->valid ? "VALID" : "NOT VALID",
  217.     c->locks);
  218. #endif
  219.     }
  220. }