Home Docs Forums Bugzilla LXR Doxygen CVS Bonsai
Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

jmemmgr.c

Go to the documentation of this file.
00001 /*
00002  * jmemmgr.c
00003  *
00004  * Copyright (C) 1991-1997, Thomas G. Lane.
00005  * This file is part of the Independent JPEG Group's software.
00006  * For conditions of distribution and use, see the accompanying README file.
00007  *
00008  * This file contains the JPEG system-independent memory management
00009  * routines.  This code is usable across a wide variety of machines; most
00010  * of the system dependencies have been isolated in a separate file.
00011  * The major functions provided here are:
00012  *   * pool-based allocation and freeing of memory;
00013  *   * policy decisions about how to divide available memory among the
00014  *     virtual arrays;
00015  *   * control logic for swapping virtual arrays between main memory and
00016  *     backing storage.
00017  * The separate system-dependent file provides the actual backing-storage
00018  * access code, and it contains the policy decision about how much total
00019  * main memory to use.
00020  * This file is system-dependent in the sense that some of its functions
00021  * are unnecessary in some systems.  For example, if there is enough virtual
00022  * memory so that backing storage will never be used, much of the virtual
00023  * array control logic could be removed.  (Of course, if you have that much
00024  * memory then you shouldn't care about a little bit of unused code...)
00025  */
00026 
00027 #define JPEG_INTERNALS
00028 #define AM_MEMORY_MANAGER   /* we define jvirt_Xarray_control structs */
00029 #include "jinclude.h"
00030 #include "jpeglib.h"
00031 #include "jmemsys.h"        /* import the system-dependent declarations */
00032 
00033 #ifndef NO_GETENV
00034 #ifndef HAVE_STDLIB_H       /* <stdlib.h> should declare getenv() */
00035 extern char * getenv JPP((const char * name));
00036 #endif
00037 #endif
00038 
00039 
00040 /*
00041  * Some important notes:
00042  *   The allocation routines provided here must never return NULL.
00043  *   They should exit to error_exit if unsuccessful.
00044  *
00045  *   It's not a good idea to try to merge the sarray and barray routines,
00046  *   even though they are textually almost the same, because samples are
00047  *   usually stored as bytes while coefficients are shorts or ints.  Thus,
00048  *   in machines where byte pointers have a different representation from
00049  *   word pointers, the resulting machine code could not be the same.
00050  */
00051 
00052 
00053 /*
00054  * Many machines require storage alignment: longs must start on 4-byte
00055  * boundaries, doubles on 8-byte boundaries, etc.  On such machines, malloc()
00056  * always returns pointers that are multiples of the worst-case alignment
00057  * requirement, and we had better do so too.
00058  * There isn't any really portable way to determine the worst-case alignment
00059  * requirement.  This module assumes that the alignment requirement is
00060  * multiples of sizeof(ALIGN_TYPE).
00061  * By default, we define ALIGN_TYPE as double.  This is necessary on some
00062  * workstations (where doubles really do need 8-byte alignment) and will work
00063  * fine on nearly everything.  If your machine has lesser alignment needs,
00064  * you can save a few bytes by making ALIGN_TYPE smaller.
00065  * The only place I know of where this will NOT work is certain Macintosh
00066  * 680x0 compilers that define double as a 10-byte IEEE extended float.
00067  * Doing 10-byte alignment is counterproductive because longwords won't be
00068  * aligned well.  Put "#define ALIGN_TYPE long" in jconfig.h if you have
00069  * such a compiler.
00070  */
00071 
00072 #ifndef ALIGN_TYPE      /* so can override from jconfig.h */
00073 #define ALIGN_TYPE  double
00074 #endif
00075 
00076 
00077 /*
00078  * We allocate objects from "pools", where each pool is gotten with a single
00079  * request to jpeg_get_small() or jpeg_get_large().  There is no per-object
00080  * overhead within a pool, except for alignment padding.  Each pool has a
00081  * header with a link to the next pool of the same class.
00082  * Small and large pool headers are identical except that the latter's
00083  * link pointer must be FAR on 80x86 machines.
00084  * Notice that the "real" header fields are union'ed with a dummy ALIGN_TYPE
00085  * field.  This forces the compiler to make SIZEOF(small_pool_hdr) a multiple
00086  * of the alignment requirement of ALIGN_TYPE.
00087  */
00088 
00089 typedef union small_pool_struct * small_pool_ptr;
00090 
00091 typedef union small_pool_struct {
00092   struct {
00093     small_pool_ptr next;    /* next in list of pools */
00094     size_t bytes_used;      /* how many bytes already used within pool */
00095     size_t bytes_left;      /* bytes still available in this pool */
00096   } hdr;
00097   ALIGN_TYPE dummy;     /* included in union to ensure alignment */
00098 } small_pool_hdr;
00099 
00100 typedef union large_pool_struct FAR * large_pool_ptr;
00101 
00102 typedef union large_pool_struct {
00103   struct {
00104     large_pool_ptr next;    /* next in list of pools */
00105     size_t bytes_used;      /* how many bytes already used within pool */
00106     size_t bytes_left;      /* bytes still available in this pool */
00107   } hdr;
00108   ALIGN_TYPE dummy;     /* included in union to ensure alignment */
00109 } large_pool_hdr;
00110 
00111 
00112 /*
00113  * Here is the full definition of a memory manager object.
00114  */
00115 
00116 typedef struct {
00117   struct jpeg_memory_mgr pub;   /* public fields */
00118 
00119   /* Each pool identifier (lifetime class) names a linked list of pools. */
00120   small_pool_ptr small_list[JPOOL_NUMPOOLS];
00121   large_pool_ptr large_list[JPOOL_NUMPOOLS];
00122 
00123   /* Since we only have one lifetime class of virtual arrays, only one
00124    * linked list is necessary (for each datatype).  Note that the virtual
00125    * array control blocks being linked together are actually stored somewhere
00126    * in the small-pool list.
00127    */
00128   jvirt_sarray_ptr virt_sarray_list;
00129   jvirt_barray_ptr virt_barray_list;
00130 
00131   /* This counts total space obtained from jpeg_get_small/large */
00132   long total_space_allocated;
00133 
00134   /* alloc_sarray and alloc_barray set this value for use by virtual
00135    * array routines.
00136    */
00137   JDIMENSION last_rowsperchunk; /* from most recent alloc_sarray/barray */
00138 } my_memory_mgr;
00139 
00140 typedef my_memory_mgr * my_mem_ptr;
00141 
00142 
00143 /*
00144  * The control blocks for virtual arrays.
00145  * Note that these blocks are allocated in the "small" pool area.
00146  * System-dependent info for the associated backing store (if any) is hidden
00147  * inside the backing_store_info struct.
00148  */
00149 
00150 struct jvirt_sarray_control {
00151   JSAMPARRAY mem_buffer;    /* => the in-memory buffer */
00152   JDIMENSION rows_in_array; /* total virtual array height */
00153   JDIMENSION samplesperrow; /* width of array (and of memory buffer) */
00154   JDIMENSION maxaccess;     /* max rows accessed by access_virt_sarray */
00155   JDIMENSION rows_in_mem;   /* height of memory buffer */
00156   JDIMENSION rowsperchunk;  /* allocation chunk size in mem_buffer */
00157   JDIMENSION cur_start_row; /* first logical row # in the buffer */
00158   JDIMENSION first_undef_row;   /* row # of first uninitialized row */
00159   boolean pre_zero;     /* pre-zero mode requested? */
00160   boolean dirty;        /* do current buffer contents need written? */
00161   boolean b_s_open;     /* is backing-store data valid? */
00162   jvirt_sarray_ptr next;    /* link to next virtual sarray control block */
00163   backing_store_info b_s_info;  /* System-dependent control info */
00164 };
00165 
00166 struct jvirt_barray_control {
00167   JBLOCKARRAY mem_buffer;   /* => the in-memory buffer */
00168   JDIMENSION rows_in_array; /* total virtual array height */
00169   JDIMENSION blocksperrow;  /* width of array (and of memory buffer) */
00170   JDIMENSION maxaccess;     /* max rows accessed by access_virt_barray */
00171   JDIMENSION rows_in_mem;   /* height of memory buffer */
00172   JDIMENSION rowsperchunk;  /* allocation chunk size in mem_buffer */
00173   JDIMENSION cur_start_row; /* first logical row # in the buffer */
00174   JDIMENSION first_undef_row;   /* row # of first uninitialized row */
00175   boolean pre_zero;     /* pre-zero mode requested? */
00176   boolean dirty;        /* do current buffer contents need written? */
00177   boolean b_s_open;     /* is backing-store data valid? */
00178   jvirt_barray_ptr next;    /* link to next virtual barray control block */
00179   backing_store_info b_s_info;  /* System-dependent control info */
00180 };
00181 
00182 
00183 #ifdef MEM_STATS        /* optional extra stuff for statistics */
00184 
00185 LOCAL(void)
00186 print_mem_stats (j_common_ptr cinfo, int pool_id)
00187 {
00188   my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
00189   small_pool_ptr shdr_ptr;
00190   large_pool_ptr lhdr_ptr;
00191 
00192   /* Since this is only a debugging stub, we can cheat a little by using
00193    * fprintf directly rather than going through the trace message code.
00194    * This is helpful because message parm array can't handle longs.
00195    */
00196   fprintf(stderr, "Freeing pool %d, total space = %ld\n",
00197       pool_id, mem->total_space_allocated);
00198 
00199   for (lhdr_ptr = mem->large_list[pool_id]; lhdr_ptr != NULL;
00200        lhdr_ptr = lhdr_ptr->hdr.next) {
00201     fprintf(stderr, "  Large chunk used %ld\n",
00202         (long) lhdr_ptr->hdr.bytes_used);
00203   }
00204 
00205   for (shdr_ptr = mem->small_list[pool_id]; shdr_ptr != NULL;
00206        shdr_ptr = shdr_ptr->hdr.next) {
00207     fprintf(stderr, "  Small chunk used %ld free %ld\n",
00208         (long) shdr_ptr->hdr.bytes_used,
00209         (long) shdr_ptr->hdr.bytes_left);
00210   }
00211 }
00212 
00213 #endif /* MEM_STATS */
00214 
00215 
00216 LOCAL(void)
00217 out_of_memory (j_common_ptr cinfo, int which)
00218 /* Report an out-of-memory error and stop execution */
00219 /* If we compiled MEM_STATS support, report alloc requests before dying */
00220 {
00221 #ifdef MEM_STATS
00222   cinfo->err->trace_level = 2;  /* force self_destruct to report stats */
00223 #endif
00224   ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, which);
00225 }
00226 
00227 
00228 /*
00229  * Allocation of "small" objects.
00230  *
00231  * For these, we use pooled storage.  When a new pool must be created,
00232  * we try to get enough space for the current request plus a "slop" factor,
00233  * where the slop will be the amount of leftover space in the new pool.
00234  * The speed vs. space tradeoff is largely determined by the slop values.
00235  * A different slop value is provided for each pool class (lifetime),
00236  * and we also distinguish the first pool of a class from later ones.
00237  * NOTE: the values given work fairly well on both 16- and 32-bit-int
00238  * machines, but may be too small if longs are 64 bits or more.
00239  */
00240 
00241 static const size_t first_pool_slop[JPOOL_NUMPOOLS] = 
00242 {
00243     1600,           /* first PERMANENT pool */
00244     16000           /* first IMAGE pool */
00245 };
00246 
00247 static const size_t extra_pool_slop[JPOOL_NUMPOOLS] = 
00248 {
00249     0,          /* additional PERMANENT pools */
00250     5000            /* additional IMAGE pools */
00251 };
00252 
00253 #define MIN_SLOP  50        /* greater than 0 to avoid futile looping */
00254 
00255 
00256 METHODDEF(void *)
00257 alloc_small (j_common_ptr cinfo, int pool_id, size_t sizeofobject)
00258 /* Allocate a "small" object */
00259 {
00260   my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
00261   small_pool_ptr hdr_ptr, prev_hdr_ptr;
00262   char * data_ptr;
00263   size_t odd_bytes, min_request, slop;
00264 
00265   /* Check for unsatisfiable request (do now to ensure no overflow below) */
00266   if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(small_pool_hdr)))
00267     out_of_memory(cinfo, 1);    /* request exceeds malloc's ability */
00268 
00269   /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */
00270   odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE);
00271   if (odd_bytes > 0)
00272     sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes;
00273 
00274   /* See if space is available in any existing pool */
00275   if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS)
00276     ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */
00277   prev_hdr_ptr = NULL;
00278   hdr_ptr = mem->small_list[pool_id];
00279   while (hdr_ptr != NULL) {
00280     if (hdr_ptr->hdr.bytes_left >= sizeofobject)
00281       break;            /* found pool with enough space */
00282     prev_hdr_ptr = hdr_ptr;
00283     hdr_ptr = hdr_ptr->hdr.next;
00284   }
00285 
00286   /* Time to make a new pool? */
00287   if (hdr_ptr == NULL) {
00288     /* min_request is what we need now, slop is what will be leftover */
00289     min_request = sizeofobject + SIZEOF(small_pool_hdr);
00290     if (prev_hdr_ptr == NULL)   /* first pool in class? */
00291       slop = first_pool_slop[pool_id];
00292     else
00293       slop = extra_pool_slop[pool_id];
00294     /* Don't ask for more than MAX_ALLOC_CHUNK */
00295     if (slop > (size_t) (MAX_ALLOC_CHUNK-min_request))
00296       slop = (size_t) (MAX_ALLOC_CHUNK-min_request);
00297     /* Try to get space, if fail reduce slop and try again */
00298     for (;;) {
00299       hdr_ptr = (small_pool_ptr) jpeg_get_small(cinfo, min_request + slop);
00300       if (hdr_ptr != NULL)
00301     break;
00302       slop /= 2;
00303       if (slop < MIN_SLOP)  /* give up when it gets real small */
00304     out_of_memory(cinfo, 2); /* jpeg_get_small failed */
00305     }
00306     mem->total_space_allocated += min_request + slop;
00307     /* Success, initialize the new pool header and add to end of list */
00308     hdr_ptr->hdr.next = NULL;
00309     hdr_ptr->hdr.bytes_used = 0;
00310     hdr_ptr->hdr.bytes_left = sizeofobject + slop;
00311     if (prev_hdr_ptr == NULL)   /* first pool in class? */
00312       mem->small_list[pool_id] = hdr_ptr;
00313     else
00314       prev_hdr_ptr->hdr.next = hdr_ptr;
00315   }
00316 
00317   /* OK, allocate the object from the current pool */
00318   data_ptr = (char *) (hdr_ptr + 1); /* point to first data byte in pool */
00319   data_ptr += hdr_ptr->hdr.bytes_used; /* point to place for object */
00320   hdr_ptr->hdr.bytes_used += sizeofobject;
00321   hdr_ptr->hdr.bytes_left -= sizeofobject;
00322 
00323   return (void *) data_ptr;
00324 }
00325 
00326 
00327 /*
00328  * Allocation of "large" objects.
00329  *
00330  * The external semantics of these are the same as "small" objects,
00331  * except that FAR pointers are used on 80x86.  However the pool
00332  * management heuristics are quite different.  We assume that each
00333  * request is large enough that it may as well be passed directly to
00334  * jpeg_get_large; the pool management just links everything together
00335  * so that we can free it all on demand.
00336  * Note: the major use of "large" objects is in JSAMPARRAY and JBLOCKARRAY
00337  * structures.  The routines that create these structures (see below)
00338  * deliberately bunch rows together to ensure a large request size.
00339  */
00340 
00341 METHODDEF(void FAR *)
00342 alloc_large (j_common_ptr cinfo, int pool_id, size_t sizeofobject)
00343 /* Allocate a "large" object */
00344 {
00345   my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
00346   large_pool_ptr hdr_ptr;
00347   size_t odd_bytes;
00348 
00349   /* Check for unsatisfiable request (do now to ensure no overflow below) */
00350   if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)))
00351     out_of_memory(cinfo, 3);    /* request exceeds malloc's ability */
00352 
00353   /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */
00354   odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE);
00355   if (odd_bytes > 0)
00356     sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes;
00357 
00358   /* Always make a new pool */
00359   if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS)
00360     ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */
00361 
00362   hdr_ptr = (large_pool_ptr) jpeg_get_large(cinfo, sizeofobject +
00363                         SIZEOF(large_pool_hdr));
00364   if (hdr_ptr == NULL)
00365     out_of_memory(cinfo, 4);    /* jpeg_get_large failed */
00366   mem->total_space_allocated += sizeofobject + SIZEOF(large_pool_hdr);
00367 
00368   /* Success, initialize the new pool header and add to list */
00369   hdr_ptr->hdr.next = mem->large_list[pool_id];
00370   /* We maintain space counts in each pool header for statistical purposes,
00371    * even though they are not needed for allocation.
00372    */
00373   hdr_ptr->hdr.bytes_used = sizeofobject;
00374   hdr_ptr->hdr.bytes_left = 0;
00375   mem->large_list[pool_id] = hdr_ptr;
00376 
00377   return (void FAR *) (hdr_ptr + 1); /* point to first data byte in pool */
00378 }
00379 
00380 
00381 /*
00382  * Creation of 2-D sample arrays.
00383  * The pointers are in near heap, the samples themselves in FAR heap.
00384  *
00385  * To minimize allocation overhead and to allow I/O of large contiguous
00386  * blocks, we allocate the sample rows in groups of as many rows as possible
00387  * without exceeding MAX_ALLOC_CHUNK total bytes per allocation request.
00388  * NB: the virtual array control routines, later in this file, know about
00389  * this chunking of rows.  The rowsperchunk value is left in the mem manager
00390  * object so that it can be saved away if this sarray is the workspace for
00391  * a virtual array.
00392  */
00393 
00394 METHODDEF(JSAMPARRAY)
00395 alloc_sarray (j_common_ptr cinfo, int pool_id,
00396           JDIMENSION samplesperrow, JDIMENSION numrows)
00397 /* Allocate a 2-D sample array */
00398 {
00399   my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
00400   JSAMPARRAY result;
00401   JSAMPROW workspace;
00402   JDIMENSION rowsperchunk, currow, i;
00403   long ltemp;
00404 
00405   /* Calculate max # of rows allowed in one allocation chunk */
00406   ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) /
00407       ((long) samplesperrow * SIZEOF(JSAMPLE));
00408   if (ltemp <= 0)
00409     ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
00410   if (ltemp < (long) numrows)
00411     rowsperchunk = (JDIMENSION) ltemp;
00412   else
00413     rowsperchunk = numrows;
00414   mem->last_rowsperchunk = rowsperchunk;
00415 
00416   /* Get space for row pointers (small object) */
00417   result = (JSAMPARRAY) alloc_small(cinfo, pool_id,
00418                     (size_t) (numrows * SIZEOF(JSAMPROW)));
00419 
00420   /* Get the rows themselves (large objects) */
00421   currow = 0;
00422   while (currow < numrows) {
00423     rowsperchunk = MIN(rowsperchunk, numrows - currow);
00424     workspace = (JSAMPROW) alloc_large(cinfo, pool_id,
00425     (size_t) ((size_t) rowsperchunk * (size_t) samplesperrow
00426           * SIZEOF(JSAMPLE)));
00427     for (i = rowsperchunk; i > 0; i--) {
00428       result[currow++] = workspace;
00429       workspace += samplesperrow;
00430     }
00431   }
00432 
00433   return result;
00434 }
00435 
00436 
00437 /*
00438  * Creation of 2-D coefficient-block arrays.
00439  * This is essentially the same as the code for sample arrays, above.
00440  */
00441 
00442 METHODDEF(JBLOCKARRAY)
00443 alloc_barray (j_common_ptr cinfo, int pool_id,
00444           JDIMENSION blocksperrow, JDIMENSION numrows)
00445 /* Allocate a 2-D coefficient-block array */
00446 {
00447   my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
00448   JBLOCKARRAY result;
00449   JBLOCKROW workspace;
00450   JDIMENSION rowsperchunk, currow, i;
00451   long ltemp;
00452 
00453   /* Calculate max # of rows allowed in one allocation chunk */
00454   ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) /
00455       ((long) blocksperrow * SIZEOF(JBLOCK));
00456   if (ltemp <= 0)
00457     ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
00458   if (ltemp < (long) numrows)
00459     rowsperchunk = (JDIMENSION) ltemp;
00460   else
00461     rowsperchunk = numrows;
00462   mem->last_rowsperchunk = rowsperchunk;
00463 
00464   /* Get space for row pointers (small object) */
00465   result = (JBLOCKARRAY) alloc_small(cinfo, pool_id,
00466                      (size_t) (numrows * SIZEOF(JBLOCKROW)));
00467 
00468   /* Get the rows themselves (large objects) */
00469   currow = 0;
00470   while (currow < numrows) {
00471     rowsperchunk = MIN(rowsperchunk, numrows - currow);
00472     workspace = (JBLOCKROW) alloc_large(cinfo, pool_id,
00473     (size_t) ((size_t) rowsperchunk * (size_t) blocksperrow
00474           * SIZEOF(JBLOCK)));
00475     for (i = rowsperchunk; i > 0; i--) {
00476       result[currow++] = workspace;
00477       workspace += blocksperrow;
00478     }
00479   }
00480 
00481   return result;
00482 }
00483 
00484 
00485 /*
00486  * About virtual array management:
00487  *
00488  * The above "normal" array routines are only used to allocate strip buffers
00489  * (as wide as the image, but just a few rows high).  Full-image-sized buffers
00490  * are handled as "virtual" arrays.  The array is still accessed a strip at a
00491  * time, but the memory manager must save the whole array for repeated
00492  * accesses.  The intended implementation is that there is a strip buffer in
00493  * memory (as high as is possible given the desired memory limit), plus a
00494  * backing file that holds the rest of the array.
00495  *
00496  * The request_virt_array routines are told the total size of the image and
00497  * the maximum number of rows that will be accessed at once.  The in-memory
00498  * buffer must be at least as large as the maxaccess value.
00499  *
00500  * The request routines create control blocks but not the in-memory buffers.
00501  * That is postponed until realize_virt_arrays is called.  At that time the
00502  * total amount of space needed is known (approximately, anyway), so free
00503  * memory can be divided up fairly.
00504  *
00505  * The access_virt_array routines are responsible for making a specific strip
00506  * area accessible (after reading or writing the backing file, if necessary).
00507  * Note that the access routines are told whether the caller intends to modify
00508  * the accessed strip; during a read-only pass this saves having to rewrite
00509  * data to disk.  The access routines are also responsible for pre-zeroing
00510  * any newly accessed rows, if pre-zeroing was requested.
00511  *
00512  * In current usage, the access requests are usually for nonoverlapping
00513  * strips; that is, successive access start_row numbers differ by exactly
00514  * num_rows = maxaccess.  This means we can get good performance with simple
00515  * buffer dump/reload logic, by making the in-memory buffer be a multiple
00516  * of the access height; then there will never be accesses across bufferload
00517  * boundaries.  The code will still work with overlapping access requests,
00518  * but it doesn't handle bufferload overlaps very efficiently.
00519  */
00520 
00521 
00522 METHODDEF(jvirt_sarray_ptr)
00523 request_virt_sarray (j_common_ptr cinfo, int pool_id, boolean pre_zero,
00524              JDIMENSION samplesperrow, JDIMENSION numrows,
00525              JDIMENSION maxaccess)
00526 /* Request a virtual 2-D sample array */
00527 {
00528   my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
00529   jvirt_sarray_ptr result;
00530 
00531   /* Only IMAGE-lifetime virtual arrays are currently supported */
00532   if (pool_id != JPOOL_IMAGE)
00533     ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */
00534 
00535   /* get control block */
00536   result = (jvirt_sarray_ptr) alloc_small(cinfo, pool_id,
00537                       SIZEOF(struct jvirt_sarray_control));
00538 
00539   result->mem_buffer = NULL;    /* marks array not yet realized */
00540   result->rows_in_array = numrows;
00541   result->samplesperrow = samplesperrow;
00542   result->maxaccess = maxaccess;
00543   result->pre_zero = pre_zero;
00544   result->b_s_open = FALSE; /* no associated backing-store object */
00545   result->next = mem->virt_sarray_list; /* add to list of virtual arrays */
00546   mem->virt_sarray_list = result;
00547 
00548   return result;
00549 }
00550 
00551 
00552 METHODDEF(jvirt_barray_ptr)
00553 request_virt_barray (j_common_ptr cinfo, int pool_id, boolean pre_zero,
00554              JDIMENSION blocksperrow, JDIMENSION numrows,
00555              JDIMENSION maxaccess)
00556 /* Request a virtual 2-D coefficient-block array */
00557 {
00558   my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
00559   jvirt_barray_ptr result;
00560 
00561   /* Only IMAGE-lifetime virtual arrays are currently supported */
00562   if (pool_id != JPOOL_IMAGE)
00563     ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */
00564 
00565   /* get control block */
00566   result = (jvirt_barray_ptr) alloc_small(cinfo, pool_id,
00567                       SIZEOF(struct jvirt_barray_control));
00568 
00569   result->mem_buffer = NULL;    /* marks array not yet realized */
00570   result->rows_in_array = numrows;
00571   result->blocksperrow = blocksperrow;
00572   result->maxaccess = maxaccess;
00573   result->pre_zero = pre_zero;
00574   result->b_s_open = FALSE; /* no associated backing-store object */
00575   result->next = mem->virt_barray_list; /* add to list of virtual arrays */
00576   mem->virt_barray_list = result;
00577 
00578   return result;
00579 }
00580 
00581 
00582 METHODDEF(void)
00583 realize_virt_arrays (j_common_ptr cinfo)
00584 /* Allocate the in-memory buffers for any unrealized virtual arrays */
00585 {
00586   my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
00587   long space_per_minheight, maximum_space, avail_mem;
00588   long minheights, max_minheights;
00589   jvirt_sarray_ptr sptr;
00590   jvirt_barray_ptr bptr;
00591 
00592   /* Compute the minimum space needed (maxaccess rows in each buffer)
00593    * and the maximum space needed (full image height in each buffer).
00594    * These may be of use to the system-dependent jpeg_mem_available routine.
00595    */
00596   space_per_minheight = 0;
00597   maximum_space = 0;
00598   for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {
00599     if (sptr->mem_buffer == NULL) { /* if not realized yet */
00600       space_per_minheight += (long) sptr->maxaccess *
00601                  (long) sptr->samplesperrow * SIZEOF(JSAMPLE);
00602       maximum_space += (long) sptr->rows_in_array *
00603                (long) sptr->samplesperrow * SIZEOF(JSAMPLE);
00604     }
00605   }
00606   for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) {
00607     if (bptr->mem_buffer == NULL) { /* if not realized yet */
00608       space_per_minheight += (long) bptr->maxaccess *
00609                  (long) bptr->blocksperrow * SIZEOF(JBLOCK);
00610       maximum_space += (long) bptr->rows_in_array *
00611                (long) bptr->blocksperrow * SIZEOF(JBLOCK);
00612     }
00613   }
00614 
00615   if (space_per_minheight <= 0)
00616     return;         /* no unrealized arrays, no work */
00617 
00618   /* Determine amount of memory to actually use; this is system-dependent. */
00619   avail_mem = jpeg_mem_available(cinfo, space_per_minheight, maximum_space,
00620                  mem->total_space_allocated);
00621 
00622   /* If the maximum space needed is available, make all the buffers full
00623    * height; otherwise parcel it out with the same number of minheights
00624    * in each buffer.
00625    */
00626   if (avail_mem >= maximum_space)
00627     max_minheights = 1000000000L;
00628   else {
00629     max_minheights = avail_mem / space_per_minheight;
00630     /* If there doesn't seem to be enough space, try to get the minimum
00631      * anyway.  This allows a "stub" implementation of jpeg_mem_available().
00632      */
00633     if (max_minheights <= 0)
00634       max_minheights = 1;
00635   }
00636 
00637   /* Allocate the in-memory buffers and initialize backing store as needed. */
00638 
00639   for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {
00640     if (sptr->mem_buffer == NULL) { /* if not realized yet */
00641       minheights = ((long) sptr->rows_in_array - 1L) / sptr->maxaccess + 1L;
00642       if (minheights <= max_minheights) {
00643     /* This buffer fits in memory */
00644     sptr->rows_in_mem = sptr->rows_in_array;
00645       } else {
00646     /* It doesn't fit in memory, create backing store. */
00647     sptr->rows_in_mem = (JDIMENSION) (max_minheights * sptr->maxaccess);
00648     jpeg_open_backing_store(cinfo, & sptr->b_s_info,
00649                 (long) sptr->rows_in_array *
00650                 (long) sptr->samplesperrow *
00651                 (long) SIZEOF(JSAMPLE));
00652     sptr->b_s_open = TRUE;
00653       }
00654       sptr->mem_buffer = alloc_sarray(cinfo, JPOOL_IMAGE,
00655                       sptr->samplesperrow, sptr->rows_in_mem);
00656       sptr->rowsperchunk = mem->last_rowsperchunk;
00657       sptr->cur_start_row = 0;
00658       sptr->first_undef_row = 0;
00659       sptr->dirty = FALSE;
00660     }
00661   }
00662 
00663   for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) {
00664     if (bptr->mem_buffer == NULL) { /* if not realized yet */
00665       minheights = ((long) bptr->rows_in_array - 1L) / bptr->maxaccess + 1L;
00666       if (minheights <= max_minheights) {
00667     /* This buffer fits in memory */
00668     bptr->rows_in_mem = bptr->rows_in_array;
00669       } else {
00670     /* It doesn't fit in memory, create backing store. */
00671     bptr->rows_in_mem = (JDIMENSION) (max_minheights * bptr->maxaccess);
00672     jpeg_open_backing_store(cinfo, & bptr->b_s_info,
00673                 (long) bptr->rows_in_array *
00674                 (long) bptr->blocksperrow *
00675                 (long) SIZEOF(JBLOCK));
00676     bptr->b_s_open = TRUE;
00677       }
00678       bptr->mem_buffer = alloc_barray(cinfo, JPOOL_IMAGE,
00679                       bptr->blocksperrow, bptr->rows_in_mem);
00680       bptr->rowsperchunk = mem->last_rowsperchunk;
00681       bptr->cur_start_row = 0;
00682       bptr->first_undef_row = 0;
00683       bptr->dirty = FALSE;
00684     }
00685   }
00686 }
00687 
00688 
00689 LOCAL(void)
00690 do_sarray_io (j_common_ptr cinfo, jvirt_sarray_ptr ptr, boolean writing)
00691 /* Do backing store read or write of a virtual sample array */
00692 {
00693   long bytesperrow, file_offset, byte_count, rows, thisrow, i;
00694 
00695   bytesperrow = (long) ptr->samplesperrow * SIZEOF(JSAMPLE);
00696   file_offset = ptr->cur_start_row * bytesperrow;
00697   /* Loop to read or write each allocation chunk in mem_buffer */
00698   for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) {
00699     /* One chunk, but check for short chunk at end of buffer */
00700     rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i);
00701     /* Transfer no more than is currently defined */
00702     thisrow = (long) ptr->cur_start_row + i;
00703     rows = MIN(rows, (long) ptr->first_undef_row - thisrow);
00704     /* Transfer no more than fits in file */
00705     rows = MIN(rows, (long) ptr->rows_in_array - thisrow);
00706     if (rows <= 0)      /* this chunk might be past end of file! */
00707       break;
00708     byte_count = rows * bytesperrow;
00709     if (writing)
00710       (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info,
00711                         (void FAR *) ptr->mem_buffer[i],
00712                         file_offset, byte_count);
00713     else
00714       (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info,
00715                        (void FAR *) ptr->mem_buffer[i],
00716                        file_offset, byte_count);
00717     file_offset += byte_count;
00718   }
00719 }
00720 
00721 
00722 LOCAL(void)
00723 do_barray_io (j_common_ptr cinfo, jvirt_barray_ptr ptr, boolean writing)
00724 /* Do backing store read or write of a virtual coefficient-block array */
00725 {
00726   long bytesperrow, file_offset, byte_count, rows, thisrow, i;
00727 
00728   bytesperrow = (long) ptr->blocksperrow * SIZEOF(JBLOCK);
00729   file_offset = ptr->cur_start_row * bytesperrow;
00730   /* Loop to read or write each allocation chunk in mem_buffer */
00731   for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) {
00732     /* One chunk, but check for short chunk at end of buffer */
00733     rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i);
00734     /* Transfer no more than is currently defined */
00735     thisrow = (long) ptr->cur_start_row + i;
00736     rows = MIN(rows, (long) ptr->first_undef_row - thisrow);
00737     /* Transfer no more than fits in file */
00738     rows = MIN(rows, (long) ptr->rows_in_array - thisrow);
00739     if (rows <= 0)      /* this chunk might be past end of file! */
00740       break;
00741     byte_count = rows * bytesperrow;
00742     if (writing)
00743       (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info,
00744                         (void FAR *) ptr->mem_buffer[i],
00745                         file_offset, byte_count);
00746     else
00747       (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info,
00748                        (void FAR *) ptr->mem_buffer[i],
00749                        file_offset, byte_count);
00750     file_offset += byte_count;
00751   }
00752 }
00753 
00754 
00755 METHODDEF(JSAMPARRAY)
00756 access_virt_sarray (j_common_ptr cinfo, jvirt_sarray_ptr ptr,
00757             JDIMENSION start_row, JDIMENSION num_rows,
00758             boolean writable)
00759 /* Access the part of a virtual sample array starting at start_row */
00760 /* and extending for num_rows rows.  writable is true if  */
00761 /* caller intends to modify the accessed area. */
00762 {
00763   JDIMENSION end_row = start_row + num_rows;
00764   JDIMENSION undef_row;
00765 
00766   /* debugging check */
00767   if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess ||
00768       ptr->mem_buffer == NULL)
00769     ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
00770 
00771   /* Make the desired part of the virtual array accessible */
00772   if (start_row < ptr->cur_start_row ||
00773       end_row > ptr->cur_start_row+ptr->rows_in_mem) {
00774     if (! ptr->b_s_open)
00775       ERREXIT(cinfo, JERR_VIRTUAL_BUG);
00776     /* Flush old buffer contents if necessary */
00777     if (ptr->dirty) {
00778       do_sarray_io(cinfo, ptr, TRUE);
00779       ptr->dirty = FALSE;
00780     }
00781     /* Decide what part of virtual array to access.
00782      * Algorithm: if target address > current window, assume forward scan,
00783      * load starting at target address.  If target address < current window,
00784      * assume backward scan, load so that target area is top of window.
00785      * Note that when switching from forward write to forward read, will have
00786      * start_row = 0, so the limiting case applies and we load from 0 anyway.
00787      */
00788     if (start_row > ptr->cur_start_row) {
00789       ptr->cur_start_row = start_row;
00790     } else {
00791       /* use long arithmetic here to avoid overflow & unsigned problems */
00792       long ltemp;
00793 
00794       ltemp = (long) end_row - (long) ptr->rows_in_mem;
00795       if (ltemp < 0)
00796     ltemp = 0;      /* don't fall off front end of file */
00797       ptr->cur_start_row = (JDIMENSION) ltemp;
00798     }
00799     /* Read in the selected part of the array.
00800      * During the initial write pass, we will do no actual read
00801      * because the selected part is all undefined.
00802      */
00803     do_sarray_io(cinfo, ptr, FALSE);
00804   }
00805   /* Ensure the accessed part of the array is defined; prezero if needed.
00806    * To improve locality of access, we only prezero the part of the array
00807    * that the caller is about to access, not the entire in-memory array.
00808    */
00809   if (ptr->first_undef_row < end_row) {
00810     if (ptr->first_undef_row < start_row) {
00811       if (writable)     /* writer skipped over a section of array */
00812     ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
00813       undef_row = start_row;    /* but reader is allowed to read ahead */
00814     } else {
00815       undef_row = ptr->first_undef_row;
00816     }
00817     if (writable)
00818       ptr->first_undef_row = end_row;
00819     if (ptr->pre_zero) {
00820       size_t bytesperrow = (size_t) ptr->samplesperrow * SIZEOF(JSAMPLE);
00821       undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */
00822       end_row -= ptr->cur_start_row;
00823       while (undef_row < end_row) {
00824     jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow);
00825     undef_row++;
00826       }
00827     } else {
00828       if (! writable)       /* reader looking at undefined data */
00829     ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
00830     }
00831   }
00832   /* Flag the buffer dirty if caller will write in it */
00833   if (writable)
00834     ptr->dirty = TRUE;
00835   /* Return address of proper part of the buffer */
00836   return ptr->mem_buffer + (start_row - ptr->cur_start_row);
00837 }
00838 
00839 
00840 METHODDEF(JBLOCKARRAY)
00841 access_virt_barray (j_common_ptr cinfo, jvirt_barray_ptr ptr,
00842             JDIMENSION start_row, JDIMENSION num_rows,
00843             boolean writable)
00844 /* Access the part of a virtual block array starting at start_row */
00845 /* and extending for num_rows rows.  writable is true if  */
00846 /* caller intends to modify the accessed area. */
00847 {
00848   JDIMENSION end_row = start_row + num_rows;
00849   JDIMENSION undef_row;
00850 
00851   /* debugging check */
00852   if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess ||
00853       ptr->mem_buffer == NULL)
00854     ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
00855 
00856   /* Make the desired part of the virtual array accessible */
00857   if (start_row < ptr->cur_start_row ||
00858       end_row > ptr->cur_start_row+ptr->rows_in_mem) {
00859     if (! ptr->b_s_open)
00860       ERREXIT(cinfo, JERR_VIRTUAL_BUG);
00861     /* Flush old buffer contents if necessary */
00862     if (ptr->dirty) {
00863       do_barray_io(cinfo, ptr, TRUE);
00864       ptr->dirty = FALSE;
00865     }
00866     /* Decide what part of virtual array to access.
00867      * Algorithm: if target address > current window, assume forward scan,
00868      * load starting at target address.  If target address < current window,
00869      * assume backward scan, load so that target area is top of window.
00870      * Note that when switching from forward write to forward read, will have
00871      * start_row = 0, so the limiting case applies and we load from 0 anyway.
00872      */
00873     if (start_row > ptr->cur_start_row) {
00874       ptr->cur_start_row = start_row;
00875     } else {
00876       /* use long arithmetic here to avoid overflow & unsigned problems */
00877       long ltemp;
00878 
00879       ltemp = (long) end_row - (long) ptr->rows_in_mem;
00880       if (ltemp < 0)
00881     ltemp = 0;      /* don't fall off front end of file */
00882       ptr->cur_start_row = (JDIMENSION) ltemp;
00883     }
00884     /* Read in the selected part of the array.
00885      * During the initial write pass, we will do no actual read
00886      * because the selected part is all undefined.
00887      */
00888     do_barray_io(cinfo, ptr, FALSE);
00889   }
00890   /* Ensure the accessed part of the array is defined; prezero if needed.
00891    * To improve locality of access, we only prezero the part of the array
00892    * that the caller is about to access, not the entire in-memory array.
00893    */
00894   if (ptr->first_undef_row < end_row) {
00895     if (ptr->first_undef_row < start_row) {
00896       if (writable)     /* writer skipped over a section of array */
00897     ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
00898       undef_row = start_row;    /* but reader is allowed to read ahead */
00899     } else {
00900       undef_row = ptr->first_undef_row;
00901     }
00902     if (writable)
00903       ptr->first_undef_row = end_row;
00904     if (ptr->pre_zero) {
00905       size_t bytesperrow = (size_t) ptr->blocksperrow * SIZEOF(JBLOCK);
00906       undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */
00907       end_row -= ptr->cur_start_row;
00908       while (undef_row < end_row) {
00909     jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow);
00910     undef_row++;
00911       }
00912     } else {
00913       if (! writable)       /* reader looking at undefined data */
00914     ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
00915     }
00916   }
00917   /* Flag the buffer dirty if caller will write in it */
00918   if (writable)
00919     ptr->dirty = TRUE;
00920   /* Return address of proper part of the buffer */
00921   return ptr->mem_buffer + (start_row - ptr->cur_start_row);
00922 }
00923 
00924 
00925 /*
00926  * Release all objects belonging to a specified pool.
00927  */
00928 
00929 METHODDEF(void)
00930 free_pool (j_common_ptr cinfo, int pool_id)
00931 {
00932   my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
00933   small_pool_ptr shdr_ptr;
00934   large_pool_ptr lhdr_ptr;
00935   size_t space_freed;
00936 
00937   if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS)
00938     ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */
00939 
00940 #ifdef MEM_STATS
00941   if (cinfo->err->trace_level > 1)
00942     print_mem_stats(cinfo, pool_id); /* print pool's memory usage statistics */
00943 #endif
00944 
00945   /* If freeing IMAGE pool, close any virtual arrays first */
00946   if (pool_id == JPOOL_IMAGE) {
00947     jvirt_sarray_ptr sptr;
00948     jvirt_barray_ptr bptr;
00949 
00950     for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {
00951       if (sptr->b_s_open) { /* there may be no backing store */
00952     sptr->b_s_open = FALSE; /* prevent recursive close if error */
00953     (*sptr->b_s_info.close_backing_store) (cinfo, & sptr->b_s_info);
00954       }
00955     }
00956     mem->virt_sarray_list = NULL;
00957     for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) {
00958       if (bptr->b_s_open) { /* there may be no backing store */
00959     bptr->b_s_open = FALSE; /* prevent recursive close if error */
00960     (*bptr->b_s_info.close_backing_store) (cinfo, & bptr->b_s_info);
00961       }
00962     }
00963     mem->virt_barray_list = NULL;
00964   }
00965 
00966   /* Release large objects */
00967   lhdr_ptr = mem->large_list[pool_id];
00968   mem->large_list[pool_id] = NULL;
00969 
00970   while (lhdr_ptr != NULL) {
00971     large_pool_ptr next_lhdr_ptr = lhdr_ptr->hdr.next;
00972     space_freed = lhdr_ptr->hdr.bytes_used +
00973           lhdr_ptr->hdr.bytes_left +
00974           SIZEOF(large_pool_hdr);
00975     jpeg_free_large(cinfo, (void FAR *) lhdr_ptr, space_freed);
00976     mem->total_space_allocated -= space_freed;
00977     lhdr_ptr = next_lhdr_ptr;
00978   }
00979 
00980   /* Release small objects */
00981   shdr_ptr = mem->small_list[pool_id];
00982   mem->small_list[pool_id] = NULL;
00983 
00984   while (shdr_ptr != NULL) {
00985     small_pool_ptr next_shdr_ptr = shdr_ptr->hdr.next;
00986     space_freed = shdr_ptr->hdr.bytes_used +
00987           shdr_ptr->hdr.bytes_left +
00988           SIZEOF(small_pool_hdr);
00989     jpeg_free_small(cinfo, (void *) shdr_ptr, space_freed);
00990     mem->total_space_allocated -= space_freed;
00991     shdr_ptr = next_shdr_ptr;
00992   }
00993 }
00994 
00995 
00996 /*
00997  * Close up shop entirely.
00998  * Note that this cannot be called unless cinfo->mem is non-NULL.
00999  */
01000 
01001 METHODDEF(void)
01002 self_destruct (j_common_ptr cinfo)
01003 {
01004   int pool;
01005 
01006   /* Close all backing store, release all memory.
01007    * Releasing pools in reverse order might help avoid fragmentation
01008    * with some (brain-damaged) malloc libraries.
01009    */
01010   for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) {
01011     free_pool(cinfo, pool);
01012   }
01013 
01014   /* Release the memory manager control block too. */
01015   jpeg_free_small(cinfo, (void *) cinfo->mem, SIZEOF(my_memory_mgr));
01016   cinfo->mem = NULL;        /* ensures I will be called only once */
01017 
01018   jpeg_mem_term(cinfo);     /* system-dependent cleanup */
01019 }
01020 
01021 
01022 /*
01023  * Memory manager initialization.
01024  * When this is called, only the error manager pointer is valid in cinfo!
01025  */
01026 
01027 GLOBAL(void)
01028 jinit_memory_mgr (j_common_ptr cinfo)
01029 {
01030   my_mem_ptr mem;
01031   long max_to_use;
01032   int pool;
01033   size_t test_mac;
01034 
01035   cinfo->mem = NULL;        /* for safety if init fails */
01036 
01037   /* Check for configuration errors.
01038    * SIZEOF(ALIGN_TYPE) should be a power of 2; otherwise, it probably
01039    * doesn't reflect any real hardware alignment requirement.
01040    * The test is a little tricky: for X>0, X and X-1 have no one-bits
01041    * in common if and only if X is a power of 2, ie has only one one-bit.
01042    * Some compilers may give an "unreachable code" warning here; ignore it.
01043    */
01044   if ((SIZEOF(ALIGN_TYPE) & (SIZEOF(ALIGN_TYPE)-1)) != 0)
01045     ERREXIT(cinfo, JERR_BAD_ALIGN_TYPE);
01046   /* MAX_ALLOC_CHUNK must be representable as type size_t, and must be
01047    * a multiple of SIZEOF(ALIGN_TYPE).
01048    * Again, an "unreachable code" warning may be ignored here.
01049    * But a "constant too large" warning means you need to fix MAX_ALLOC_CHUNK.
01050    */
01051   test_mac = (size_t) MAX_ALLOC_CHUNK;
01052   if ((long) test_mac != MAX_ALLOC_CHUNK ||
01053       (MAX_ALLOC_CHUNK % SIZEOF(ALIGN_TYPE)) != 0)
01054     ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK);
01055 
01056   max_to_use = jpeg_mem_init(cinfo); /* system-dependent initialization */
01057 
01058   /* Attempt to allocate memory manager's control block */
01059   mem = (my_mem_ptr) jpeg_get_small(cinfo, SIZEOF(my_memory_mgr));
01060 
01061   if (mem == NULL) {
01062     jpeg_mem_term(cinfo);   /* system-dependent cleanup */
01063     ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 0);
01064   }
01065 
01066   /* OK, fill in the method pointers */
01067   mem->pub.alloc_small = alloc_small;
01068   mem->pub.alloc_large = alloc_large;
01069   mem->pub.alloc_sarray = alloc_sarray;
01070   mem->pub.alloc_barray = alloc_barray;
01071   mem->pub.request_virt_sarray = request_virt_sarray;
01072   mem->pub.request_virt_barray = request_virt_barray;
01073   mem->pub.realize_virt_arrays = realize_virt_arrays;
01074   mem->pub.access_virt_sarray = access_virt_sarray;
01075   mem->pub.access_virt_barray = access_virt_barray;
01076   mem->pub.free_pool = free_pool;
01077   mem->pub.self_destruct = self_destruct;
01078 
01079   /* Make MAX_ALLOC_CHUNK accessible to other modules */
01080   mem->pub.max_alloc_chunk = MAX_ALLOC_CHUNK;
01081 
01082   /* Initialize working state */
01083   mem->pub.max_memory_to_use = max_to_use;
01084 
01085   for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) {
01086     mem->small_list[pool] = NULL;
01087     mem->large_list[pool] = NULL;
01088   }
01089   mem->virt_sarray_list = NULL;
01090   mem->virt_barray_list = NULL;
01091 
01092   mem->total_space_allocated = SIZEOF(my_memory_mgr);
01093 
01094   /* Declare ourselves open for business */
01095   cinfo->mem = & mem->pub;
01096 
01097   /* Check for an environment variable JPEGMEM; if found, override the
01098    * default max_memory setting from jpeg_mem_init.  Note that the
01099    * surrounding application may again override this value.
01100    * If your system doesn't support getenv(), define NO_GETENV to disable
01101    * this feature.
01102    */
01103 #ifndef NO_GETENV
01104   { char * memenv;
01105 
01106     if ((memenv = getenv("JPEGMEM")) != NULL) {
01107       char ch = 'x';
01108 
01109       if (sscanf(memenv, "%ld%c", &max_to_use, &ch) > 0) {
01110     if (ch == 'm' || ch == 'M')
01111       max_to_use *= 1000L;
01112     mem->pub.max_memory_to_use = max_to_use * 1000L;
01113       }
01114     }
01115   }
01116 #endif
01117 
01118 }