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