home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 2
/
FFMCD02.bin
/
new
/
gfx
/
edit
/
tsmorph
/
jpeg_ls
/
jmemmgr.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-12-21
|
38KB
|
1,103 lines
/*
* jmemmgr.c
*
* Copyright (C) 1991, 1992, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file provides the standard system-independent memory management
* routines. This code is usable across a wide variety of machines; most
* of the system dependencies have been isolated in a separate file.
* The major functions provided here are:
* * bookkeeping to allow all allocated memory to be freed upon exit;
* * policy decisions about how to divide available memory among the
* various large arrays;
* * control logic for swapping virtual arrays between main memory and
* backing storage.
* The separate system-dependent file provides the actual backing-storage
* access code, and it contains the policy decision about how much total
* main memory to use.
* This file is system-dependent in the sense that some of its functions
* are unnecessary in some systems. For example, if there is enough virtual
* memory so that backing storage will never be used, much of the big-array
* control logic could be removed. (Of course, if you have that much memory
* then you shouldn't care about a little bit of unused code...)
*
* These routines are invoked via the methods alloc_small, free_small,
* alloc_medium, free_medium, alloc_small_sarray, free_small_sarray,
* alloc_small_barray, free_small_barray, request_big_sarray,
* request_big_barray, alloc_big_arrays, access_big_sarray, access_big_barray,
* free_big_sarray, free_big_barray, and free_all.
*/
#define AM_MEMORY_MANAGER /* we define big_Xarray_control structs */
#include "jinclude.h"
#include "jmemsys.h" /* import the system-dependent declarations */
#ifndef NO_GETENV
#ifdef INCLUDES_ARE_ANSI
#include <stdlib.h> /* to declare getenv() */
#else
extern char * getenv PP((const char * name));
#endif
#endif
/*
* On many systems it is not necessary to distinguish alloc_small from
* alloc_medium; the main case where they must be distinguished is when
* FAR pointers are distinct from regular pointers. However, you might
* want to keep them separate if you have different system-dependent logic
* for small and large memory requests (i.e., jget_small and jget_large
* do different things).
*/
#ifdef NEED_FAR_POINTERS
#define NEED_ALLOC_MEDIUM /* flags alloc_medium really exists */
#endif
/*
* Many machines require storage alignment: longs must start on 4-byte
* boundaries, doubles on 8-byte boundaries, etc. On such machines, malloc()
* always returns pointers that are multiples of the worst-case alignment
* requirement, and we had better do so too. This means the headers that
* we tack onto allocated structures had better have length a multiple of
* the alignment requirement.
* There isn't any really portable way to determine the worst-case alignment
* requirement. In this code we assume that the alignment requirement is
* multiples of sizeof(align_type). Here we define align_type as double;
* with this definition, the code will run on all machines known to me.
* If your machine has lesser alignment needs, you can save a few bytes
* by making align_type smaller.
*/
typedef double align_type;
/*
* Some important notes:
* The allocation routines provided here must never return NULL.
* They should exit to error_exit if unsuccessful.
*
* It's not a good idea to try to merge the sarray and barray routines,
* even though they are textually almost the same, because samples are
* usually stored as bytes while coefficients are shorts. Thus, in machines
* where byte pointers have a different representation from word pointers,
* the resulting machine code could not be the same.
*/
static external_methods_ptr methods; /* saved for access to error_exit */
#ifdef MEM_STATS /* optional extra stuff for statistics */
/* These macros are the assumed overhead per block for malloc().
* They don't have to be accurate, but the printed statistics will be
* off a little bit if they are not.
*/
#define MALLOC_OVERHEAD (SIZEOF(void *)) /* overhead for jget_small() */
#define MALLOC_FAR_OVERHEAD (SIZEOF(void FAR *)) /* for jget_large() */
static long total_num_small = 0; /* total # of small objects alloced */
static long total_bytes_small = 0; /* total bytes requested */
static long cur_num_small = 0; /* # currently alloced */
static long max_num_small = 0; /* max simultaneously alloced */
#ifdef NEED_ALLOC_MEDIUM
static long total_num_medium = 0; /* total # of medium objects alloced */
static long total_bytes_medium = 0; /* total bytes requested */
static long cur_num_medium = 0; /* # currently alloced */
static long max_num_medium = 0; /* max simultaneously alloced */
#endif
static long total_num_sarray = 0; /* total # of sarray objects alloced */
static long total_bytes_sarray = 0; /* total bytes requested */
static long cur_num_sarray = 0; /* # currently alloced */
static long max_num_sarray = 0; /* max simultaneously alloced */
static long total_num_barray = 0; /* total # of barray objects alloced */
static long total_bytes_barray = 0; /* total bytes requested */
static long cur_num_barray = 0; /* # currently alloced */
static long max_num_barray = 0; /* max simultaneously alloced */
LOCAL void
print_mem_stats (void)
{
/* since this is only a debugging stub, we can cheat a little on the
* trace message mechanism... helpful 'cuz trace_message can't handle longs.
*/
fprintf1(stderr, "total_num_small = %ld\n", total_num_small);
fprintf1(stderr, "total_bytes_small = %ld\n", total_bytes_small);
if (cur_num_small)
fprintf1(stderr, "cur_num_small = %ld\n", cur_num_small);
fprintf1(stderr, "max_num_small = %ld\n", max_num_small);
#ifdef NEED_ALLOC_MEDIUM
fprintf1(stderr, "total_num_medium = %ld\n", total_num_medium);
fprintf1(stderr, "total_bytes_medium = %ld\n", total_bytes_medium);
if (cur_num_medium)
fprintf1(stderr, "cur_num_medium = %ld\n", cur_num_medium);
fprintf1(stderr, "max_num_medium = %ld\n", max_num_medium);
#endif
fprintf1(stderr, "total_num_sarray = %ld\n", total_num_sarray);
fprintf1(stderr, "total_bytes_sarray = %ld\n", total_bytes_sarray);
if (cur_num_sarray)
fprintf1(stderr, "cur_num_sarray = %ld\n", cur_num_sarray);
fprintf1(stderr, "max_num_sarray = %ld\n", max_num_sarray);
fprintf1(stderr, "total_num_barray = %ld\n", total_num_barray);
fprintf1(stderr, "total_bytes_barray = %ld\n", total_bytes_barray);
if (cur_num_barray)
fprintf1(stderr, "cur_num_barray = %ld\n", cur_num_barray);
fprintf1(stderr, "max_num_barray = %ld\n", max_num_barray);
}
#endif /* MEM_STATS */
LOCAL void
out_of_memory (int which)
/* Report an out-of-memory error and stop execution */
/* If we compiled MEM_STATS support, report alloc requests before dying */
{
#ifdef MEM_STATS
if (methods->trace_level <= 0) /* don't do it if free_all() will */
print_mem_stats(); /* print optional memory usage statistics */
#endif
ERREXIT1(methods, "Insufficient memory (case %ld)", which);
}
/*
* Management of "small" objects.
* These are all-in-memory, and are in near-heap space on an 80x86.
*/
typedef union small_struct * small_ptr;
typedef union small_struct {
small_ptr next; /* next in list of allocated objects */
align_type dummy; /* ensures alignment of following storage */
} small_hdr;
static small_ptr small_list; /* head of list */
METHODDEF void *
alloc_small (size_t sizeofobject)
/* Allocate a "small" object */
{
small_ptr result;
sizeofobject += SIZEOF(small_hdr); /* add space for header */
#ifdef MEM_STATS
total_num_small++;
total_bytes_small += sizeofobject + MALLOC_OVERHEAD;
cur_num_small++;
if (cur_num_small > max_num_small) max_num_small = cur_num_small;
#endif
result = (small_ptr) jget_small(sizeofobject);
if (result == NULL)
out_of_memory(1);
result->next = small_list;
small_list = result;
result++; /* advance past header */
return (void *) result;
}
METHODDEF void
free_small (void *ptr)
/* Free a "small" object */
{
small_ptr hdr;
small_ptr * llink;
hdr = (small_ptr) ptr;