/* * $Id: mem.c,v 1.1.1.1 2004/08/25 19:21:30 jan Exp $ * * Copyright (c) 2002 Jan Algermissen * See the file "COPYING" for copying permission. * */ #include "tmmem.h" #include "tmtrace.h" #include "tmassert.h" #include "tmlist.h" #include "tm.h" #include "tmutil.h" /* for tm_strdup */ #include #include #include #define TAB_SIZE 1000 /* size of hash table */ #define ONE ((void*)1) typedef struct LIST *LIST; struct LIST { LIST next; void *content; }; static LIST list_push(LIST self, void *content); static void list_delete(LIST *pself); static LIST list_remove(LIST list, void *v); static LIST list_copy(LIST list); #ifdef TM_MEMCHECKING typedef struct TABLE *TABLE; struct TABLE { int size; int length; unsigned timestamp; struct binding { struct binding *link; void *key; void *value; } **buckets; }; #endif /* static int cmpatom(const void *x,const void *y) { return x != y; } static unsigned hashatom(const void *key) { return (unsigned long)key >> 2; } */ #ifdef TM_MEMCHECKING static TABLE table_new(int hint); static void table_delete(TABLE *pself); /* static void *table_get(TABLE table, const void *key); */ static void *table_put(TABLE table, void *key, void *value); static void *table_remove(TABLE table, const void *key); static void table_apply(TABLE table, void apply(void *key,void **value, void *cl), void *cl); #endif struct TMPool { TM tm; char *name; struct TMPool *parent; LIST children; #ifdef TM_MEMCHECKING TABLE items; int nallocs; int ncallocs; int nresizes; int nfrees; #endif }; #ifdef TM_MEMCHECKING static void free_keys(void *key,void **value, void *cl) { TMTRACE(TM_POOL_TRACE, "[%s] *** MEMORY HAS NOT BEEN CLEANED UP ***: " "ptr %ld has not been cleaned up\n" _ ((TMPool)cl)->name _ (long)key); assert(0); free(key); } #endif void *tm_alloc(TMPool pool,long nbytes, const char *file, int line) { #ifdef TM_MEMCHECKING void *chk; #endif void *ptr; #ifdef TM_MEMCHECKING TMTRACE(TM_POOL_TRACE,"[%s] allocating %ld bytes in %s line %d\n" _ pool->name _ nbytes _ file _ line); #endif assert(nbytes > 0); ptr = malloc(nbytes); if(ptr == NULL) TMTRACE(TM_ANY_TRACE,"tm_alloc: out of memory in %s line %d" _ file _ line); if (ptr == NULL) { /* FIXME: call out_of_mem_handler */ assert(ptr); } #ifdef TM_MEMCHECKING chk = table_put(pool->items,ptr,ONE); assert(chk == NULL); TMTRACE(TM_POOL_TRACE,"[%s] allocated %ld bytes (ptr = %ld) in %s line %d\n" _ pool->name _ nbytes _ (long)ptr _ file _ line); pool->nallocs++; #endif return ptr; } void *tm_calloc(TMPool pool,long count,long nbytes, const char *file, int line) { #ifdef TM_MEMCHECKING void *chk; #endif void *ptr; assert(nbytes > 0); assert(count > 0); assert(0); /* do I use this at all? */ ptr = calloc(count,nbytes); if(ptr == NULL) TMTRACE(TM_ANY_TRACE,"gs_calloc: out of memory in %s line %d" _ file _ line); #ifdef TM_MEMCHECKING TMTRACE(TM_POOL_TRACE,"[%s] callocated %ld bytes x %d (ptr = %ld) in %s line %d\n" _ pool->name _ nbytes _ count _ (long)ptr _ file _ line); chk = table_put(pool->items,ptr,ONE); assert(chk == NULL); pool->ncallocs++; #endif return ptr; } void *tm_resize(TMPool pool,void *ptr,long nbytes, const char *file, int line) { #ifdef TM_MEMCHECKING void *chk; #endif assert(nbytes > 0); assert(ptr); #ifdef TM_MEMCHECKING TMTRACE(TM_POOL_TRACE,"[%s] resizing (ptr = %ld) in %s line %d\n" _ pool->name _ (long)ptr _ file _ line); chk = table_remove(pool->items,ptr); assert( chk == ONE); TMTRACE(TM_POOL_TRACE,"[%s] removed (ptr = %ld)\n" _ pool->name _ (long)ptr ); #endif ptr = realloc(ptr,nbytes); if(ptr == NULL) TMTRACE(TM_ANY_TRACE,"gs_resize: out of memory in %s line %d" _ file _ line); #ifdef TM_MEMCHECKING chk = table_put(pool->items,ptr,ONE); assert(chk == NULL); TMTRACE(TM_POOL_TRACE,"[%s] resized (new ptr = %ld) in %s line %d\n" _ pool->name _ (long)ptr _ file _ line); pool->nresizes++; #endif return ptr; } void tm_free(TMPool pool,void *ptr, const char *var,const char *file, int line) { #ifdef TM_MEMCHECKING void *chk; pool->nfrees++; /* return; */ TMTRACE(TM_POOL_TRACE,"[%s] deallocating var %s (ptr = %ld) in %s line %d\n" _ pool->name _ var _ (long)ptr _ file _ line ); #endif assert(ptr); #ifdef TM_MEMCHECKING chk = table_remove(pool->items,ptr); assert( chk == ONE); #endif if(ptr) free(ptr); else assert(!"gs_free called with NULL pointer !"); } TMPool tm_pool_new(const char *name,TMPool parent,...) { va_list args; TMPool self; self = (TMPool)malloc(sizeof(struct TMPool)); if(self == NULL) { assert(0); exit(0); } self->parent = parent; self->children = NULL; if(parent == NULL) { va_start(args,parent); self->tm = va_arg(args,TM); va_end(args); } else { self->tm = parent->tm; parent->children = list_push(parent->children,self); } self->name = malloc(strlen(name)+1); strcpy(self->name,name); #ifdef TM_MEMCHECKING self->items = table_new(TAB_SIZE); self->nallocs = 0; self->ncallocs = 0; self->nresizes = 0; self->nfrees = 0; #endif TMTRACE(TM_POOL_TRACE,"Pool %s created; parent: %s\n" _ self->name _ self->parent ? self->parent->name : "NONE"); return (self); } TMPool tm_pool_new2(const char *name,TMPool parent,int tabsize) { TMPool self; self = (TMPool)malloc(sizeof(struct TMPool)); if(self == NULL) { assert(0); exit(0); } self->parent = parent; self->children = NULL; self->tm = parent->tm; parent->children = list_push(parent->children,self); self->name = malloc(strlen(name)+1); strcpy(self->name,name); #ifdef TM_MEMCHECKING self->items = table_new(tabsize); self->nallocs = 0; self->ncallocs = 0; self->nresizes = 0; self->nfrees = 0; #endif TMTRACE(TM_POOL_TRACE,"Pool %s created(TABSIZE:%d); parent: %s\n" _ self->name _ tabsize _ self->parent ? self->parent->name : "NONE"); return (self); } void tm_pool_delete(TMPool *pself) { TMPool self; TMPool parent; LIST save_children,lp; assert(pself && *pself); self = *pself; parent = self->parent; TMTRACE(TM_POOL_TRACE,"deleting Pool %s; parent: %s\n" _ self->name _ parent ? parent->name : "NONE"); #ifdef TM_MEMCHECKING TMTRACE(TM_POOL_TRACE,"Pool %s - allocs: %d\n" _ self->name _ self->nallocs); TMTRACE(TM_POOL_TRACE,"Pool %s - callocs: %d\n" _ self->name _ self->ncallocs); TMTRACE(TM_POOL_TRACE,"Pool %s - resizes: %d\n" _ self->name _ self->nresizes); TMTRACE(TM_POOL_TRACE,"Pool %s - frees: %d\n" _ self->name _ self->nfrees); table_apply(self->items,free_keys,self); TMTRACE(TM_POOL_TRACE,"Pool %s ; deleted all items\n" _ self->name); table_delete(&(self->items)); #endif save_children = list_copy(self->children); for(lp = save_children;lp;lp=lp->next) { tm_pool_delete( (TMPool*)&(lp->content) ); } assert(self->children == NULL); TMTRACE(TM_POOL_TRACE,"Pool %s ; deleted children\n" _ self->name); list_delete(&(save_children)); if(parent) { parent->children = list_remove(parent->children,self); TMTRACE(TM_POOL_TRACE,"deleted Pool %s from parent: %s\n" _ self->name _ parent->name); free(self->name); free(self); } else { free(self->name); free(self); } *pself = NULL; } /* TM tm_pool_get_tm(TMPool self) { return (self->tm); } */ LIST list_push(LIST self, void *content) { LIST newItem; newItem = (LIST)malloc(sizeof(struct LIST)); newItem->content = content; newItem->next = self; return newItem; } void list_delete(LIST *pself) { LIST next; assert(pself); for( ; *pself; *pself = next) { next = (*pself)->next; free(*pself); } } LIST list_remove(LIST list, void *v) { LIST prev,lp; if(list == NULL) return(NULL); prev = NULL; for(lp=list;lp;lp=lp->next) { LIST tmp = NULL; if(lp->content != v) { prev = lp; continue; } if(!prev) { tmp = list; list = list->next; free(tmp); } else { assert(prev->next == lp); prev->next = lp->next; free(lp); } break; } return list; } #if 0 static int list_contains(LIST list, const void *v); int list_contains(LIST list, const void *v) { if(!list) return 0; for( ; list ; list = list->next) { if(list->content == v) return 1; } return 0; } #endif LIST list_copy(LIST list) { LIST n = NULL; if(!list) return NULL; for( ; list; list = list->next) n = list_push(n,list->content); return n; } #ifdef TM_MEMCHECKING TABLE table_new(int hint) { TABLE table; int i; static int primes[] = { 509,509,1021,2053,4093,8191,16381,32771, 65521, INT_MAX}; assert(hint >= 0); for(i = 1; primes[i] < hint; i++) ; table = (TABLE)malloc(sizeof(*table) + primes[i-1]*sizeof(table->buckets[0])); table->size = primes[i-1]; table->buckets = (struct binding **)(table + 1); for(i = 0; i < table->size; i++) table->buckets[i] = NULL; table->length = 0; table->timestamp = 0; return table; } void table_delete(TABLE *pself) { assert(pself && *pself); if((*pself)->length > 0) { int i; struct binding *p,*q; for(i=0;i<(*pself)->size;i++) { for(p = (*pself)->buckets[i]; p; p=q) { q=p->link; free(p); } } } free(*pself); *pself = NULL; } #if 0 void *table_get(TABLE table, const void *key) { int i; struct binding *p; assert(table); assert(key); /* i = hashatom(key)%table->size; */ i = ((unsigned long)key >> 2)%table->size; for(p = table->buckets[i]; p; p = p->link) if(key == p->key) break; return p ? p->value : NULL; } #endif void *table_put(TABLE table, void *key, void *value) { int i; struct binding *p; void *prev; assert(table); assert(key); TMTRACE(TM_X_TRACE,"storing key %ld\n" _ (long)key); /* i = hashatom(key)%table->size; */ i = ((unsigned long)key >> 2)%table->size; for(p = table->buckets[i]; p; p = p->link) if(key == p->key) { assert(0); /* cannot be inside */ break; } if(p == NULL) { p = (struct binding *)malloc(sizeof(struct binding)); assert(p); p->key = key; p->link = table->buckets[i]; table->buckets[i] = p; table->length++; prev = NULL; } else { prev = p->value; } p->value = value; table->timestamp++; return prev; } void *table_remove(TABLE table, const void *key) { int i; struct binding **pp; assert(table); assert(key); /* table->timestamp++; */ /* i = hashatom(key)%table->size; */ i = ((unsigned long)key >> 2)%table->size; for(pp = &table->buckets[i]; *pp; pp = &(*pp)->link) { if(key == (*pp)->key) { struct binding *p = *pp; void *value = p->value; *pp = p->link; free(p); p = NULL; table->length--; return value; } } return NULL; } void table_apply(TABLE table, void apply(void *key,void **value, void *cl), void *cl) { int i; unsigned stamp; struct binding *p; assert(table); assert(apply); stamp = 0; /* stamp = table->timestamp; */ for(i = 0; i < table->size; i++) { for(p = table->buckets[i]; p; p = p->link) { apply(p->key,&p->value, cl); /* assert(table->timestamp == stamp); */ } } } #endif /* if TM_MEMCHECKING */ #if 0 TMList tm_table_keys(TMTable table, TMPool pool,TMList *listp) { int i; struct binding *p; TMList lp; assert(table); assert(listp); lp = NULL; for(i = 0; i < table->size; i++) { for(p = table->buckets[i]; p; p = p->link) { lp = tm_list_push(pool,lp,(void*)p->key); } } if(listp) *listp = lp; return lp; } #endif