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