]> git.ipfire.org Git - thirdparty/squid.git/blob - src/stmem.cc
-Changed comm_write() to free/give up memory after the write has been
[thirdparty/squid.git] / src / stmem.cc
1 /*
2 * $Id: stmem.cc,v 1.14 1996/07/20 03:16:56 wessels Exp $
3 *
4 * DEBUG: section 19 Memory Primitives
5 * AUTHOR: Harvest Derived
6 *
7 * SQUID Internet Object Cache http://www.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
13 * the National Science Foundation.
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 *
29 */
30
31 /*
32 * Copyright (c) 1994, 1995. All rights reserved.
33 *
34 * The Harvest software was developed by the Internet Research Task
35 * Force Research Group on Resource Discovery (IRTF-RD):
36 *
37 * Mic Bowman of Transarc Corporation.
38 * Peter Danzig of the University of Southern California.
39 * Darren R. Hardy of the University of Colorado at Boulder.
40 * Udi Manber of the University of Arizona.
41 * Michael F. Schwartz of the University of Colorado at Boulder.
42 * Duane Wessels of the University of Colorado at Boulder.
43 *
44 * This copyright notice applies to software in the Harvest
45 * ``src/'' directory only. Users should consult the individual
46 * copyright notices in the ``components/'' subdirectories for
47 * copyright information about other software bundled with the
48 * Harvest source code distribution.
49 *
50 * TERMS OF USE
51 *
52 * The Harvest software may be used and re-distributed without
53 * charge, provided that the software origin and research team are
54 * cited in any use of the system. Most commonly this is
55 * accomplished by including a link to the Harvest Home Page
56 * (http://harvest.cs.colorado.edu/) from the query page of any
57 * Broker you deploy, as well as in the query result pages. These
58 * links are generated automatically by the standard Broker
59 * software distribution.
60 *
61 * The Harvest software is provided ``as is'', without express or
62 * implied warranty, and with no support nor obligation to assist
63 * in its use, correction, modification or enhancement. We assume
64 * no liability with respect to the infringement of copyrights,
65 * trade secrets, or any patents, and are not responsible for
66 * consequential damages. Proper use of the Harvest software is
67 * entirely the responsibility of the user.
68 *
69 * DERIVATIVE WORKS
70 *
71 * Users may make derivative works from the Harvest software, subject
72 * to the following constraints:
73 *
74 * - You must include the above copyright notice and these
75 * accompanying paragraphs in all forms of derivative works,
76 * and any documentation and other materials related to such
77 * distribution and use acknowledge that the software was
78 * developed at the above institutions.
79 *
80 * - You must notify IRTF-RD regarding your distribution of
81 * the derivative work.
82 *
83 * - You must clearly notify users that your are distributing
84 * a modified version and not the original Harvest software.
85 *
86 * - Any derivative product is also subject to these copyright
87 * and use restrictions.
88 *
89 * Note that the Harvest software is NOT in the public domain. We
90 * retain copyright, as specified above.
91 *
92 * HISTORY OF FREE SOFTWARE STATUS
93 *
94 * Originally we required sites to license the software in cases
95 * where they were going to build commercial products/services
96 * around Harvest. In June 1995 we changed this policy. We now
97 * allow people to use the core Harvest software (the code found in
98 * the Harvest ``src/'' directory) for free. We made this change
99 * in the interest of encouraging the widest possible deployment of
100 * the technology. The Harvest software is really a reference
101 * implementation of a set of protocols and formats, some of which
102 * we intend to standardize. We encourage commercial
103 * re-implementations of code complying to this set of standards.
104 */
105
106 #include "squid.h"
107
108 stmem_stats sm_stats;
109 stmem_stats disk_stats;
110 stmem_stats request_pool;
111 stmem_stats mem_obj_pool;
112
113 #define min(x,y) ((x)<(y)? (x) : (y))
114
115 #ifndef USE_MEMALIGN
116 #define USE_MEMALIGN 0
117 #endif
118
119 static void *get_free_thing _PARAMS((stmem_stats * thing));
120 static void put_free_thing _PARAMS((stmem_stats * thing, void *p));
121
122
123 void memFree(mem)
124 mem_ptr mem;
125 {
126 mem_node lastp, p = mem->head;
127
128 if (p) {
129 while (p && (p != mem->tail)) {
130 lastp = p;
131 p = p->next;
132 if (lastp) {
133 put_free_4k_page(lastp->data);
134 safe_free(lastp);
135 }
136 }
137
138 if (p) {
139 put_free_4k_page(p->data);
140 safe_free(p);
141 }
142 }
143 memset(mem, '\0', sizeof(mem_ptr)); /* nuke in case ref'ed again */
144 safe_free(mem);
145 }
146
147 void memFreeData(mem)
148 mem_ptr mem;
149 {
150 mem_node lastp, p = mem->head;
151
152 while (p != mem->tail) {
153 lastp = p;
154 p = p->next;
155 put_free_4k_page(lastp->data);
156 safe_free(lastp);
157 }
158
159 if (p != NULL) {
160 put_free_4k_page(p->data);
161 safe_free(p);
162 p = NULL;
163 }
164 mem->head = mem->tail = NULL; /* detach in case ref'd */
165 mem->origin_offset = 0;
166 }
167
168 int memFreeDataUpto(mem, target_offset)
169 mem_ptr mem;
170 int target_offset;
171 {
172 int current_offset = mem->origin_offset;
173 mem_node lastp, p = mem->head;
174
175 while (p && ((current_offset + p->len) <= target_offset)) {
176 if (p == mem->tail) {
177 /* keep the last one to avoid change to other part of code */
178 mem->head = mem->tail;
179 mem->origin_offset = current_offset;
180 return current_offset;
181 } else {
182 lastp = p;
183 p = p->next;
184 current_offset += lastp->len;
185 put_free_4k_page(lastp->data);
186 safe_free(lastp);
187 }
188 }
189
190 mem->head = p;
191 mem->origin_offset = current_offset;
192 if (current_offset < target_offset) {
193 /* there are still some data left. */
194 return current_offset;
195 }
196 if (current_offset != target_offset) {
197 debug(19, 1, "memFreeDataBehind: This shouldn't happen. Some odd condition.\n");
198 debug(19, 1, " Current offset: %d Target offset: %d p: %p\n",
199 current_offset, target_offset, p);
200 }
201 return current_offset;
202
203 }
204
205
206 /* Append incoming data. */
207 int memAppend(mem, data, len)
208 mem_ptr mem;
209 char *data;
210 int len;
211 {
212 mem_node p;
213 int avail_len;
214 int len_to_copy;
215
216 debug(19, 6, "memAppend: len %d\n", len);
217
218 /* Does the last block still contain empty space?
219 * If so, fill out the block before dropping into the
220 * allocation loop */
221
222 if (mem->head && mem->tail && (mem->tail->len < SM_PAGE_SIZE)) {
223 avail_len = SM_PAGE_SIZE - (mem->tail->len);
224 len_to_copy = min(avail_len, len);
225 xmemcpy((mem->tail->data + mem->tail->len), data, len_to_copy);
226 /* Adjust the ptr and len according to what was deposited in the page */
227 data += len_to_copy;
228 len -= len_to_copy;
229 mem->tail->len += len_to_copy;
230 }
231 while (len > 0) {
232 len_to_copy = min(len, SM_PAGE_SIZE);
233 p = xcalloc(1, sizeof(Mem_Node));
234 p->next = NULL;
235 p->len = len_to_copy;
236 p->data = get_free_4k_page();
237 xmemcpy(p->data, data, len_to_copy);
238
239 if (!mem->head) {
240 /* The chain is empty */
241 mem->head = mem->tail = p;
242 } else {
243 /* Append it to existing chain */
244 mem->tail->next = p;
245 mem->tail = p;
246 }
247 len -= len_to_copy;
248 data += len_to_copy;
249 }
250 return len;
251 }
252
253 #ifdef UNUSED_CODE
254 int memGrep(mem, string, nbytes)
255 mem_ptr mem;
256 char *string;
257 int nbytes;
258 {
259 mem_node p = mem->head;
260 char *str_i, *mem_i;
261 int i = 0, blk_idx = 0, state, goal;
262
263 debug(19, 6, "memGrep: looking for %s in less than %d bytes.\n",
264 string, nbytes);
265
266 if (!p)
267 return 0;
268
269 if (mem->origin_offset != 0) {
270 debug(19, 1, "memGrep: Some lower chunk of data has been erased. Can't do memGrep!\n");
271 return 0;
272 }
273 str_i = string;
274 mem_i = p->data;
275 state = 1;
276 goal = strlen(string);
277
278 while (i < nbytes) {
279 if (tolower(*mem_i++) == tolower(*str_i++))
280 state++;
281 else {
282 state = 1;
283 str_i = string;
284 }
285
286 i++;
287 blk_idx++;
288
289 /* Return offset of byte beyond the matching string */
290 if (state == goal)
291 return (i + 1);
292
293 if (blk_idx >= p->len) {
294 if (p->next) {
295 p = p->next;
296 mem_i = p->data;
297 blk_idx = 0;
298 } else
299 break;
300 }
301 }
302 return 0;
303 }
304 #endif
305
306 int memCopy(mem, offset, buf, size)
307 mem_ptr mem;
308 int offset;
309 char *buf;
310 int size;
311 {
312 mem_node p = mem->head;
313 int t_off = mem->origin_offset;
314 int bytes_to_go = size;
315 char *ptr_to_buf = NULL;
316 int bytes_from_this_packet = 0;
317 int bytes_into_this_packet = 0;
318
319 debug(19, 6, "memCopy: offset %d: size %d\n", offset, size);
320
321 if (p == NULL)
322 fatal_dump("memCopy: NULL mem_node");
323
324 if (size <= 0)
325 return size;
326
327 /* Seek our way into store */
328 while ((t_off + p->len) < offset) {
329 t_off += p->len;
330 if (p->next)
331 p = p->next;
332 else {
333 debug(19, 1, "memCopy: Offset: %d is off limit of current object of %d\n", t_off, offset);
334 return 0;
335 }
336 }
337
338 /* Start copying begining with this block until
339 * we're satiated */
340
341 bytes_into_this_packet = offset - t_off;
342 bytes_from_this_packet = min(bytes_to_go,
343 p->len - bytes_into_this_packet);
344
345 xmemcpy(buf, p->data + bytes_into_this_packet, bytes_from_this_packet);
346 bytes_to_go -= bytes_from_this_packet;
347 ptr_to_buf = buf + bytes_from_this_packet;
348 p = p->next;
349
350 while (p && bytes_to_go > 0) {
351 if (bytes_to_go > p->len) {
352 xmemcpy(ptr_to_buf, p->data, p->len);
353 ptr_to_buf += p->len;
354 bytes_to_go -= p->len;
355 } else {
356 xmemcpy(ptr_to_buf, p->data, bytes_to_go);
357 bytes_to_go -= bytes_to_go;
358 }
359 p = p->next;
360 }
361
362 return size;
363 }
364
365
366 /* Do whatever is necessary to begin storage of new object */
367 mem_ptr memInit()
368 {
369 mem_ptr new = xcalloc(1, sizeof(Mem_Hdr));
370 new->tail = new->head = NULL;
371 new->mem_free = memFree;
372 new->mem_free_data = memFreeData;
373 new->mem_free_data_upto = memFreeDataUpto;
374 new->mem_append = memAppend;
375 new->mem_copy = memCopy;
376 #ifdef UNUSED_CODE
377 new->mem_grep = memGrep;
378 #endif
379 return new;
380 }
381
382 static void *get_free_thing(thing)
383 stmem_stats *thing;
384 {
385 void *p = NULL;
386 if (!empty_stack(&thing->free_page_stack)) {
387 p = pop(&thing->free_page_stack);
388 if (p == NULL)
389 fatal_dump("get_free_thing: NULL pointer?");
390 } else {
391 p = xmalloc(thing->page_size);
392 thing->total_pages_allocated++;
393 }
394 thing->n_pages_in_use++;
395 memset(p, '\0', thing->page_size);
396 return p;
397 }
398
399 void *get_free_request_t()
400 {
401 return get_free_thing(&request_pool);
402 }
403
404 void *get_free_mem_obj()
405 {
406 return get_free_thing(&mem_obj_pool);
407 }
408
409 char *get_free_4k_page()
410 {
411 return get_free_thing(&sm_stats);
412 }
413
414 char *get_free_8k_page()
415 {
416 return get_free_thing(&disk_stats);
417 }
418
419 static void put_free_thing(thing, p)
420 stmem_stats *thing;
421 void *p;
422 {
423 thing->n_pages_in_use--;
424 if (thing->total_pages_allocated > thing->max_pages) {
425 xfree(p);
426 thing->total_pages_allocated--;
427 } else if (full_stack(&thing->free_page_stack)) {
428 xfree(p);
429 thing->total_pages_allocated--;
430 } else {
431 push(&thing->free_page_stack, p);
432 }
433 }
434
435 void put_free_request_t(req)
436 void *req;
437 {
438 put_free_thing(&request_pool, req);
439 }
440
441 void put_free_mem_obj(mem)
442 void *mem;
443 {
444 put_free_thing(&mem_obj_pool, mem);
445 }
446
447 void put_free_4k_page(page)
448 void *page;
449 {
450 put_free_thing(&sm_stats, page);
451 }
452
453 void put_free_8k_page(page)
454 void *page;
455 {
456 put_free_thing(&disk_stats, page);
457 }
458
459 void stmemInit()
460 {
461 sm_stats.page_size = SM_PAGE_SIZE;
462 sm_stats.total_pages_allocated = 0;
463 sm_stats.n_pages_free = 0;
464 sm_stats.n_pages_in_use = 0;
465 sm_stats.max_pages = (getCacheMemMax() / SM_PAGE_SIZE) >> 1;
466
467 disk_stats.page_size = DISK_PAGE_SIZE;
468 disk_stats.total_pages_allocated = 0;
469 disk_stats.n_pages_free = 0;
470 disk_stats.n_pages_in_use = 0;
471 disk_stats.max_pages = 200;
472
473 request_pool.page_size = sizeof(request_t);
474 request_pool.total_pages_allocated = 0;
475 request_pool.n_pages_free = 0;
476 request_pool.n_pages_in_use = 0;
477 request_pool.max_pages = FD_SETSIZE >> 3;
478
479 mem_obj_pool.page_size = sizeof(MemObject);
480 mem_obj_pool.total_pages_allocated = 0;
481 mem_obj_pool.n_pages_free = 0;
482 mem_obj_pool.n_pages_in_use = 0;
483 mem_obj_pool.max_pages = FD_SETSIZE >> 3;
484
485 #if PURIFY
486 sm_stats.max_pages = 0;
487 disk_stats.max_pages = 0;
488 request_pool.max_pages = 0;
489 mem_obj_pool.max_pages = 0;
490 #endif
491
492 init_stack(&sm_stats.free_page_stack, sm_stats.max_pages);
493 init_stack(&disk_stats.free_page_stack, disk_stats.max_pages);
494 init_stack(&request_pool.free_page_stack, request_pool.max_pages);
495 init_stack(&mem_obj_pool.free_page_stack, mem_obj_pool.max_pages);
496 }