1 |
/* |
2 |
* Ascend Pooled Memory Manager |
3 |
* by Benjamin Andrew Allan |
4 |
* Created: 2/96 |
5 |
* Version: $Revision: 1.1 $ |
6 |
* Version control file: $RCSfile: pool.c,v $ |
7 |
* Date last modified: $Date: 1997/07/18 11:37:01 $ |
8 |
* Last modified by: $Author: mthomas $ |
9 |
* |
10 |
* This file is part of the Ascend Language Interpreter. |
11 |
* |
12 |
* Copyright (C) 1996 Benjamin Andrew Allan |
13 |
* |
14 |
* The Ascend Language Interpreter is free software; you can redistribute |
15 |
* it and/or modify it under the terms of the GNU General Public License as |
16 |
* published by the Free Software Foundation; either version 2 of the |
17 |
* License, or (at your option) any later version. |
18 |
* |
19 |
* The Ascend Language Interpreter is distributed in hope that it will be |
20 |
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
22 |
* General Public License for more details. |
23 |
* |
24 |
* You should have received a copy of the GNU General Public License |
25 |
* along with the program; if not, write to the Free Software Foundation, |
26 |
* Inc., 675 Mass Ave, Cambridge, MA 02139 USA. Check the file named |
27 |
* COPYING. |
28 |
*/ |
29 |
|
30 |
#include <stdlib.h> |
31 |
|
32 |
#include "utilities/ascConfig.h" |
33 |
#include "utilities/ascMalloc.h" |
34 |
#include "general/pool.h" |
35 |
|
36 |
#ifndef FALSE |
37 |
#define FALSE 0 |
38 |
#define TRUE 1 |
39 |
#endif |
40 |
#ifdef NULL |
41 |
/* ok, so the machine has a NULL defined. */ |
42 |
#ifndef ISNULL |
43 |
/* and we've not got an ISNULL function */ |
44 |
#define ISNULL(a) ((a) == NULL) |
45 |
#define NOTNULL(a) ((a) != NULL) |
46 |
#endif /* isnull */ |
47 |
#endif /* null */ |
48 |
/* get local max and min definitions */ |
49 |
#ifdef PMN |
50 |
#undef PMN |
51 |
#undef PMX |
52 |
#endif |
53 |
#define PMN(a,b) ((a) < (b) ? (a) : (b)) |
54 |
#define PMX(a,b) ((a) < (b) ? (b) : (a)) |
55 |
|
56 |
/*********************** pool_store code. BAA 5/16/95 ***********************/ |
57 |
/* according to K&R2 char <--> byte and size_t is a byte count. |
58 |
We are coding with those assumptions. (sizeof(char)==1) */ |
59 |
#define OK 345676543 |
60 |
#define DESTROYED 765434567 |
61 |
#if pool_DEBUG |
62 |
/* ground LIGHTENING */ |
63 |
#undef pool_LIGHTENING |
64 |
#define pool_LIGHTENING FALSE |
65 |
#endif |
66 |
#define BYPASS_ASCMALLOC FALSE |
67 |
#if (pool_LIGHTENING || BYPASS_ASCMALLOC) |
68 |
/* gonna bypass ascmalloc, eh? ;-) shaame on you! */ |
69 |
#define PMEM_calloc(a,b) calloc(a,b) |
70 |
#define PMEM_malloc(a) malloc(a) |
71 |
#define PMEM_free(a) free(a) |
72 |
#define PMEM_realloc(a,b) realloc(a,b) |
73 |
#else |
74 |
#define PMEM_calloc(a,b) asccalloc(a,b) |
75 |
#define PMEM_malloc(a) ascmalloc(a) |
76 |
#define PMEM_free(a) ascfree(a) |
77 |
#define PMEM_realloc(a,b) ascrealloc(a,b) |
78 |
#endif |
79 |
|
80 |
/* |
81 |
Don't get caught taking the size of struct pool_element, |
82 |
It is the head for anonymous elements of any size. |
83 |
*/ |
84 |
struct pool_element { |
85 |
struct pool_element *nextelt; |
86 |
}; |
87 |
|
88 |
struct pool_store_header { |
89 |
int integrity; /* sanity number. */ |
90 |
/* actual data */ |
91 |
int maxlen; /* current length of pool, not necessarily w/bars full */ |
92 |
char **pool; /* array of pointers to bars */ |
93 |
struct pool_element *list; /* pointer to the most recently freed element */ |
94 |
|
95 |
/* some interesting book keeping quantities */ |
96 |
#if !pool_LIGHTENING |
97 |
long active; /* number of elements individually requested, ever */ |
98 |
long retned; /* number of elements individually returned, ever */ |
99 |
#endif |
100 |
size_t eltsize; /* size of element, often an unsigned (long) */ |
101 |
size_t eltsize_req; /* size of element, often an unsigned (long) */ |
102 |
size_t barsize; /* size of bar. no point in extra multiplications */ |
103 |
|
104 |
/* memory management quantities */ |
105 |
int len; /* number of bars filled (length of pool filled) */ |
106 |
int wid; /* num elements in a bar */ |
107 |
int expand; /* number of bars to expand by usually */ |
108 |
int growpool; /* expansion increment for pool array */ |
109 |
int curbar; /* pool entry from which fresh elements may be had */ |
110 |
int curelt; /* number of the next element in the curbar to hand out */ |
111 |
int onlist; /* length of recycle list, in elements */ |
112 |
#if !pool_LIGHTENING |
113 |
int total; /* total number of elements in this store */ |
114 |
int highwater; /* fresh elements turned loose from store */ |
115 |
int inuse; /* current elts user has outstanding */ |
116 |
#endif |
117 |
}; |
118 |
/* notes on header: |
119 |
* list is, as currently coded, null terminated by accident. |
120 |
* The intent of the author is that the counter onlist is the |
121 |
* authoritative list length. |
122 |
*/ |
123 |
|
124 |
#define PMEM_MINBARSIZE 5 |
125 |
#define PMEM_MINPOOLSIZE 2 |
126 |
#ifdef __alpha |
127 |
#define PMEM_MINPOOLGROW 128 |
128 |
/* gotta love those fat pointers. grow by 4k min. */ |
129 |
#else |
130 |
#define PMEM_MINPOOLGROW 256 |
131 |
#endif |
132 |
|
133 |
/* |
134 |
Returns 2 if really bad, 1 if something fishy, 0 otherwise. |
135 |
*/ |
136 |
static int check_pool_store(const pool_store_t ps) |
137 |
{ |
138 |
#if pool_LIGHTENING |
139 |
return 0; |
140 |
#else |
141 |
int i; |
142 |
|
143 |
if (ISNULL(ps)) { |
144 |
FPRINTF(ASCERR,"check_pool_store (pool.c): NULL pool_store_t!\n"); |
145 |
return 2; |
146 |
} |
147 |
if (ps->integrity != OK) { |
148 |
(ps->integrity == DESTROYED) ? |
149 |
FPRINTF(ASCERR, |
150 |
"check_pool_store (pool.c): pool_store_t recently destroyed!\n") |
151 |
: FPRINTF(ASCERR, |
152 |
"check_pool_store (pool.c): pool_store_t corrupted!\n"); |
153 |
return 2; |
154 |
} |
155 |
if (ps->onlist && ISNULL(ps->list)) { |
156 |
FPRINTF(ASCERR, "ERROR: check_pool_store (pool.c): NULL recycle list!\n"); |
157 |
return 1; |
158 |
} |
159 |
/* more in than out? */ |
160 |
if (ps->retned > ps->active) { |
161 |
FPRINTF(ASCERR, "ERROR: check_pool_store (pool.c): Imbalanced memory.\n"); |
162 |
return 1; |
163 |
} |
164 |
if (ps->onlist + ps->inuse != ps->highwater) { |
165 |
FPRINTF(ASCERR,"ERROR: check_pool_store (pool.c): Imbalanced elements.\n"); |
166 |
return 1; |
167 |
} |
168 |
/* is pool allocated to ps->len? */ |
169 |
for (i=0; i < ps->len; i++) { |
170 |
if (ISNULL(ps->pool[i])) { |
171 |
FPRINTF(ASCERR, |
172 |
"ERROR: check_pool_store (pool.c): Hole found in pool!\n"); |
173 |
FPRINTF(ASCERR, " Bar %d is NULL.\n",i); |
174 |
return 2; |
175 |
} |
176 |
} |
177 |
/* do not check for integrity or count of recycle list elements. */ |
178 |
return 0; |
179 |
#endif |
180 |
} |
181 |
|
182 |
/* |
183 |
This should not be called unless all current store is in use. |
184 |
Returns 0 if ok, 1 for all other insanities. |
185 |
If only partial expansion is possible, we will do it and |
186 |
return 0. If change in ps->len is < the expected incremented value |
187 |
on return, the user knows he should do some garbage removal. |
188 |
incr is provided for times when we know how much we want |
189 |
to expand by. |
190 |
|
191 |
This should never be called on a totally empty pool. |
192 |
*/ |
193 |
static int expand_store(pool_store_t ps, int incr) |
194 |
{ |
195 |
static int oldsize, newsize,punt,i; |
196 |
char **newpool = NULL; |
197 |
if (check_pool_store(ps) >1) { |
198 |
FPRINTF(ASCERR,"ERROR: (pool.c) expand_store received bad\n"); |
199 |
FPRINTF(ASCERR," pool_store_t. Expansion failed.\n"); |
200 |
return 1; |
201 |
} |
202 |
|
203 |
#if !pool_LIGHTENING |
204 |
/* do not expand elements or pool if all is not in use */ |
205 |
if (ps->inuse < ps->total) { |
206 |
FPRINTF(ASCERR,"ERROR: (pool.c) expand_store called prematurely.\n"); |
207 |
FPRINTF(ASCERR," Expansion will be reported as failed.\n"); |
208 |
return 1; |
209 |
} |
210 |
#endif |
211 |
|
212 |
/* make sure bar expansion is at least the minimum */ |
213 |
if (incr < ps->expand) incr = ps->expand; |
214 |
oldsize = ps->len; |
215 |
newsize = oldsize+incr; |
216 |
|
217 |
/* expand pool capacity only if all of pool in use */ |
218 |
if (newsize > ps->maxlen) { |
219 |
i = ps->maxlen + PMX(ps->growpool,incr); |
220 |
newpool = (char **)PMEM_realloc(ps->pool, i*sizeof(char *)); |
221 |
if (ISNULL(newpool)) { |
222 |
FPRINTF(ASCERR,"ERROR: (pool.c) expand_store can't realloc pool.\n"); |
223 |
return 1; |
224 |
} |
225 |
/* NULL the new pool */ |
226 |
for (punt = ps->maxlen; punt < i; punt++) { |
227 |
newpool[punt] = NULL; |
228 |
} |
229 |
ps->maxlen = i; |
230 |
ps->pool = newpool; |
231 |
} |
232 |
/* end of pool expansion */ |
233 |
|
234 |
/* expand elements/bars */ |
235 |
ps->len = newsize; /* set expanded number of bars filled */ |
236 |
punt = -1; |
237 |
for (i = oldsize; i < newsize; i++) { |
238 |
#if pool_DEBUG |
239 |
ps->pool[i] = (char *)PMEM_calloc(ps->barsize,1); |
240 |
#else |
241 |
ps->pool[i] = (char *)PMEM_malloc(ps->barsize); |
242 |
#endif |
243 |
if (ISNULL(ps->pool[i])) { |
244 |
punt = i; |
245 |
/* we will return partially expanded if possible */ |
246 |
break; |
247 |
} |
248 |
} |
249 |
if (punt >= 0) { |
250 |
/* incomplete expansion */ |
251 |
if (punt == oldsize) { |
252 |
/* unable to add elements at all. fail */ |
253 |
FPRINTF(ASCERR,"ERROR: (pool) expand_store: Insufficient memory.\n"); |
254 |
ps->len = oldsize; |
255 |
return 1; |
256 |
} else { |
257 |
/* contract pool to the actual expansion size */ |
258 |
FPRINTF(ASCERR,"WARNING: (pool) expand_store: Insufficient memory.\n"); |
259 |
FPRINTF(ASCERR," Doing partial expansion.\n"); |
260 |
ps->len = punt; |
261 |
} |
262 |
} |
263 |
#if !pool_LIGHTENING |
264 |
ps->total = ps->len * ps->wid; |
265 |
#endif |
266 |
return 0; |
267 |
} |
268 |
|
269 |
#if !pool_LIGHTENING |
270 |
#if pool_DEBUG |
271 |
/* |
272 |
Returns 1 if pointer is to an elt of the store, 0 otherwise. |
273 |
The case of pointer into store reserved space, but not an elt is checked. |
274 |
*/ |
275 |
static int from_store( pool_store_t ps, void *elt) |
276 |
{ |
277 |
char *data, **pool; |
278 |
int i,lim; |
279 |
|
280 |
if (ISNULL(ps) || ISNULL(elt)) return 0; |
281 |
lim = ps->len; |
282 |
pool = ps->pool; |
283 |
data = (char *)elt; |
284 |
for (i=0; i<lim; i++) { |
285 |
/* did the char come from the current bar of chars? */ |
286 |
if (*pool <= data && data < *pool + ps->barsize) { |
287 |
/* if so, is it legal? */ |
288 |
if ( !((data - (*pool)) % ps->eltsize) ) { |
289 |
return 1; |
290 |
} else { |
291 |
FPRINTF(ASCERR,"ERROR: (pool.c) from_store: Misaligned element\n"); |
292 |
FPRINTF(ASCERR," pointer detected.\n"); |
293 |
return 0; |
294 |
} |
295 |
} |
296 |
pool++; |
297 |
} |
298 |
return 0; |
299 |
} |
300 |
#endif |
301 |
#endif |
302 |
|
303 |
void pool_get_stats(struct pool_statistics *pss, pool_store_t m) |
304 |
{ |
305 |
if (ISNULL(pss)) { |
306 |
FPRINTF(ASCERR,"ERROR: (pool_get_stats) Called with NULL struct\n"); |
307 |
FPRINTF(ASCERR," pool_statistics.\n"); |
308 |
return; |
309 |
} |
310 |
if (check_pool_store(m)>1 ) { |
311 |
ascbzero((void *)pss,(int)sizeof(struct pool_statistics)); |
312 |
FPRINTF(ASCERR,"ERROR: (pool_get_stats) Bad pool_store_t given.\n"); |
313 |
FPRINTF(ASCERR," Returning 0s.\n"); |
314 |
return; |
315 |
} |
316 |
#if !pool_LIGHTENING |
317 |
pss->p_eff = m->inuse*m->eltsize_req/(double)pool_sizeof_store(m); |
318 |
pss->p_recycle = |
319 |
( (m->highwater > 0) ? m->active/(double)m->highwater : 0.0 ); |
320 |
pss->elt_total = m->total; |
321 |
pss->elt_taken = m->highwater; |
322 |
pss->elt_inuse = m->inuse; |
323 |
#else |
324 |
pss->p_eff = 0.0; |
325 |
pss->p_recycle = 0.0; |
326 |
pss->elt_total = m->len*m->wid; |
327 |
pss->elt_taken = m->curelt+m->curbar*m->wid; |
328 |
pss->elt_inuse = 0; |
329 |
#endif |
330 |
pss->elt_onlist = m->onlist; |
331 |
pss->elt_size = m->eltsize; |
332 |
pss->str_len = m->len; |
333 |
pss->str_wid = m->wid; |
334 |
} |
335 |
|
336 |
pool_store_t pool_create_store(int length, int width, |
337 |
size_t eltsize, int deltalen, int deltapool) |
338 |
{ |
339 |
int i, punt; |
340 |
pool_store_t newps=NULL; |
341 |
size_t uelt; |
342 |
|
343 |
if (length < 1 || width < 1 || deltalen < 1 ) { |
344 |
FPRINTF(ASCERR,"ERROR: (pool_create_store) : Bad input detected.\n"); |
345 |
return NULL; |
346 |
} |
347 |
|
348 |
/* check minsizes */ |
349 |
if (length < PMEM_MINPOOLSIZE) length = PMEM_MINPOOLSIZE; |
350 |
if (width < PMEM_MINBARSIZE) width = PMEM_MINBARSIZE; |
351 |
/* maybe the user gave us length = max he knows he needs, so we |
352 |
will not enforce a minimum maxlen on length at creation */ |
353 |
|
354 |
uelt = eltsize; |
355 |
/* check for elt padding needed */ |
356 |
if (eltsize % sizeof(void *)) { |
357 |
int ptrperelt; |
358 |
ptrperelt = eltsize/sizeof(void *) + 1; |
359 |
#if pool_DEBUG |
360 |
FPRINTF(ASCERR,"(pool_create_store) Elts of size %d padded to %d\n", |
361 |
(int)eltsize,(int)(eltsize=ptrperelt*sizeof(void *))); |
362 |
#else |
363 |
eltsize = ptrperelt*sizeof(void *); |
364 |
#endif |
365 |
} |
366 |
/* eltsize is now pointer alignable */ |
367 |
/* it could still be user data misalignable, of course, if pointer |
368 |
is not the most restrictive data type for the machine */ |
369 |
|
370 |
|
371 |
newps = (pool_store_t)PMEM_calloc(1,sizeof(struct pool_store_header)); |
372 |
if (ISNULL(newps)) { |
373 |
FPRINTF(ASCERR,"ERROR: (pool_create_store) : Insufficient memory.\n"); |
374 |
return NULL; |
375 |
} |
376 |
/* the following are all initially 0/NULL by calloc, and should be: |
377 |
newps->list |
378 |
newps->active |
379 |
newps->retned |
380 |
newps->curbar |
381 |
newps->curelt |
382 |
newps->highwater |
383 |
newps->onlist |
384 |
newps->inuse |
385 |
newps->pool |
386 |
*/ |
387 |
newps->integrity = OK; |
388 |
newps->len = length; |
389 |
newps->maxlen = length; |
390 |
newps->wid = width; |
391 |
newps->expand = deltalen; |
392 |
newps->eltsize = eltsize; |
393 |
newps->barsize = eltsize * width; |
394 |
#if !pool_LIGHTENING |
395 |
newps->total = length * width; |
396 |
#endif |
397 |
newps->growpool = PMX(PMEM_MINPOOLGROW,deltapool); |
398 |
newps->eltsize_req = uelt; |
399 |
|
400 |
/* get pool */ |
401 |
newps->pool = (char **)PMEM_calloc(length,sizeof(char *)); |
402 |
if (ISNULL(newps->pool)) { |
403 |
FPRINTF(ASCERR,"ERROR: (pool_create_store) : Insufficient memory.\n"); |
404 |
newps->integrity = DESTROYED; |
405 |
PMEM_free(newps); |
406 |
return NULL; |
407 |
} |
408 |
|
409 |
/* fill it */ |
410 |
punt = -1; |
411 |
for (i=0; i < length; i++) { |
412 |
newps->pool[i] = (char *)PMEM_malloc(newps->barsize); |
413 |
if (ISNULL(newps->pool[i])) { |
414 |
punt = i; /* we will stop cleanup deallocation at punt-1 */ |
415 |
break; |
416 |
} |
417 |
} |
418 |
|
419 |
/* drain it if can't fill it */ |
420 |
if (punt != -1) { |
421 |
FPRINTF(ASCERR,"ERROR: (pool_create_store) : Insufficient memory.\n"); |
422 |
for (i = 0; i < punt; i++) { |
423 |
PMEM_free(newps->pool[i]); |
424 |
} |
425 |
newps->integrity = DESTROYED; |
426 |
PMEM_free(newps->pool); |
427 |
PMEM_free(newps); |
428 |
return NULL; |
429 |
} |
430 |
return newps; |
431 |
} |
432 |
|
433 |
void *pool_get_element(pool_store_t ps) |
434 |
{ |
435 |
/* no automatic variables please */ |
436 |
register struct pool_element *elt; |
437 |
/* in a test on the alpha, though, making elt static global slowed it */ |
438 |
|
439 |
if (ISNULL(ps)) { |
440 |
FPRINTF(ASCERR,"ERROR: (pool_get_element) Called with NULL store.\n"); |
441 |
return NULL; |
442 |
} |
443 |
/* recycling */ |
444 |
if (ps->onlist) { |
445 |
elt = ps->list; /* get last element put into list */ |
446 |
ps->list = ps->list->nextelt; /* pop list */ |
447 |
/* preserves original null if list is empty */ |
448 |
ps->onlist--; |
449 |
#if !pool_LIGHTENING |
450 |
ps->inuse++; |
451 |
ps->active++; |
452 |
#endif |
453 |
return (void *)elt; |
454 |
} |
455 |
|
456 |
/* fresh element */ |
457 |
if (ps->curelt == ps->wid) { |
458 |
/* bump up pool if bar all allocated */ |
459 |
ps->curelt = 0; |
460 |
ps->curbar++; |
461 |
} |
462 |
if (ps->curbar == ps->len) { |
463 |
/* attempt to expand pool if all allocated */ |
464 |
if ( expand_store(ps,1) ) { |
465 |
FPRINTF(ASCERR,"ERROR: (pool_get_element) Insufficient memory.\n"); |
466 |
return NULL; |
467 |
} |
468 |
} |
469 |
/* if we got here, pool is big enough to grab an element from */ |
470 |
|
471 |
/* get the pointer to an element's worth of char from the pool */ |
472 |
elt = |
473 |
(struct pool_element *) &(ps->pool[ps->curbar][ps->curelt * ps->eltsize]); |
474 |
ps->curelt++; |
475 |
#if !pool_LIGHTENING |
476 |
ps->inuse++; |
477 |
ps->highwater++; |
478 |
ps->active++; |
479 |
#endif |
480 |
return (void *)elt; |
481 |
} |
482 |
|
483 |
void pool_get_element_list(pool_store_t ps, int nelts, void **ary) |
484 |
{ |
485 |
FPRINTF(ASCERR,"ERROR: pool_get_element_list NOT implemented\n"); |
486 |
if (ISNULL(ps) || ISNULL(ary)) { |
487 |
FPRINTF(ASCERR,"ERROR: pool_get_element_list Called with NULL\n"); |
488 |
FPRINTF(ASCERR," array or pool_store_t"); |
489 |
return; |
490 |
} |
491 |
if (nelts <1) { |
492 |
FPRINTF(ASCERR,"WARNING: pool_get_element_list Called with request\n"); |
493 |
FPRINTF(ASCERR," for 0 elements."); |
494 |
return; |
495 |
} |
496 |
ary[0]=NULL; |
497 |
} |
498 |
|
499 |
void pool_free_elementF(pool_store_t ps, void *ptr |
500 |
#if pool_DEBUG |
501 |
, CONST char *fn |
502 |
#endif |
503 |
) |
504 |
{ |
505 |
register struct pool_element *elt; |
506 |
|
507 |
if (ISNULL(ptr)) return; |
508 |
elt = (struct pool_element *)ptr; |
509 |
|
510 |
#if !pool_LIGHTENING |
511 |
#if pool_DEBUG |
512 |
if (check_pool_store(ps)) { |
513 |
FPRINTF(ASCERR,"ERROR: (pool_free_element) Fishy pool_store_t.\n"); |
514 |
FPRINTF(ASCERR," Element not recycled.\n"); |
515 |
FPRINTF(ASCERR,"%s\n",fn); |
516 |
return; |
517 |
/* at this point we have no way to get back at the abandoned element */ |
518 |
} |
519 |
/* check for belongs to this pool_store_t */ |
520 |
if (!from_store(ps,ptr)) { |
521 |
FPRINTF(ASCERR,"ERROR: (pool_free_element) Spurious element detected.\n"); |
522 |
FPRINTF(ASCERR," Element ignored.\n"); |
523 |
FPRINTF(ASCERR,"%s\n",fn); |
524 |
return; |
525 |
} |
526 |
#endif |
527 |
#endif |
528 |
|
529 |
/* recycle him */ |
530 |
elt->nextelt = ps->list; /* push onto list */ |
531 |
/* first one in will pick up the null list starts as */ |
532 |
ps->list = elt; |
533 |
/* ptr now on lifo stack in elt linked list form */ |
534 |
ps->onlist++; |
535 |
|
536 |
#if !pool_LIGHTENING |
537 |
ps->retned++; |
538 |
ps->inuse--; |
539 |
if (ps->inuse < 0) { |
540 |
FPRINTF(ASCERR,"ERROR: (pool_free_element) More elements freed than\n"); |
541 |
FPRINTF(ASCERR," have been handed out. (%d)\n", |
542 |
abs(ps->inuse)); |
543 |
#if pool_DEBUG |
544 |
FPRINTF(ASCERR,"%s\n",fn); |
545 |
#endif |
546 |
} |
547 |
#endif |
548 |
return; |
549 |
} |
550 |
|
551 |
void pool_clear_storeF(pool_store_t ps |
552 |
#if pool_DEBUG |
553 |
, CONST char *fn |
554 |
#endif |
555 |
) { |
556 |
if ( check_pool_store(ps) > 1 ) { |
557 |
FPRINTF(ASCERR,"ERROR: (pool_clear_store) Bad pool_store_t given.\n"); |
558 |
FPRINTF(ASCERR," Not cleared.\n"); |
559 |
#if pool_DEBUG |
560 |
FPRINTF(ASCERR,"%s\n",fn); |
561 |
#endif |
562 |
return; |
563 |
} |
564 |
#if pool_DEBUG |
565 |
if (ps->inuse || ps->highwater - ps->onlist ) { |
566 |
FPRINTF(ASCERR,"WARNING: (pool_clear_store) In use elements in given\n"); |
567 |
FPRINTF(ASCERR," pool_store_t are cleared.\n"); |
568 |
FPRINTF(ASCERR," Don't refer to them again.\n"); |
569 |
FPRINTF(ASCERR,"%s\n",fn); |
570 |
} |
571 |
#endif |
572 |
#if !pool_LIGHTENING |
573 |
ps->retned += ps->inuse; |
574 |
if (ps->active - ps->retned || |
575 |
ps->onlist + ps->inuse - ps->highwater || |
576 |
ps->curelt + ps->curbar*ps->wid - ps->highwater) { |
577 |
FPRINTF(ASCERR,"Warning: pool_clear_store: Element imbalance detected.\n"); |
578 |
#if pool_DEBUG |
579 |
FPRINTF(ASCERR,"%s\n",fn); |
580 |
#endif |
581 |
} |
582 |
#endif |
583 |
#if !pool_LIGHTENING |
584 |
ps->inuse = 0; |
585 |
ps->highwater = 0; |
586 |
#endif |
587 |
ps->curbar = 0; |
588 |
ps->curelt = 0; |
589 |
ps->onlist = 0; |
590 |
ps->list = NULL; |
591 |
} |
592 |
|
593 |
void pool_destroy_store(pool_store_t ps) |
594 |
{ |
595 |
int i; |
596 |
#if pool_DEBUG |
597 |
if ( (i=check_pool_store(ps))==2 ) { |
598 |
FPRINTF(ASCERR,"ERROR: (pool_destroy_store) Bad pool_store_t given.\n"); |
599 |
FPRINTF(ASCERR," Not destroyed.\n"); |
600 |
return; |
601 |
} |
602 |
if ( i ) { |
603 |
FPRINTF(ASCERR, |
604 |
"WARNING: (pool_destroy_store) Suspicious pool_store_t given.\n"); |
605 |
FPRINTF(ASCERR," Destroyed anyway.\n"); |
606 |
return; |
607 |
} |
608 |
if (ps->inuse || ps->highwater - ps->onlist ) { |
609 |
FPRINTF(ASCERR,"WARNING: (pool_destroy_store) In use elements in given\n"); |
610 |
FPRINTF(ASCERR," pool_store_t are cleared.\n"); |
611 |
FPRINTF(ASCERR, |
612 |
" Don't refer to them again.\n"); |
613 |
} |
614 |
#else |
615 |
if (ISNULL(ps) || ps->integrity != OK) { |
616 |
FPRINTF(ASCERR,"ERROR: (pool_destroy_store) Bad pool_store_t given.\n"); |
617 |
FPRINTF(ASCERR," Not destroyed.\n"); |
618 |
return; |
619 |
} |
620 |
#endif |
621 |
for (i=0; i < ps->len; i++) { |
622 |
PMEM_free(ps->pool[i]); |
623 |
} |
624 |
PMEM_free(ps->pool); |
625 |
ps->integrity = DESTROYED; |
626 |
PMEM_free(ps); |
627 |
return; |
628 |
} |
629 |
|
630 |
void pool_print_store(FILE *fp, pool_store_t ps, unsigned detail) |
631 |
{ |
632 |
if (ISNULL(fp) || ISNULL(ps)) { |
633 |
FPRINTF(ASCERR,"ERROR: (pool_print_store) Called with NULL\n"); |
634 |
FPRINTF(ASCERR," FILE or pool_store_t\n"); |
635 |
return; |
636 |
} |
637 |
if (check_pool_store(ps)>1) { |
638 |
FPRINTF(ASCERR,"ERROR: (pool_print_store) Called with bad pool_store_t\n"); |
639 |
return; |
640 |
} |
641 |
FPRINTF(fp,"pool_store_t statistics:\n"); |
642 |
if (detail) { |
643 |
FPRINTF(fp,"INTERNAL (integrity OK if = %d):\n",OK); |
644 |
FPRINTF(fp,"%-30s %-20d\n","integrity",ps->integrity); |
645 |
#if !pool_LIGHTENING |
646 |
FPRINTF(fp,"%-30s %-20ld\n","active",ps->active); |
647 |
FPRINTF(fp,"%-30s %-20ld\n","returned",ps->retned); |
648 |
#endif |
649 |
FPRINTF(fp,"%-30s %-20lu\n","eltsize",(unsigned long)ps->eltsize); |
650 |
FPRINTF(fp,"%-30s %-20lu\n","barsize",(unsigned long)ps->barsize); |
651 |
FPRINTF(fp,"%-30s %-20d\n","pool length",ps->len); |
652 |
FPRINTF(fp,"%-30s %-20d\n","pool maxlength",ps->maxlen); |
653 |
FPRINTF(fp,"%-30s %-20d\n","bar width",ps->wid); |
654 |
FPRINTF(fp,"%-30s %-20d\n","pool extension",ps->growpool); |
655 |
FPRINTF(fp,"%-30s %-20d\n","pool fill rate",ps->expand); |
656 |
FPRINTF(fp,"%-30s %-20d\n","current bar",ps->curbar); |
657 |
FPRINTF(fp,"%-30s %-20d\n","current elt",ps->curelt); |
658 |
#if !pool_LIGHTENING |
659 |
FPRINTF(fp,"%-30s %-20d\n","total elts",ps->total); |
660 |
FPRINTF(fp,"%-30s %-20d\n","highwater",ps->highwater); |
661 |
#endif |
662 |
FPRINTF(fp,"%-30s %-20d\n","elt on list",ps->onlist); |
663 |
#if !pool_LIGHTENING |
664 |
FPRINTF(fp,"%-30s %-20d\n","elt in use",ps->inuse); |
665 |
#endif |
666 |
} |
667 |
if (!detail || detail > 1) { |
668 |
FPRINTF(fp,"SUMMARY:\n"); |
669 |
FPRINTF(fp,"%-30s %-20d\n","Pointers in pool",ps->maxlen); |
670 |
FPRINTF(fp,"%-30s %-20d\n","Pointers allocated",ps->len); |
671 |
#if !pool_LIGHTENING |
672 |
FPRINTF(fp,"%-30s %-20d\n","Elements in pool",ps->total); |
673 |
FPRINTF(fp,"%-30s %-20d\n","Elements in use",ps->inuse); |
674 |
#endif |
675 |
FPRINTF(fp,"%-30s %-20d\n","Elements waiting recycle",ps->onlist); |
676 |
#if !pool_LIGHTENING |
677 |
FPRINTF(fp,"%-30s %-20d\n","Elements unused",ps->total - ps->highwater); |
678 |
#endif |
679 |
FPRINTF(fp,"%-30s %-20d\n","Working deltapool",ps->growpool); |
680 |
FPRINTF(fp,"%-30s %-20d\n","Working deltalen",ps->expand); |
681 |
FPRINTF(fp,"%-30s %-20g\n","Element efficiency", |
682 |
ps->eltsize_req/(double)ps->eltsize); |
683 |
#if !pool_LIGHTENING |
684 |
FPRINTF(fp,"%-30s %-20g\n","Memory efficiency (w/recycle)", |
685 |
ps->highwater*ps->eltsize_req/(double)pool_sizeof_store(ps)); |
686 |
FPRINTF(fp,"%-30s %-20g\n","Memory efficiency (instant)", |
687 |
ps->inuse*ps->eltsize_req/(double)pool_sizeof_store(ps)); |
688 |
FPRINTF(fp,"%-30s %-20g\n","Recycle rate", |
689 |
((ps->highwater > 0) ? ps->active/(double)ps->highwater : 0) ); |
690 |
#endif |
691 |
} |
692 |
FPRINTF(fp,"%-30s %-20lu\n","Total bytes in store", |
693 |
(unsigned long)pool_sizeof_store(ps)); |
694 |
|
695 |
return; |
696 |
} |
697 |
|
698 |
size_t pool_sizeof_store(pool_store_t ps) |
699 |
{ |
700 |
register size_t siz; |
701 |
if (check_pool_store(ps)>1) return (size_t)0; |
702 |
siz = sizeof(struct pool_store_header); /* header */ |
703 |
siz += ps->barsize * ps->len; /* elt data */ |
704 |
return (siz += ps->maxlen*sizeof(char*)); /* pool vector */ |
705 |
} |