/* malloc.c -- Copyright 1989, 1995 Liam R. Quin. * All Rights Reserved. * This code is NOT in the public domain. * See the file COPYRIGHT for full details. */ /* * malloc.c -- wrapper routines for free/malloc, that can do checking and * print errors. * * $Id: malloc.c,v 1.19 96/08/14 16:57:34 lee Exp $ */ #include "globals.h" #include "error.h" #include #ifdef HAVE_STDLIB_H # include #else # include #endif #include "emalloc.h" #undef malloc #undef emalloc /* TODO: make What be a data structure: * typedef struct s_MemoryPool { * char FreeBlock[] * char *Data * unsigned int nominalSize; * char *Description; * int Flags; * } t_MemoryPool; * where flags can include * CanGrow * Can Shrink * ByteAlignment|PointerAlignment|BlockAlignment|DoubleAlignment * FreeWhenEmpty * UnmapWhenEmpty * * Then, can use mmap() to allocate memory, and unmap it again when it's * done. This would be a big win for the lqaddfile (LQC_AddWord) symbol * table, which might grow to 10 MBytes or more, and then shrink to * being mostly or entirely empty. */ typedef struct s_Reclaimer { unsigned long (* Reclaimer)( #ifdef HAVE_PROTO void *privte_stuff, unsigned long AmountToFree #endif ); char *Argument; struct s_Reclaimer *Next; } t_Reclaimer; PRIVATE t_Reclaimer *Reclaimers = 0; API void LQU_AddMemoryReclaimFunction(argument, theFunction) char *argument; unsigned long (* theFunction)( #ifdef HAVE_PROTO void *privte_stuff, unsigned long AmountToFree #endif ); { t_Reclaimer **rp; for (rp = &Reclaimers; *rp; rp = &(*rp)->Next) { if ((*rp)->Reclaimer == theFunction) { /* already there */ return; } } *rp = (t_Reclaimer *) emalloc("Reclaimer", sizeof(t_Reclaimer)); (*rp)->Reclaimer = theFunction; (*rp)->Argument = argument; (*rp)->Next = 0; } PRIVATE void ReclaimMemory(Amount) unsigned long Amount; { t_Reclaimer *rp; for (rp = Reclaimers; rp; rp = rp->Next) { unsigned long saved; saved = (* rp->Reclaimer)(rp->Argument, Amount); if (saved <= Amount) { Amount -= saved; } else { return; } } } /* * emalloc * Utilities/Memory * *

Allocates the given number of bytes of memory and returns a pointer * to it, using the system-supplied malloc function. *

If there is not enough memory, a fatal error is generated. * The What argument is included in any such error message, and should * be a human-readable description of the error, as an aid to help the * user understand exactly what failed.

*

A future release of lq-text will have an improved memory allocation * interface.

* * A fatal (E_FATAL | E_MEMORY) error is produced if memory is * exhausted. * * ecalloc * efree * Error *
*/ char * emalloc(What, nbytes) CONST char *What; unsigned nbytes; { char *Result; if (nbytes == 0) { nbytes = 4; } if ((Result = malloc(nbytes)) == (char *) 0) { ReclaimMemory(nbytes); if ((Result = malloc(nbytes)) == (char *) 0) { Error(E_FATAL|E_MEMORY, "emalloc request for %u bytes for %s denied", nbytes, What ); } } return Result; } #ifdef MALLOCTRACE char * LQU_TraceMalloc(What, nbytes, FileName, Line) CONST char *What; unsigned int nbytes; CONST char *FileName; int Line; { char *Result; if (nbytes == 0) { nbytes = 4; } if ((Result = malloc(nbytes)) == (char *) 0) { Error(E_FATAL|E_MEMORY|E_BUG, "%s: %d: emalloc(%u) failed for %s.", FileName, Line, nbytes, What ); } (void) fprintf(stderr, "malloc %u > 0x%x %s %d %s\n", nbytes, Result, FileName, Line, What); return Result; } #endif #undef ecalloc /* * ecalloc * Utilities/Memory * *

Allocates sufficient memory to hold the given Number of objects * of the given Size, after taking alignment constraints into account; * the system-supplied calloc function is used.

*

If there is not enough memory, a fatal error is generated. * The What argument is included in any such error message, and should * be a human-readable description of the error, as an aid to help the * user understand exactly what failed.

*

A future release of lq-text will have an improved memory allocation * interface.

* * A fatal (E_FATAL | E_MEMORY) error is produced if memory is * exhausted. * * emalloc * efree * Error *
*/ char * ecalloc(What, Number, Size) CONST char *What; unsigned int Number; unsigned int Size; { char *Result; if ((long) Number <= 0 || Size <= 0) { fprintf(stderr, "%s: warning: ecalloc(%u x %u) seems a little odd.\n", progname, Number, Size); } if ((Result = calloc(Number, Size)) == (char *) 0) { ReclaimMemory(Number * Size); if ((Result = calloc(Number, Size)) == (char *) 0) { Error(E_FATAL|E_MEMORY, "ecalloc request for (%u x %u) failed", Number, Size); } } return Result; } #ifdef MALLOCTRACE API char * LQU_TraceCalloc(What, Number, Size, FileName, Line) CONST char *What; unsigned int Number; unsigned int Size; CONST char *FileName; int Line; { char *Result; if ((long) Number <= 0) { fprintf(stderr, "%s: %s: %d: warning: ecalloc(%u x %u) strange!\n", progname, FileName, Line, Number, Size); } if ((Result = calloc(Number, Size)) == (char *) 0) { Error(E_FATAL|E_MEMORY|E_BUG, "%s: %d: ecalloc(%u x %u) failed.", FileName, Line, Number, Size); exit(1); } return Result; } #endif #undef erealloc /* * erealloc * Utilities/Memory * *

Changes the size of the given Object, either by extending the * area of memory allocated to it or by allocating a new area, * copying the data and freeing the original storage area.

*

If insufficient memory is available, a fatal (E_FATAL) error * is produced, which includes the given What argument as a textual * (human-readable) description of the object.

*

The system-supplied realloc function is used.

* * A pointer to the newly sized object; in most implementations this * will almost always be a new copy of the object. *

A future release of lq-text will have an improved memory allocation * interface.

* * A fatal (E_FATAL | E_MEMORY) error is produced if memory is * exhausted. * * emalloc * efree * Error *
*/ char * erealloc(Object, NewSize) char *Object; unsigned int NewSize; { char *Result; if (NewSize == 0) { NewSize = 4; } if ((Result = realloc(Object, NewSize)) == (char *) 0) { Error(E_FATAL|E_MEMORY, "erealloc to change 0x%x to %u bytes failed", Object, NewSize ); } return Result; } #ifdef MALLOCTRACE char * LQU_TraceRealloc(Object, NewSize, FileName, Line) CONST char *Object; unsigned int NewSize; CONST char *FileName; int Line; { char *Result; if (NewSize == 0) { NewSize = 4; } if ((Result = realloc(Object, NewSize)) == (char *) 0) { Error(E_FATAL|E_BUG|E_MEMORY, "%s: %d: erealloc(0x%x, %u) failed.", FileName, Line, Object, NewSize ); exit(1); } (void) fprintf(stderr, "realloc 0x%x %u > 0x%x %s %d\n", Object, NewSize, Result, FileName, Line); return Result; } #endif #undef efree /* * efree * Utilities/Memory * *

Returns the memory used by an object to the system, using the * system-provided free function.

*

A future release of lq-text will have an improved memory allocation * interface.

* * A warning (E_WARN) is produced a NULL pointer is passed as an argument. *
*/ void efree(String) char *String; { if (!String) { Error(E_WARN, "efree: call to free(0) ignored"); return; } (void) free(String); } #ifdef MALLOCTRACE API void LQU_TraceFree(String, FileName, Line) char *String; CONST char *FileName; int Line; { if (!String) { (void) Error(E_FATAL|E_BUG, "%s: %d: Warning: free(0) ignored", progname, FileName, Line); return; } (void) fprintf(stderr, "free 0x%x %s %d\n", String, FileName, Line); (void) free(String); } #endif