diff options
author | paulcantrell <paulcantrell> | 2007-12-10 21:59:20 +0000 |
---|---|---|
committer | paulcantrell <paulcantrell> | 2007-12-10 21:59:20 +0000 |
commit | 2ee4787d1df9784d40a7eda91e61691da3d56f74 (patch) | |
tree | 0947afb6c37ffeb4ae193401a187255cf27b0ed3 /tecmem.c | |
download | videoteco-fork-2ee4787d1df9784d40a7eda91e61691da3d56f74.tar.gz |
Initial revision
Diffstat (limited to 'tecmem.c')
-rw-r--r-- | tecmem.c | 456 |
1 files changed, 456 insertions, 0 deletions
diff --git a/tecmem.c b/tecmem.c new file mode 100644 index 0000000..739265b --- /dev/null +++ b/tecmem.c @@ -0,0 +1,456 @@ +char *tecmem_c_version = "tecmem.c: $Revision: 1.1 $"; + +/* + * $Date: 2007/12/10 21:59:20 $ + * $Source: /cvsroot/videoteco/videoteco/tecmem.c,v $ + * $Revision: 1.1 $ + * $Locker: $ + */ + +/* tecmem.c + * Subroutines to manage memory allocation and deallocation + * + * COPYRIGHT (c) 1985-2003 BY + * PAUL CANTRELL & J. M. NISHINAGA + * SUDBURY, MA 01776 + * ALL RIGHTS RESERVED + * + * This software is furnished in it's current state free of charge. + * The authors reserve all rights to the software. Further + * distribution of the software is not authorized. Modifications to + * the software may be made locally, but shall not be distributed + * without the consent of the authors. This software or any other + * copies thereof, may not be provided or otherwise made available + * to anyone without express permission of the authors. Title to and + * ownership of this software remains with the authors. + * + */ + +#include "teco.h" + +#if HAVE_SBRK +#ifndef HAVE_UNISTD_H + char *sbrk(); +#endif +#endif + + char *starting_break; + +#ifndef HAVE_UNISTD_H + char *malloc(); + void free(); + void exit(); +#endif + + extern struct buff_header *curbuf; + extern FILE *teco_debug_log; + +struct memblock { + unsigned char type; + int size; +}; + +struct memlist { + unsigned char type; + struct memlist *next_block; +}; + +char *malloc_leftover; +int malloc_leftover_size; +struct memlist *lookaside_lists[LOOKASIDE_COUNT]; +int lookaside_stat_allocated[LOOKASIDE_COUNT]; +int lookaside_stat_available[LOOKASIDE_COUNT]; +int malloc_stat_call_count,malloc_stat_inuse; + +int memstat_by_type[TYPE_C_MAXTYPE-TYPE_C_MINTYPE+1]; + +void tecmem_verify(unsigned char,char *,char *); + +/* TEC_ALLOC - Routine to allocate some memory + * + * Function: + * + * This routine is called to request memory + */ +char * +tec_alloc(type,size) +int type; +int size; +{ +int actual_size; +register int i,j; +register char *cp; +register struct memblock *mp; +register struct memlist *lp; +extern char outof_memory; + + PREAMBLE(); + +/* + * First we check that the caller is requesting a known memory block + * type. This is just a consitency check. + */ + if(type < TYPE_C_MINTYPE || type > TYPE_C_MAXTYPE){ + printf("\nTECO: UNKNOWN MEMORY BLOCK TYPE %d in TEC_ALLOC\n",type); +#ifdef UNIX + kill(getpid(),SIGQUIT); +#endif + exit(ENOMEM); + }/* End IF */ + + +#ifdef INSERT_RANDOM_MALLOC_ERRORS + { + int chance; + chance = rand() % 100; + if(chance == 0){ + return(NULL); + }/* End IF */ + } +#endif /* INSERT_RANDOM_MALLOC_ERRORS */ + +/* + * If the size required is larger than the largest lookaside block we support, + * we just call malloc with it. + */ + actual_size = size + sizeof(struct memblock); + if(actual_size > LARGEST_LOOKASIDE_BLOCK){ + mp = (struct memblock *)malloc((unsigned)actual_size); + + if(mp == NULL){ + outof_memory = YES; + return(NULL); + }/* End IF */ + + malloc_stat_call_count += 1; + malloc_stat_inuse += actual_size; + mp->type = type; + mp->size = actual_size; + cp = (char *)mp + sizeof(struct memblock); + return(cp); + }/* End IF */ + +/* + * Round up to the next larger lookaside block size + */ + if(actual_size & (MINIMUM_ALLOCATION_BLOCK - 1)){ + actual_size += MINIMUM_ALLOCATION_BLOCK; + actual_size &= ~(MINIMUM_ALLOCATION_BLOCK - 1); + }/* End IF */ + +/* + * Check whether we have a lookaside entry of that size. If not, we allocate + * some number of entries of that size from our large memory hunk. + */ + i = (actual_size / MINIMUM_ALLOCATION_BLOCK) - 1; + + if(lookaside_lists[i] == NULL){ + tec_gc_lists(); + }/* End IF */ + + if(lookaside_lists[i] == NULL){ + if(malloc_leftover != NULL){ + if(malloc_leftover_size < actual_size){ + i = (malloc_leftover_size / MINIMUM_ALLOCATION_BLOCK) - 1; + lp = (struct memlist *)malloc_leftover; + lp->next_block = lookaside_lists[i]; + lookaside_lists[i] = lp; + lookaside_stat_available[i] += 1; + i = (actual_size / MINIMUM_ALLOCATION_BLOCK) - 1; + malloc_leftover = NULL; + malloc_leftover_size= 0; + }/* End IF */ + else { + lp = (struct memlist *)malloc_leftover; + malloc_leftover += actual_size; + malloc_leftover_size -= actual_size; + if(malloc_leftover_size == 0) malloc_leftover = NULL; + lp->next_block = NULL; + lookaside_lists[i] = lp; + lookaside_stat_available[i] += 1; + }/* End Else */ + }/* End IF */ + }/* End IF */ + + if(lookaside_lists[i] == NULL){ + j = BIG_MALLOC_HUNK_SIZE / actual_size; + cp = malloc((unsigned)(BIG_MALLOC_HUNK_SIZE)); + + if(cp == NULL){ + printf("\nTECO: malloc failed!\n"); + outof_memory = YES; + return(NULL); + }/* End IF */ + +/* + * Place the one block on the lookaside list, and the rest as a malloc + * leftover. + */ + lp = (struct memlist *)cp; + lookaside_stat_available[i] += 1; + lp->next_block = NULL; + lookaside_lists[i] = lp; + malloc_leftover = cp + actual_size; + malloc_leftover_size = BIG_MALLOC_HUNK_SIZE - actual_size; + + }/* End IF */ + + lp = lookaside_lists[i]; + lookaside_lists[i] = lp->next_block; + lookaside_stat_allocated[i] += 1; + lookaside_stat_available[i] -= 1; + memstat_by_type[type-TYPE_C_MINTYPE] += 1; + + mp = (struct memblock *)lp; + mp->type = type; + mp->size = actual_size; + cp = (char *)mp + sizeof(struct memblock); + bzero(cp,size); + return(cp); + +}/* End Routine */ + +/* TEC_RELEASE - Envelope routine for free() + * + * Function: + * + * This routine is called to release memory which was previously allocated + * by calling the tec_alloc routine. + */ +void +tec_release(type,addr) +unsigned char type; +register char *addr; +{ +register struct memblock *mp; +register struct memlist *lp; +register int i; + + PREAMBLE(); + + mp = (struct memblock *)( addr - sizeof(struct memblock) ); + if(mp->type != type){ + printf("\nTEC_RELEASE: TYPE Mismatch: Supplied %d Stored %d addr 0x%x\n", + type,mp->type,(unsigned int)addr); +#ifdef UNIX + kill(getpid(),SIGQUIT); +#endif + exit(ENOMEM); + }/* End IF */ + + if(mp->size > LARGEST_LOOKASIDE_BLOCK){ + malloc_stat_inuse -= mp->size; + free(mp); + return; + }/* End IF */ + + mp->type += 1000; + i = mp->size / MINIMUM_ALLOCATION_BLOCK - 1; + lp = (struct memlist *)mp; + lp->next_block = lookaside_lists[i]; + lookaside_lists[i] = lp; + + lookaside_stat_available[i] += 1; + lookaside_stat_allocated[i] -= 1; + memstat_by_type[type-TYPE_C_MINTYPE] -= 1; + + return; + +}/* End Routine */ + + + +/* TECMEM_VERIFY - Verify that structure type hasn't been corrupted + * + * Function: + * + * This debug routine checks to see whether the memory block has been + * overwritten by checking the type code. + */ +void +tecmem_verify(type,addr,message) +unsigned char type; +register char *addr; +char *message; +{ +register struct memblock *mp; +#if 0 +register struct memlist *lp; +#endif +#if 0 +register int i; +#endif + + PREAMBLE(); + + mp = (struct memblock *)( addr - sizeof(struct memblock) ); + if(mp->type != type){ + printf( + "\nTYPE Mismatch: Supplied %d Stored %d addr %x '%s'\n", + type,mp->type,(unsigned int)addr,message); + exit(1); + }/* End IF */ + + return; + +}/* End Routine */ + + + +/* TEC_GC_LISTS - Garbage collect any local lookaside lists + * + * Function: + * + * This routine is called before we call malloc for more memory in + * an attempt to find the memory on some local lookaside lists. + */ +void +tec_gc_lists() +{ + + PREAMBLE(); + + screen_deallocate_format_lookaside_list(); + buff_deallocate_line_buffer_lookaside_list(); + +}/* End Routine */ + + +void +initialize_memory_stats() +{ + starting_break = 0; + +#if HAVE_SBRK + if(starting_break == NULL){ + starting_break = sbrk(0); + }/* End IF */ +#endif + +} + + +/* TECMEM_STATS - Insert memory statistics into the current buffer + * + * Function: + * + * This routine is called by the buffer map routine to allow us to + * insert some memory statistics into the map. + */ +void +tecmem_stats() +{ +char tmp_buffer[LINE_BUFFER_SIZE]; +register int i; +register int size; +int total_memory_in_use; +char *current_break; +int bss_in_use; + + PREAMBLE(); + + total_memory_in_use = malloc_stat_inuse; + + sprintf( + tmp_buffer, + "\n\n%d non-lookaside allocations, %d bytes outstanding\n\n", + malloc_stat_call_count, + malloc_stat_inuse + ); + buff_insert(curbuf,curbuf->dot,tmp_buffer,strlen(tmp_buffer)); + + for(i = 0; i < LOOKASIDE_COUNT; i++){ + if(lookaside_stat_allocated[i] == 0 && + lookaside_stat_available[i] == 0) continue; + size = ( i + 1 ) * MINIMUM_ALLOCATION_BLOCK; + total_memory_in_use += lookaside_stat_allocated[i] * size; + + sprintf( + tmp_buffer, + "LA%2d, size %4d, bytes in use %6d, bytes available %6d\n", + i, + size, + lookaside_stat_allocated[i] * size, + lookaside_stat_available[i] * size + ); + + buff_insert(curbuf,curbuf->dot,tmp_buffer,strlen(tmp_buffer)); + + }/* End FOR */ + + sprintf( + tmp_buffer, + "Malloc Leftover %d bytes\n", + malloc_leftover_size + ); + buff_insert(curbuf,curbuf->dot,tmp_buffer,strlen(tmp_buffer)); + + buff_insert(curbuf,curbuf->dot,"\n",1); + + for(i = 0; i < TYPE_C_MAXTYPE-TYPE_C_MINTYPE; i++){ + static char *type_name_list[] = { + "CBUFF", + "CPERM", + "CMD", + "UNDO", + "SCR", + "SCRBUF", + "SCREEN", + "SCREENBUF", + "LINE", + "LINEBUF", + "BHDR", + "WINDOW", + "LABELFIELD", + "WILD", + "TAGS", + "TAGENT", + "TAGSTR", + "MAXTYPE" + }; + + if(i >= ELEMENTS(type_name_list)){ + sprintf( + tmp_buffer, + "Unknown memory type index %d(%d)\n", + i, + i+TYPE_C_MINTYPE + ); + }/* End IF */ + + else { + sprintf( + tmp_buffer, + "Type %10s, blocks in use %d\n", + type_name_list[i], + memstat_by_type[i] + ); + }/* End Else */ + + buff_insert(curbuf,curbuf->dot,tmp_buffer,strlen(tmp_buffer)); + + }/* End FOR */ + +#if HAVE_SBRK + current_break = sbrk(0); + if(current_break != sbrk(0)){ + tec_panic("sbrk(0) seems to be allocating space!\n"); + }/* End IF */ + bss_in_use = current_break - starting_break; +#else + bss_in_use = 0; +#endif /* UNIX */ + + if( bss_in_use ){ + sprintf( + tmp_buffer, + "\nTotal memory in use %d, Total allocated bss %d\n", + total_memory_in_use, + bss_in_use + ); + } else { + sprintf(tmp_buffer,"\nTotal memory in use %d\n",total_memory_in_use); + } + buff_insert(curbuf,curbuf->dot,tmp_buffer,strlen(tmp_buffer)); + +}/* End Routine */ |