1 |
/* |
2 |
* Memory module |
3 |
* by Karl Westerberg, Ben Allan |
4 |
* Created: 6/90 |
5 |
* Version: $Revision: 1.7 $ |
6 |
* Version control file: $RCSfile: mem.c,v $ |
7 |
* Date last modified: $Date: 1998/01/10 18:00:06 $ |
8 |
* Last modified by: $Author: ballan $ |
9 |
* |
10 |
* This file is part of the Ascend Language Interpreter. |
11 |
* |
12 |
* Copyright (C) 1997 Carnegie Mellon University |
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 "ascConfig.h" |
31 |
#include "ascMalloc.h" |
32 |
#include "mem.h" |
33 |
#include <general/mathmacros.h> |
34 |
|
35 |
static void move_fwd(POINTER from, POINTER too, size_t nbytes) |
36 |
/** |
37 |
*** Copies bytes from --> too in forward direction. |
38 |
**/ |
39 |
{ |
40 |
while( nbytes-- > 0 ) |
41 |
*(too++) = *(from++); |
42 |
} |
43 |
|
44 |
static void move_bwd(POINTER from, POINTER too, size_t nbytes) |
45 |
/** |
46 |
*** Copies bytes from --> too in backward direction. |
47 |
**/ |
48 |
{ |
49 |
from += nbytes; |
50 |
too += nbytes; |
51 |
while( nbytes-- > 0 ) |
52 |
*(--too) = *(--from); |
53 |
} |
54 |
|
55 |
void mem_move_disjoint(POINTER from, POINTER too, size_t nbytes) |
56 |
{ |
57 |
ascbcopy((char *)from,(char *)too,nbytes); |
58 |
} |
59 |
|
60 |
void mem_move(POINTER from, POINTER too,size_t nbytes) |
61 |
{ |
62 |
if( from < too ) |
63 |
move_bwd(from,too,nbytes); |
64 |
else |
65 |
move_fwd(from,too,nbytes); |
66 |
} |
67 |
|
68 |
/* zeroes nbytes of memory pointed at by too. byte is ignored but |
69 |
* there for interchangability with mem_repl_byte |
70 |
*/ |
71 |
void mem_zero_byte(POINTER too, unsigned byte, size_t nbytes) |
72 |
{ |
73 |
(void)byte; |
74 |
ascbzero((void *)too,(size_t)nbytes); |
75 |
/* |
76 |
* while( nbytes-- > 0 ) |
77 |
* *(too++) = 0; |
78 |
*/ |
79 |
} |
80 |
|
81 |
void mem_repl_byte(POINTER too, unsigned byte, size_t nbytes) |
82 |
{ |
83 |
while( nbytes-- > 0 ) |
84 |
*(too++) = (char)byte; |
85 |
} |
86 |
|
87 |
void mem_repl_word(POINTER too,unsigned word, size_t nwords) |
88 |
{ |
89 |
unsigned *pw = (unsigned *)too; |
90 |
while( nwords-- > 0 ) |
91 |
*(pw++) = word; |
92 |
} |
93 |
|
94 |
#define mv_get(too,from,nbytes) move_fwd((POINTER)(from),(POINTER)(too),nbytes) |
95 |
#define mv_set(from,too,nbytes) move_fwd((POINTER)(from),(POINTER)(too),nbytes) |
96 |
|
97 |
#if 0 |
98 |
int mem_get_byte(long from) |
99 |
{ |
100 |
char c; |
101 |
mv_get(&c,from,1); |
102 |
return( ((int)c) & mask_I_L(BYTESIZE) ); |
103 |
} |
104 |
#endif /* 0 */ |
105 |
unsigned char mem_get_byte(long from) |
106 |
{ |
107 |
unsigned char c; |
108 |
mv_get(&c, from, 1); |
109 |
return(c); |
110 |
} |
111 |
|
112 |
int mem_get_int(long from) |
113 |
{ |
114 |
int i; |
115 |
mv_get(&i,from,sizeof(int)); |
116 |
return(i); |
117 |
} |
118 |
|
119 |
long mem_get_long(long from) |
120 |
{ |
121 |
long l; |
122 |
mv_get(&l,from,sizeof(long)); |
123 |
return(l); |
124 |
} |
125 |
|
126 |
double mem_get_float(long from) |
127 |
{ |
128 |
float f; |
129 |
mv_get(&f,from,sizeof(float)); |
130 |
return((double)f); |
131 |
} |
132 |
|
133 |
double mem_get_double(long from) |
134 |
{ |
135 |
double d; |
136 |
mv_get(&d,from,sizeof(double)); |
137 |
return(d); |
138 |
} |
139 |
|
140 |
void mem_set_byte(long from, int b) |
141 |
{ |
142 |
char c = (char)b; |
143 |
mv_set(&c,from,1); |
144 |
} |
145 |
|
146 |
void mem_set_int(long from, int i) |
147 |
{ |
148 |
mv_set(&i,from,sizeof(int)); |
149 |
} |
150 |
|
151 |
void mem_set_long(long from, long l) |
152 |
{ |
153 |
mv_set(&l,from,sizeof(long)); |
154 |
} |
155 |
|
156 |
void mem_set_float(long from, double f) |
157 |
{ |
158 |
float ff = (float)f; |
159 |
mv_set(&ff,from,sizeof(float)); |
160 |
} |
161 |
|
162 |
void mem_set_double(long from, double d) |
163 |
{ |
164 |
mv_set(&d,from,sizeof(double)); |
165 |
} |
166 |
|
167 |
/*********************** mem_store code. BAA 5/16/95 ***********************/ |
168 |
/* according to K&R2 char <--> byte and size_t is a byte count. |
169 |
We are coding with those assumptions. (sizeof(char)==1) */ |
170 |
#define OK 345676543 |
171 |
#define DESTROYED 765434567 |
172 |
#if mem_DEBUG |
173 |
/* ground LIGHTENING */ |
174 |
#undef mem_LIGHTENING |
175 |
#define mem_LIGHTENING FALSE |
176 |
#endif |
177 |
#define BYPASS_ASCMALLOC FALSE |
178 |
#if (mem_LIGHTENING || BYPASS_ASCMALLOC) |
179 |
/* gonna bypass ascmalloc, eh? ;-) shaame on you! */ |
180 |
#define AMEM_calloc(a,b) calloc(a,b) |
181 |
#define AMEM_malloc(a) malloc(a) |
182 |
#define AMEM_free(a) free(a) |
183 |
#define AMEM_realloc(a,b) realloc(a,b) |
184 |
#else |
185 |
#define AMEM_calloc(a,b) asccalloc(a,b) |
186 |
#define AMEM_malloc(a) ascmalloc(a) |
187 |
#define AMEM_free(a) ascfree(a) |
188 |
#define AMEM_realloc(a,b) ascrealloc(a,b) |
189 |
#endif |
190 |
|
191 |
/* |
192 |
Don't get caught taking the size of struct mem_element, |
193 |
It is the head for anonymous elements of any size. |
194 |
*/ |
195 |
struct mem_element { |
196 |
struct mem_element *nextelt; |
197 |
}; |
198 |
|
199 |
struct mem_store_header { |
200 |
int integrity; /* sanity number. */ |
201 |
/* actual data */ |
202 |
int maxlen; /* current length of pool, not necessarily w/bars full */ |
203 |
char **pool; /* array of pointers to bars */ |
204 |
struct mem_element *list; /* pointer to the most recently freed element */ |
205 |
|
206 |
/* some interesting book keeping quantities */ |
207 |
#if !mem_LIGHTENING |
208 |
long active; /* number of elements individually requested, ever */ |
209 |
long retned; /* number of elements individually returned, ever */ |
210 |
#endif |
211 |
size_t eltsize; /* size of element, often an unsigned (long) */ |
212 |
size_t eltsize_req; /* size of element, often an unsigned (long) */ |
213 |
size_t barsize; /* size of bar. no point in extra multiplications */ |
214 |
|
215 |
/* memory management quantities */ |
216 |
int len; /* number of bars filled (length of pool filled) */ |
217 |
int wid; /* num elements in a bar */ |
218 |
int expand; /* number of bars to expand by usually */ |
219 |
int growpool; /* expansion increment for pool array */ |
220 |
int curbar; /* pool entry from which fresh elements may be had */ |
221 |
int curelt; /* number of the next element in the curbar to hand out */ |
222 |
int onlist; /* length of recycle list, in elements */ |
223 |
#if !mem_LIGHTENING |
224 |
int total; /* total number of elements in this store */ |
225 |
int highwater; /* fresh elements turned loose from store */ |
226 |
int inuse; /* current elts user has outstanding */ |
227 |
#endif |
228 |
}; |
229 |
/* notes on header: |
230 |
* list is, as currently coded, null terminated by accident. |
231 |
* The intent of the author is that the counter onlist is the |
232 |
* authoritative list length. |
233 |
*/ |
234 |
|
235 |
#define AMEM_MINBARSIZE 5 |
236 |
#define AMEM_MINPOOLSIZE 2 |
237 |
#ifdef __alpha |
238 |
#define AMEM_MINPOOLGROW 512 |
239 |
/* gotta love those fat pointers. grow by 4k min. */ |
240 |
#else |
241 |
#define AMEM_MINPOOLGROW 1024 |
242 |
#endif |
243 |
|
244 |
/* |
245 |
Returns 2 if really bad, 1 if something fishy, 0 otherwise. |
246 |
*/ |
247 |
static int check_mem_store(const mem_store_t ms) |
248 |
{ |
249 |
#if mem_LIGHTENING |
250 |
return 0; |
251 |
#else |
252 |
int i; |
253 |
|
254 |
if (ISNULL(ms)) { |
255 |
FPRINTF(stderr,"check_mem_store (mem.c): NULL mem_store_t!\n"); |
256 |
return 2; |
257 |
} |
258 |
if (ms->integrity != OK) { |
259 |
(ms->integrity == DESTROYED) ? |
260 |
FPRINTF(stderr, |
261 |
"check_mem_store (mem.c): mem_store_t recently destroyed!\n") |
262 |
: FPRINTF(stderr, |
263 |
"check_mem_store (mem.c): mem_store_t corrupted!\n"); |
264 |
return 2; |
265 |
} |
266 |
if (ms->onlist && ISNULL(ms->list)) { |
267 |
FPRINTF(stderr, "ERROR: check_mem_store (mem.c): NULL recycle list!\n"); |
268 |
return 1; |
269 |
} |
270 |
/* more in than out? */ |
271 |
if (ms->retned > ms->active) { |
272 |
FPRINTF(stderr, "ERROR: check_mem_store (mem.c): Imbalanced memory.\n"); |
273 |
return 1; |
274 |
} |
275 |
if (ms->onlist + ms->inuse != ms->highwater) { |
276 |
FPRINTF(stderr, "ERROR: check_mem_store (mem.c): Imbalanced elements.\n"); |
277 |
return 1; |
278 |
} |
279 |
/* is pool allocated to ms->len? */ |
280 |
for (i=0; i < ms->len; i++) { |
281 |
if (ISNULL(ms->pool[i])) { |
282 |
FPRINTF(stderr, "ERROR: check_mem_store (mem.c): Hole found in pool!\n"); |
283 |
FPRINTF(stderr, " Bar %d is NULL.\n",i); |
284 |
return 2; |
285 |
} |
286 |
} |
287 |
/* do not check for integrity or count of recycle list elements. */ |
288 |
return 0; |
289 |
#endif |
290 |
} |
291 |
|
292 |
/* |
293 |
This should not be called unless all current store is in use. |
294 |
Returns 0 if ok, 1 for all other insanities. |
295 |
If only partial expansion is possible, we will do it and |
296 |
return 0. If change in ms->len is < the expected incremented value |
297 |
on return, the user knows he should do some garbage removal. |
298 |
incr is provided for times when we know how much we want |
299 |
to expand by. |
300 |
*/ |
301 |
static int expand_store(mem_store_t ms, int incr) |
302 |
{ |
303 |
static int oldsize, newsize,punt,i; |
304 |
char **newpool = NULL; |
305 |
if (check_mem_store(ms) >1) { |
306 |
FPRINTF(stderr,"ERROR: (mem.c) expand_store received bad\n"); |
307 |
FPRINTF(stderr," mem_store_t. Expansion failed.\n"); |
308 |
return 1; |
309 |
} |
310 |
|
311 |
#if !mem_LIGHTENING |
312 |
/* do not expand elements or pool if all is not in use */ |
313 |
if (ms->inuse < ms->total) { |
314 |
FPRINTF(stderr,"ERROR: (mem.c) expand_store called prematurely.\n"); |
315 |
FPRINTF(stderr," Expansion will be reported as failed.\n"); |
316 |
return 1; |
317 |
} |
318 |
#endif |
319 |
|
320 |
/* make sure bar expansion is at least the minimum */ |
321 |
if (incr < ms->expand) incr = ms->expand; |
322 |
oldsize = ms->len; |
323 |
newsize = oldsize+incr; |
324 |
|
325 |
/* expand pool capacity only if all of pool in use */ |
326 |
if (newsize > ms->maxlen) { |
327 |
i = ms->maxlen + MAX(ms->growpool,incr); |
328 |
newpool = (char **)AMEM_realloc(ms->pool, i*sizeof(char *)); |
329 |
if (ISNULL(newpool)) { |
330 |
FPRINTF(stderr,"ERROR: (mem.c) expand_store can't realloc pool.\n"); |
331 |
return 1; |
332 |
} |
333 |
/* NULL the new pool */ |
334 |
for (punt = ms->maxlen; punt < i; punt++) { |
335 |
newpool[punt] = NULL; |
336 |
} |
337 |
ms->maxlen = i; |
338 |
ms->pool = newpool; |
339 |
} |
340 |
/* end of pool expansion */ |
341 |
|
342 |
/* expand elements/bars */ |
343 |
ms->len = newsize; /* set expanded number of bars filled */ |
344 |
punt = -1; |
345 |
for (i = oldsize; i < newsize; i++) { |
346 |
#if mem_DEBUG |
347 |
ms->pool[i] = (char *)AMEM_calloc(ms->barsize,1); |
348 |
#else |
349 |
ms->pool[i] = (char *)AMEM_malloc(ms->barsize); |
350 |
#endif |
351 |
if (ISNULL(ms->pool[i])) { |
352 |
punt = i; |
353 |
/* we will return partially expanded if possible */ |
354 |
break; |
355 |
} |
356 |
} |
357 |
if (punt >= 0) { |
358 |
/* incomplete expansion */ |
359 |
if (punt == oldsize) { |
360 |
/* unable to add elements at all. fail */ |
361 |
FPRINTF(stderr,"ERROR: (mem) expand_store: Insufficient memory.\n"); |
362 |
ms->len = oldsize; |
363 |
return 1; |
364 |
} else { |
365 |
/* contract pool to the actual expansion size */ |
366 |
FPRINTF(stderr,"WARNING: (mem) expand_store: Insufficient memory.\n"); |
367 |
FPRINTF(stderr," Doing partial expansion.\n"); |
368 |
ms->len = punt; |
369 |
} |
370 |
} |
371 |
#if !mem_LIGHTENING |
372 |
ms->total = ms->len * ms->wid; |
373 |
#endif |
374 |
return 0; |
375 |
} |
376 |
|
377 |
#if !mem_LIGHTENING |
378 |
#if mem_DEBUG |
379 |
/* |
380 |
Returns 1 if pointer is to an elt of the store, 0 otherwise. |
381 |
The case of pointer into store reserved space, but not an elt is checked. |
382 |
*/ |
383 |
static int from_store( mem_store_t ms, void *elt) |
384 |
{ |
385 |
char *data; |
386 |
char **pool; |
387 |
int i; |
388 |
int lim; |
389 |
|
390 |
if (ISNULL(ms) || ISNULL(elt)) return 0; |
391 |
lim = ms->len; |
392 |
pool = ms->pool; |
393 |
data = (char *)elt; |
394 |
for (i=0; i<lim; i++) { |
395 |
/* did the char come from the current bar of chars? */ |
396 |
if (*pool <= data && data < *pool + ms->barsize) { |
397 |
/* if so, is it legal? */ |
398 |
if ( !((data - (*pool)) % ms->eltsize) ) { |
399 |
return 1; |
400 |
} else { |
401 |
FPRINTF(stderr,"ERROR: (mem.c) from_store: Misaligned element\n"); |
402 |
FPRINTF(stderr," pointer detected.\n"); |
403 |
return 0; |
404 |
} |
405 |
} |
406 |
pool++; |
407 |
} |
408 |
return 0; |
409 |
} |
410 |
#endif |
411 |
#endif |
412 |
|
413 |
void mem_get_stats(struct mem_statistics *mss, mem_store_t m) |
414 |
{ |
415 |
if (ISNULL(mss)) { |
416 |
FPRINTF(stderr,"ERROR: (mem_get_stats) Called with NULL struct\n"); |
417 |
FPRINTF(stderr," mem_statistics.\n"); |
418 |
return; |
419 |
} |
420 |
if (check_mem_store(m)>1 ) { |
421 |
ascbzero((void *)mss,(size_t)sizeof(struct mem_statistics)); |
422 |
FPRINTF(stderr,"ERROR: (mem_get_stats) Bad mem_store_t given.\n"); |
423 |
FPRINTF(stderr," Returning 0s.\n"); |
424 |
return; |
425 |
} |
426 |
#if !mem_LIGHTENING |
427 |
mss->m_eff = (double)(m->inuse * m->eltsize_req)/(double)mem_sizeof_store(m); |
428 |
mss->m_recycle = |
429 |
( (m->highwater > 0) ? (double)m->active/(double)m->highwater : 0.0 ); |
430 |
mss->elt_total = m->total; |
431 |
mss->elt_taken = m->highwater; |
432 |
mss->elt_inuse = m->inuse; |
433 |
#else |
434 |
mss->m_eff = 0.0; |
435 |
mss->m_recycle = 0.0; |
436 |
mss->elt_total = m->len*m->wid; |
437 |
mss->elt_taken = m->curelt+m->curbar*m->wid; |
438 |
mss->elt_inuse = 0; |
439 |
#endif |
440 |
mss->elt_onlist = m->onlist; |
441 |
mss->elt_size = (int)m->eltsize; |
442 |
mss->str_len = m->len; |
443 |
mss->str_wid = m->wid; |
444 |
} |
445 |
|
446 |
mem_store_t mem_create_store(int length, int width, |
447 |
size_t eltsize, int deltalen, int deltapool) |
448 |
{ |
449 |
int i, punt; |
450 |
mem_store_t newms=NULL; |
451 |
size_t uelt; |
452 |
|
453 |
if (length < 1 || width < 1 || deltalen < 1 ) { |
454 |
FPRINTF(stderr,"ERROR: (mem_create_store) : Bad input detected.\n"); |
455 |
return NULL; |
456 |
} |
457 |
|
458 |
/* check minsizes */ |
459 |
if (length < AMEM_MINPOOLSIZE) length = AMEM_MINPOOLSIZE; |
460 |
if (width < AMEM_MINBARSIZE) width = AMEM_MINBARSIZE; |
461 |
/* maybe the user gave us length = max he knows he needs, so we |
462 |
will not enforce a minimum maxlen on length at creation */ |
463 |
|
464 |
uelt = eltsize; |
465 |
/* check for elt padding needed */ |
466 |
if (eltsize % sizeof(void *)) { |
467 |
size_t ptrperelt; |
468 |
ptrperelt = eltsize/sizeof(void *) + 1; |
469 |
#if mem_DEBUG |
470 |
FPRINTF(stderr,"(mem_create_store) Elts of size %d padded to %d\n", |
471 |
eltsize,(eltsize=ptrperelt*sizeof(void *))); |
472 |
#else |
473 |
eltsize = ptrperelt*sizeof(void *); |
474 |
#endif |
475 |
} |
476 |
/* eltsize is now pointer alignable */ |
477 |
/* it could still be user data misalignable, of course, if pointer |
478 |
is not the most restrictive data type for the machine */ |
479 |
|
480 |
|
481 |
newms = (mem_store_t)AMEM_calloc(1,sizeof(struct mem_store_header)); |
482 |
if (ISNULL(newms)) { |
483 |
FPRINTF(stderr,"ERROR: (mem_create_store) : Insufficient memory.\n"); |
484 |
return NULL; |
485 |
} |
486 |
/* the following are all initially 0/NULL by calloc, and should be: |
487 |
newms->list |
488 |
newms->active |
489 |
newms->retned |
490 |
newms->curbar |
491 |
newms->curelt |
492 |
newms->highwater |
493 |
newms->onlist |
494 |
newms->inuse |
495 |
newms->pool |
496 |
*/ |
497 |
newms->integrity = OK; |
498 |
newms->len = length; |
499 |
newms->maxlen = length; |
500 |
newms->wid = width; |
501 |
newms->expand = deltalen; |
502 |
newms->eltsize = eltsize; |
503 |
newms->barsize = eltsize * width; |
504 |
#if !mem_LIGHTENING |
505 |
newms->total = length * width; |
506 |
#endif |
507 |
newms->growpool = MAX(AMEM_MINPOOLGROW,deltapool); |
508 |
newms->eltsize_req = uelt; |
509 |
|
510 |
/* get pool */ |
511 |
newms->pool = (char **)AMEM_calloc((size_t)length,sizeof(char *)); |
512 |
if (ISNULL(newms->pool)) { |
513 |
FPRINTF(stderr,"ERROR: (mem_create_store) : Insufficient memory.\n"); |
514 |
newms->integrity = DESTROYED; |
515 |
AMEM_free(newms); |
516 |
return NULL; |
517 |
} |
518 |
|
519 |
/* fill it */ |
520 |
punt = -1; |
521 |
for (i=0; i < length; i++) { |
522 |
newms->pool[i] = (char *)AMEM_malloc(newms->barsize); |
523 |
if (ISNULL(newms->pool[i])) { |
524 |
punt = i; /* we will stop cleanup deallocation at punt-1 */ |
525 |
break; |
526 |
} |
527 |
} |
528 |
|
529 |
/* drain it if can't fill it */ |
530 |
if (punt != -1) { |
531 |
FPRINTF(stderr,"ERROR: (mem_create_store) : Insufficient memory.\n"); |
532 |
for (i = 0; i < punt; i++) { |
533 |
AMEM_free(newms->pool[i]); |
534 |
} |
535 |
newms->integrity = DESTROYED; |
536 |
AMEM_free(newms->pool); |
537 |
AMEM_free(newms); |
538 |
return NULL; |
539 |
} |
540 |
return newms; |
541 |
} |
542 |
|
543 |
void *mem_get_element(mem_store_t ms) |
544 |
{ |
545 |
/* no automatic variables please */ |
546 |
register struct mem_element *elt; |
547 |
/* in a test on the alpha, though, making elt static global slowed it */ |
548 |
|
549 |
if (ISNULL(ms)) { |
550 |
FPRINTF(stderr,"ERROR: (mem_get_element) Called with NULL store.\n"); |
551 |
return NULL; |
552 |
} |
553 |
/* recycling */ |
554 |
if (ms->onlist) { |
555 |
elt = ms->list; /* get last element put into list */ |
556 |
ms->list = ms->list->nextelt; /* pop list */ |
557 |
/* preserves original null if list is empty */ |
558 |
ms->onlist--; |
559 |
#if !mem_LIGHTENING |
560 |
ms->inuse++; |
561 |
ms->active++; |
562 |
#endif |
563 |
return (void *)elt; |
564 |
} |
565 |
|
566 |
/* fresh element */ |
567 |
if (ms->curelt == ms->wid) { |
568 |
/* bump up pool if bar all allocated */ |
569 |
ms->curelt = 0; |
570 |
ms->curbar++; |
571 |
} |
572 |
if (ms->curbar == ms->len) { |
573 |
/* attempt to expand pool if all allocated */ |
574 |
if ( expand_store(ms,1) ) { |
575 |
FPRINTF(stderr,"ERROR: (mem_get_element) Insufficient memory.\n"); |
576 |
return NULL; |
577 |
} |
578 |
} |
579 |
/* if we got here, pool is big enough to grab an element from */ |
580 |
|
581 |
/* get the pointer to an element's worth of char from the pool */ |
582 |
elt = |
583 |
(struct mem_element *) &(ms->pool[ms->curbar][ms->curelt * ms->eltsize]); |
584 |
ms->curelt++; |
585 |
#if !mem_LIGHTENING |
586 |
ms->inuse++; |
587 |
ms->highwater++; |
588 |
ms->active++; |
589 |
#endif |
590 |
return (void *)elt; |
591 |
} |
592 |
|
593 |
void mem_get_element_list(mem_store_t ms, int nelts, void **ary) |
594 |
{ |
595 |
FPRINTF(stderr,"ERROR: mem_get_element_list NOT implemented\n"); |
596 |
if (ISNULL(ms) || ISNULL(ary)) { |
597 |
FPRINTF(stderr,"ERROR: mem_get_element_list Called with NULL\n"); |
598 |
FPRINTF(stderr," array or mem_store_t"); |
599 |
return; |
600 |
} |
601 |
if (nelts <1) { |
602 |
FPRINTF(stderr,"WARNING: mem_get_element_list Called with request\n"); |
603 |
FPRINTF(stderr," for 0 elements."); |
604 |
return; |
605 |
} |
606 |
ary[0]=NULL; |
607 |
} |
608 |
|
609 |
void mem_free_element(mem_store_t ms, void *ptr) |
610 |
{ |
611 |
register struct mem_element *elt; |
612 |
|
613 |
if (ISNULL(ptr)) return; |
614 |
elt = (struct mem_element *)ptr; |
615 |
|
616 |
#if !mem_LIGHTENING |
617 |
#if mem_DEBUG |
618 |
if (check_mem_store(ms)) { |
619 |
FPRINTF(stderr,"ERROR: (mem_free_element) Fishy mem_store_t.\n"); |
620 |
FPRINTF(stderr," Element not recycled.\n"); |
621 |
return; |
622 |
/* at this point we have no way to get back at the abandoned element */ |
623 |
} |
624 |
/* check for belongs to this mem_store_t */ |
625 |
if (!from_store(ms,ptr)) { |
626 |
FPRINTF(stderr,"ERROR: (mem_free_element) Spurious element detected.\n"); |
627 |
FPRINTF(stderr," Element ignored.\n"); |
628 |
return; |
629 |
} |
630 |
#endif |
631 |
#endif |
632 |
|
633 |
/* recycle him */ |
634 |
elt->nextelt = ms->list; /* push onto list */ |
635 |
/* first one in will pick up the null list starts as */ |
636 |
ms->list = elt; |
637 |
/* ptr now on lifo stack in elt linked list form */ |
638 |
ms->onlist++; |
639 |
|
640 |
#if !mem_LIGHTENING |
641 |
ms->retned++; |
642 |
ms->inuse--; |
643 |
if (ms->inuse < 0) { |
644 |
FPRINTF(stderr,"ERROR: (mem_free_element) More elements freed than\n"); |
645 |
FPRINTF(stderr," have been handed out. (%d)\n", |
646 |
abs(ms->inuse)); |
647 |
} |
648 |
#endif |
649 |
return; |
650 |
} |
651 |
|
652 |
void mem_clear_store(mem_store_t ms) { |
653 |
if ( check_mem_store(ms) > 1 ) { |
654 |
FPRINTF(stderr,"ERROR: (mem_clear_store) Bad mem_store_t given.\n"); |
655 |
FPRINTF(stderr," Not cleared.\n"); |
656 |
return; |
657 |
} |
658 |
#if mem_DEBUG |
659 |
if (ms->inuse || ms->highwater - ms->onlist ) { |
660 |
FPRINTF(stderr,"WARNING: (mem_clear_store) In use elements in given\n"); |
661 |
FPRINTF(stderr," mem_store_t are cleared.\n"); |
662 |
FPRINTF(stderr," Don't refer to them again.\n"); |
663 |
} |
664 |
#endif |
665 |
ms->retned += ms->inuse; |
666 |
if (ms->active - ms->retned || |
667 |
ms->onlist + ms->inuse - ms->highwater || |
668 |
ms->curelt + ms->curbar*ms->wid - ms->highwater) { |
669 |
FPRINTF(stderr,"Warning: mem_clear_store: Element imbalance detected.\n"); |
670 |
} |
671 |
ms->inuse = 0; |
672 |
ms->curbar = 0; |
673 |
ms->curelt = 0; |
674 |
ms->highwater = 0; |
675 |
ms->onlist = 0; |
676 |
ms->list = NULL; |
677 |
} |
678 |
|
679 |
void mem_destroy_store(mem_store_t ms) |
680 |
{ |
681 |
int i; |
682 |
#if mem_DEBUG |
683 |
if ( (i=check_mem_store(ms))==2 ) { |
684 |
FPRINTF(stderr,"ERROR: (mem_destroy_store) Bad mem_store_t given.\n"); |
685 |
FPRINTF(stderr," Not destroyed.\n"); |
686 |
return; |
687 |
} |
688 |
if ( i ) { |
689 |
FPRINTF(stderr, |
690 |
"WARNING: (mem_destroy_store) Suspicious mem_store_t given.\n"); |
691 |
FPRINTF(stderr," Destroyed anyway.\n"); |
692 |
return; |
693 |
} |
694 |
if (ms->inuse || ms->highwater - ms->onlist ) { |
695 |
FPRINTF(stderr,"WARNING: (mem_destroy_store) In use elements in given\n"); |
696 |
FPRINTF(stderr," mem_store_t are cleared.\n"); |
697 |
FPRINTF(stderr," Don't refer to them again.\n"); |
698 |
} |
699 |
#else |
700 |
if (ISNULL(ms) || ms->integrity != OK) { |
701 |
FPRINTF(stderr,"ERROR: (mem_destroy_store) Bad mem_store_t given.\n"); |
702 |
FPRINTF(stderr," Not destroyed.\n"); |
703 |
return; |
704 |
} |
705 |
#endif |
706 |
for (i=0; i < ms->len; i++) { |
707 |
AMEM_free(ms->pool[i]); |
708 |
} |
709 |
AMEM_free(ms->pool); |
710 |
ms->integrity = DESTROYED; |
711 |
AMEM_free(ms); |
712 |
return; |
713 |
} |
714 |
|
715 |
void mem_print_store(FILE *fp, mem_store_t ms, unsigned detail) |
716 |
{ |
717 |
if (ISNULL(fp) || ISNULL(ms)) { |
718 |
FPRINTF(stderr,"ERROR: (mem_print_store) Called with NULL\n"); |
719 |
FPRINTF(stderr," FILE or mem_store_t\n"); |
720 |
return; |
721 |
} |
722 |
if (check_mem_store(ms)>1) { |
723 |
FPRINTF(stderr,"ERROR: (mem_print_store) Called with bad mem_store_t\n"); |
724 |
return; |
725 |
} |
726 |
FPRINTF(fp,"mem_store_t statistics:\n"); |
727 |
if (detail) { |
728 |
FPRINTF(fp,"INTERNAL (integrity OK if = %d):\n",OK); |
729 |
FPRINTF(fp,"%-30s %-20ld\n","integrity", (long)ms->integrity); |
730 |
#if !mem_LIGHTENING |
731 |
FPRINTF(fp,"%-30s %-20ld\n","active",ms->active); |
732 |
FPRINTF(fp,"%-30s %-20ld\n","returned",ms->retned); |
733 |
#endif |
734 |
FPRINTF(fp,"%-30s %-20lu\n","eltsize",(unsigned long)ms->eltsize); |
735 |
FPRINTF(fp,"%-30s %-20lu\n","barsize",(unsigned long)ms->barsize); |
736 |
FPRINTF(fp,"%-30s %-20d\n","pool length",ms->len); |
737 |
FPRINTF(fp,"%-30s %-20d\n","pool maxlength",ms->maxlen); |
738 |
FPRINTF(fp,"%-30s %-20d\n","bar width",ms->wid); |
739 |
FPRINTF(fp,"%-30s %-20d\n","pool extension",ms->growpool); |
740 |
FPRINTF(fp,"%-30s %-20d\n","pool fill rate",ms->expand); |
741 |
FPRINTF(fp,"%-30s %-20d\n","current bar",ms->curbar); |
742 |
FPRINTF(fp,"%-30s %-20d\n","current elt",ms->curelt); |
743 |
#if !mem_LIGHTENING |
744 |
FPRINTF(fp,"%-30s %-20d\n","total elts",ms->total); |
745 |
FPRINTF(fp,"%-30s %-20d\n","highwater",ms->highwater); |
746 |
#endif |
747 |
FPRINTF(fp,"%-30s %-20d\n","elt on list",ms->onlist); |
748 |
#if !mem_LIGHTENING |
749 |
FPRINTF(fp,"%-30s %-20d\n","elt in use",ms->inuse); |
750 |
#endif |
751 |
} |
752 |
if (!detail || detail > 1) { |
753 |
FPRINTF(fp,"SUMMARY:\n"); |
754 |
FPRINTF(fp,"%-30s %-20d\n","Pointers in pool",ms->maxlen); |
755 |
FPRINTF(fp,"%-30s %-20d\n","Pointers allocated",ms->len); |
756 |
#if !mem_LIGHTENING |
757 |
FPRINTF(fp,"%-30s %-20d\n","Elements in pool",ms->total); |
758 |
FPRINTF(fp,"%-30s %-20d\n","Elements in use",ms->inuse); |
759 |
#endif |
760 |
FPRINTF(fp,"%-30s %-20d\n","Elements waiting recycle",ms->onlist); |
761 |
#if !mem_LIGHTENING |
762 |
FPRINTF(fp,"%-30s %-20d\n","Elements unused",ms->total - ms->highwater); |
763 |
#endif |
764 |
FPRINTF(fp,"%-30s %-20d\n","Working deltapool",ms->growpool); |
765 |
FPRINTF(fp,"%-30s %-20d\n","Working deltalen",ms->expand); |
766 |
FPRINTF(fp,"%-30s %-20g\n","Element efficiency", |
767 |
ms->eltsize_req/(double)ms->eltsize); |
768 |
#if !mem_LIGHTENING |
769 |
FPRINTF(fp,"%-30s %-20g\n","Memory efficiency (w/recycle)", |
770 |
ms->highwater*ms->eltsize_req/(double)mem_sizeof_store(ms)); |
771 |
FPRINTF(fp,"%-30s %-20g\n","Memory efficiency (instant)", |
772 |
ms->inuse*ms->eltsize_req/(double)mem_sizeof_store(ms)); |
773 |
FPRINTF(fp,"%-30s %-20g\n","Recycle rate", |
774 |
((ms->highwater > 0) ? ms->active/(double)ms->highwater : 0) ); |
775 |
#endif |
776 |
} |
777 |
FPRINTF(fp,"%-30s %-20lu\n","Total bytes in store", |
778 |
(unsigned long)mem_sizeof_store(ms)); |
779 |
|
780 |
return; |
781 |
} |
782 |
|
783 |
size_t mem_sizeof_store(mem_store_t ms) |
784 |
{ |
785 |
register size_t siz; |
786 |
if (check_mem_store(ms)>1) return (size_t)0; |
787 |
siz = sizeof(struct mem_store_header); /* header */ |
788 |
siz += ms->barsize * ms->len; /* elt data */ |
789 |
return (siz += ms->maxlen*sizeof(char*)); /* pool vector */ |
790 |
} |