jdk
1131 строка · 42.1 Кб
1/*
2* reserved comment block
3* DO NOT REMOVE OR ALTER!
4*/
5/*
6* jmemmgr.c
7*
8* Copyright (C) 1991-1997, Thomas G. Lane.
9* This file is part of the Independent JPEG Group's software.
10* For conditions of distribution and use, see the accompanying README file.
11*
12* This file contains the JPEG system-independent memory management
13* routines. This code is usable across a wide variety of machines; most
14* of the system dependencies have been isolated in a separate file.
15* The major functions provided here are:
16* * pool-based allocation and freeing of memory;
17* * policy decisions about how to divide available memory among the
18* virtual arrays;
19* * control logic for swapping virtual arrays between main memory and
20* backing storage.
21* The separate system-dependent file provides the actual backing-storage
22* access code, and it contains the policy decision about how much total
23* main memory to use.
24* This file is system-dependent in the sense that some of its functions
25* are unnecessary in some systems. For example, if there is enough virtual
26* memory so that backing storage will never be used, much of the virtual
27* array control logic could be removed. (Of course, if you have that much
28* memory then you shouldn't care about a little bit of unused code...)
29*/
30
31#define JPEG_INTERNALS32#define AM_MEMORY_MANAGER /* we define jvirt_Xarray_control structs */33#include "jinclude.h"34#include "jpeglib.h"35#include "jmemsys.h" /* import the system-dependent declarations */36
37#ifndef NO_GETENV38#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare getenv() */39extern char * getenv JPP((const char * name));40#endif41#endif42
43
44/*
45* Some important notes:
46* The allocation routines provided here must never return NULL.
47* They should exit to error_exit if unsuccessful.
48*
49* It's not a good idea to try to merge the sarray and barray routines,
50* even though they are textually almost the same, because samples are
51* usually stored as bytes while coefficients are shorts or ints. Thus,
52* in machines where byte pointers have a different representation from
53* word pointers, the resulting machine code could not be the same.
54*/
55
56
57/*
58* Many machines require storage alignment: longs must start on 4-byte
59* boundaries, doubles on 8-byte boundaries, etc. On such machines, malloc()
60* always returns pointers that are multiples of the worst-case alignment
61* requirement, and we had better do so too.
62* There isn't any really portable way to determine the worst-case alignment
63* requirement. This module assumes that the alignment requirement is
64* multiples of sizeof(ALIGN_TYPE).
65* By default, we define ALIGN_TYPE as double. This is necessary on some
66* workstations (where doubles really do need 8-byte alignment) and will work
67* fine on nearly everything. If your machine has lesser alignment needs,
68* you can save a few bytes by making ALIGN_TYPE smaller.
69* The only place I know of where this will NOT work is certain Macintosh
70* 680x0 compilers that define double as a 10-byte IEEE extended float.
71* Doing 10-byte alignment is counterproductive because longwords won't be
72* aligned well. Put "#define ALIGN_TYPE long" in jconfig.h if you have
73* such a compiler.
74*/
75
76#ifndef ALIGN_TYPE /* so can override from jconfig.h */77#define ALIGN_TYPE double78#endif79
80
81/*
82* We allocate objects from "pools", where each pool is gotten with a single
83* request to jpeg_get_small() or jpeg_get_large(). There is no per-object
84* overhead within a pool, except for alignment padding. Each pool has a
85* header with a link to the next pool of the same class.
86* Small and large pool headers are identical except that the latter's
87* link pointer must be FAR on 80x86 machines.
88* Notice that the "real" header fields are union'ed with a dummy ALIGN_TYPE
89* field. This forces the compiler to make SIZEOF(small_pool_hdr) a multiple
90* of the alignment requirement of ALIGN_TYPE.
91*/
92
93typedef union small_pool_struct * small_pool_ptr;94
95typedef union small_pool_struct {96struct {97small_pool_ptr next; /* next in list of pools */98size_t bytes_used; /* how many bytes already used within pool */99size_t bytes_left; /* bytes still available in this pool */100} hdr;101ALIGN_TYPE dummy; /* included in union to ensure alignment */102} small_pool_hdr;103
104typedef union large_pool_struct FAR * large_pool_ptr;105
106typedef union large_pool_struct {107struct {108large_pool_ptr next; /* next in list of pools */109size_t bytes_used; /* how many bytes already used within pool */110size_t bytes_left; /* bytes still available in this pool */111} hdr;112ALIGN_TYPE dummy; /* included in union to ensure alignment */113} large_pool_hdr;114
115
116/*
117* Here is the full definition of a memory manager object.
118*/
119
120typedef struct {121struct jpeg_memory_mgr pub; /* public fields */122
123/* Each pool identifier (lifetime class) names a linked list of pools. */124small_pool_ptr small_list[JPOOL_NUMPOOLS];125large_pool_ptr large_list[JPOOL_NUMPOOLS];126
127/* Since we only have one lifetime class of virtual arrays, only one128* linked list is necessary (for each datatype). Note that the virtual
129* array control blocks being linked together are actually stored somewhere
130* in the small-pool list.
131*/
132jvirt_sarray_ptr virt_sarray_list;133jvirt_barray_ptr virt_barray_list;134
135/* This counts total space obtained from jpeg_get_small/large */136size_t total_space_allocated;137
138/* alloc_sarray and alloc_barray set this value for use by virtual139* array routines.
140*/
141JDIMENSION last_rowsperchunk; /* from most recent alloc_sarray/barray */142} my_memory_mgr;143
144typedef my_memory_mgr * my_mem_ptr;145
146
147/*
148* The control blocks for virtual arrays.
149* Note that these blocks are allocated in the "small" pool area.
150* System-dependent info for the associated backing store (if any) is hidden
151* inside the backing_store_info struct.
152*/
153
154struct jvirt_sarray_control {155JSAMPARRAY mem_buffer; /* => the in-memory buffer */156JDIMENSION rows_in_array; /* total virtual array height */157JDIMENSION samplesperrow; /* width of array (and of memory buffer) */158JDIMENSION maxaccess; /* max rows accessed by access_virt_sarray */159JDIMENSION rows_in_mem; /* height of memory buffer */160JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */161JDIMENSION cur_start_row; /* first logical row # in the buffer */162JDIMENSION first_undef_row; /* row # of first uninitialized row */163boolean pre_zero; /* pre-zero mode requested? */164boolean dirty; /* do current buffer contents need written? */165boolean b_s_open; /* is backing-store data valid? */166jvirt_sarray_ptr next; /* link to next virtual sarray control block */167backing_store_info b_s_info; /* System-dependent control info */168};169
170struct jvirt_barray_control {171JBLOCKARRAY mem_buffer; /* => the in-memory buffer */172JDIMENSION rows_in_array; /* total virtual array height */173JDIMENSION blocksperrow; /* width of array (and of memory buffer) */174JDIMENSION maxaccess; /* max rows accessed by access_virt_barray */175JDIMENSION rows_in_mem; /* height of memory buffer */176JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */177JDIMENSION cur_start_row; /* first logical row # in the buffer */178JDIMENSION first_undef_row; /* row # of first uninitialized row */179boolean pre_zero; /* pre-zero mode requested? */180boolean dirty; /* do current buffer contents need written? */181boolean b_s_open; /* is backing-store data valid? */182jvirt_barray_ptr next; /* link to next virtual barray control block */183backing_store_info b_s_info; /* System-dependent control info */184};185
186
187#ifdef MEM_STATS /* optional extra stuff for statistics */188
189LOCAL(void)190print_mem_stats (j_common_ptr cinfo, int pool_id)191{
192my_mem_ptr mem = (my_mem_ptr) cinfo->mem;193small_pool_ptr shdr_ptr;194large_pool_ptr lhdr_ptr;195
196/* Since this is only a debugging stub, we can cheat a little by using197* fprintf directly rather than going through the trace message code.
198* This is helpful because message parm array can't handle longs.
199*/
200fprintf(stderr, "Freeing pool %d, total space = %ld\n",201pool_id, mem->total_space_allocated);202
203for (lhdr_ptr = mem->large_list[pool_id]; lhdr_ptr != NULL;204lhdr_ptr = lhdr_ptr->hdr.next) {205fprintf(stderr, " Large chunk used %ld\n",206(long) lhdr_ptr->hdr.bytes_used);207}208
209for (shdr_ptr = mem->small_list[pool_id]; shdr_ptr != NULL;210shdr_ptr = shdr_ptr->hdr.next) {211fprintf(stderr, " Small chunk used %ld free %ld\n",212(long) shdr_ptr->hdr.bytes_used,213(long) shdr_ptr->hdr.bytes_left);214}215}
216
217#endif /* MEM_STATS */218
219
220LOCAL(void)221out_of_memory (j_common_ptr cinfo, int which)222/* Report an out-of-memory error and stop execution */
223/* If we compiled MEM_STATS support, report alloc requests before dying */
224{
225#ifdef MEM_STATS226cinfo->err->trace_level = 2; /* force self_destruct to report stats */227#endif228ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, which);229}
230
231
232/*
233* Allocation of "small" objects.
234*
235* For these, we use pooled storage. When a new pool must be created,
236* we try to get enough space for the current request plus a "slop" factor,
237* where the slop will be the amount of leftover space in the new pool.
238* The speed vs. space tradeoff is largely determined by the slop values.
239* A different slop value is provided for each pool class (lifetime),
240* and we also distinguish the first pool of a class from later ones.
241* NOTE: the values given work fairly well on both 16- and 32-bit-int
242* machines, but may be too small if longs are 64 bits or more.
243*/
244
245static const size_t first_pool_slop[JPOOL_NUMPOOLS] =246{
2471600, /* first PERMANENT pool */24816000 /* first IMAGE pool */249};250
251static const size_t extra_pool_slop[JPOOL_NUMPOOLS] =252{
2530, /* additional PERMANENT pools */2545000 /* additional IMAGE pools */255};256
257#define MIN_SLOP 50 /* greater than 0 to avoid futile looping */258
259
260METHODDEF(void *)261alloc_small (j_common_ptr cinfo, int pool_id, size_t sizeofobject)262/* Allocate a "small" object */
263{
264my_mem_ptr mem = (my_mem_ptr) cinfo->mem;265small_pool_ptr hdr_ptr, prev_hdr_ptr;266char * data_ptr;267size_t odd_bytes, min_request, slop;268
269/* Check for unsatisfiable request (do now to ensure no overflow below) */270if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(small_pool_hdr)))271out_of_memory(cinfo, 1); /* request exceeds malloc's ability */272
273/* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */274odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE);275if (odd_bytes > 0)276sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes;277
278/* See if space is available in any existing pool */279if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS)280ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */281prev_hdr_ptr = NULL;282hdr_ptr = mem->small_list[pool_id];283while (hdr_ptr != NULL) {284if (hdr_ptr->hdr.bytes_left >= sizeofobject)285break; /* found pool with enough space */286prev_hdr_ptr = hdr_ptr;287hdr_ptr = hdr_ptr->hdr.next;288}289
290/* Time to make a new pool? */291if (hdr_ptr == NULL) {292/* min_request is what we need now, slop is what will be leftover */293min_request = sizeofobject + SIZEOF(small_pool_hdr);294if (prev_hdr_ptr == NULL) /* first pool in class? */295slop = first_pool_slop[pool_id];296else297slop = extra_pool_slop[pool_id];298/* Don't ask for more than MAX_ALLOC_CHUNK */299if (slop > (size_t) (MAX_ALLOC_CHUNK-min_request))300slop = (size_t) (MAX_ALLOC_CHUNK-min_request);301/* Try to get space, if fail reduce slop and try again */302for (;;) {303hdr_ptr = (small_pool_ptr) jpeg_get_small(cinfo, min_request + slop);304if (hdr_ptr != NULL)305break;306slop /= 2;307if (slop < MIN_SLOP) /* give up when it gets real small */308out_of_memory(cinfo, 2); /* jpeg_get_small failed */309}310mem->total_space_allocated += min_request + slop;311/* Success, initialize the new pool header and add to end of list */312hdr_ptr->hdr.next = NULL;313hdr_ptr->hdr.bytes_used = 0;314hdr_ptr->hdr.bytes_left = sizeofobject + slop;315if (prev_hdr_ptr == NULL) /* first pool in class? */316mem->small_list[pool_id] = hdr_ptr;317else318prev_hdr_ptr->hdr.next = hdr_ptr;319}320
321/* OK, allocate the object from the current pool */322data_ptr = (char *) (hdr_ptr + 1); /* point to first data byte in pool */323data_ptr += hdr_ptr->hdr.bytes_used; /* point to place for object */324hdr_ptr->hdr.bytes_used += sizeofobject;325hdr_ptr->hdr.bytes_left -= sizeofobject;326
327return (void *) data_ptr;328}
329
330
331/*
332* Allocation of "large" objects.
333*
334* The external semantics of these are the same as "small" objects,
335* except that FAR pointers are used on 80x86. However the pool
336* management heuristics are quite different. We assume that each
337* request is large enough that it may as well be passed directly to
338* jpeg_get_large; the pool management just links everything together
339* so that we can free it all on demand.
340* Note: the major use of "large" objects is in JSAMPARRAY and JBLOCKARRAY
341* structures. The routines that create these structures (see below)
342* deliberately bunch rows together to ensure a large request size.
343*/
344
345METHODDEF(void FAR *)346alloc_large (j_common_ptr cinfo, int pool_id, size_t sizeofobject)347/* Allocate a "large" object */
348{
349my_mem_ptr mem = (my_mem_ptr) cinfo->mem;350large_pool_ptr hdr_ptr;351size_t odd_bytes;352
353/* Check for unsatisfiable request (do now to ensure no overflow below) */354if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)))355out_of_memory(cinfo, 3); /* request exceeds malloc's ability */356
357/* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */358odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE);359if (odd_bytes > 0)360sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes;361
362/* Always make a new pool */363if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS)364ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */365
366hdr_ptr = (large_pool_ptr) jpeg_get_large(cinfo, sizeofobject +367SIZEOF(large_pool_hdr));368if (hdr_ptr == NULL)369out_of_memory(cinfo, 4); /* jpeg_get_large failed */370mem->total_space_allocated += sizeofobject + SIZEOF(large_pool_hdr);371
372/* Success, initialize the new pool header and add to list */373hdr_ptr->hdr.next = mem->large_list[pool_id];374/* We maintain space counts in each pool header for statistical purposes,375* even though they are not needed for allocation.
376*/
377hdr_ptr->hdr.bytes_used = sizeofobject;378hdr_ptr->hdr.bytes_left = 0;379mem->large_list[pool_id] = hdr_ptr;380
381return (void FAR *) (hdr_ptr + 1); /* point to first data byte in pool */382}
383
384
385/*
386* Creation of 2-D sample arrays.
387* The pointers are in near heap, the samples themselves in FAR heap.
388*
389* To minimize allocation overhead and to allow I/O of large contiguous
390* blocks, we allocate the sample rows in groups of as many rows as possible
391* without exceeding MAX_ALLOC_CHUNK total bytes per allocation request.
392* NB: the virtual array control routines, later in this file, know about
393* this chunking of rows. The rowsperchunk value is left in the mem manager
394* object so that it can be saved away if this sarray is the workspace for
395* a virtual array.
396*/
397
398METHODDEF(JSAMPARRAY)399alloc_sarray (j_common_ptr cinfo, int pool_id,400JDIMENSION samplesperrow, JDIMENSION numrows)401/* Allocate a 2-D sample array */
402{
403my_mem_ptr mem = (my_mem_ptr) cinfo->mem;404JSAMPARRAY result;405JSAMPROW workspace;406JDIMENSION rowsperchunk, currow, i;407long ltemp;408
409if (samplesperrow == 0) {410ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);411}412/* Calculate max # of rows allowed in one allocation chunk */413ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) /414((long) samplesperrow * SIZEOF(JSAMPLE));415if (ltemp <= 0)416ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);417if (ltemp < (long) numrows)418rowsperchunk = (JDIMENSION) ltemp;419else420rowsperchunk = numrows;421mem->last_rowsperchunk = rowsperchunk;422
423/* Get space for row pointers (small object) */424result = (JSAMPARRAY) alloc_small(cinfo, pool_id,425(size_t) (numrows * SIZEOF(JSAMPROW)));426
427/* Get the rows themselves (large objects) */428currow = 0;429while (currow < numrows) {430rowsperchunk = MIN(rowsperchunk, numrows - currow);431workspace = (JSAMPROW) alloc_large(cinfo, pool_id,432(size_t) ((size_t) rowsperchunk * (size_t) samplesperrow433* SIZEOF(JSAMPLE)));434for (i = rowsperchunk; i > 0; i--) {435result[currow++] = workspace;436workspace += samplesperrow;437}438}439
440return result;441}
442
443
444/*
445* Creation of 2-D coefficient-block arrays.
446* This is essentially the same as the code for sample arrays, above.
447*/
448
449METHODDEF(JBLOCKARRAY)450alloc_barray (j_common_ptr cinfo, int pool_id,451JDIMENSION blocksperrow, JDIMENSION numrows)452/* Allocate a 2-D coefficient-block array */
453{
454my_mem_ptr mem = (my_mem_ptr) cinfo->mem;455JBLOCKARRAY result;456JBLOCKROW workspace;457JDIMENSION rowsperchunk, currow, i;458long ltemp;459
460if (blocksperrow == 0) {461ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);462}463
464/* Calculate max # of rows allowed in one allocation chunk */465ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) /466((long) blocksperrow * SIZEOF(JBLOCK));467if (ltemp <= 0)468ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);469if (ltemp < (long) numrows)470rowsperchunk = (JDIMENSION) ltemp;471else472rowsperchunk = numrows;473mem->last_rowsperchunk = rowsperchunk;474
475/* Get space for row pointers (small object) */476result = (JBLOCKARRAY) alloc_small(cinfo, pool_id,477(size_t) (numrows * SIZEOF(JBLOCKROW)));478
479/* Get the rows themselves (large objects) */480currow = 0;481while (currow < numrows) {482rowsperchunk = MIN(rowsperchunk, numrows - currow);483workspace = (JBLOCKROW) alloc_large(cinfo, pool_id,484(size_t) ((size_t) rowsperchunk * (size_t) blocksperrow485* SIZEOF(JBLOCK)));486for (i = rowsperchunk; i > 0; i--) {487result[currow++] = workspace;488workspace += blocksperrow;489}490}491
492return result;493}
494
495
496/*
497* About virtual array management:
498*
499* The above "normal" array routines are only used to allocate strip buffers
500* (as wide as the image, but just a few rows high). Full-image-sized buffers
501* are handled as "virtual" arrays. The array is still accessed a strip at a
502* time, but the memory manager must save the whole array for repeated
503* accesses. The intended implementation is that there is a strip buffer in
504* memory (as high as is possible given the desired memory limit), plus a
505* backing file that holds the rest of the array.
506*
507* The request_virt_array routines are told the total size of the image and
508* the maximum number of rows that will be accessed at once. The in-memory
509* buffer must be at least as large as the maxaccess value.
510*
511* The request routines create control blocks but not the in-memory buffers.
512* That is postponed until realize_virt_arrays is called. At that time the
513* total amount of space needed is known (approximately, anyway), so free
514* memory can be divided up fairly.
515*
516* The access_virt_array routines are responsible for making a specific strip
517* area accessible (after reading or writing the backing file, if necessary).
518* Note that the access routines are told whether the caller intends to modify
519* the accessed strip; during a read-only pass this saves having to rewrite
520* data to disk. The access routines are also responsible for pre-zeroing
521* any newly accessed rows, if pre-zeroing was requested.
522*
523* In current usage, the access requests are usually for nonoverlapping
524* strips; that is, successive access start_row numbers differ by exactly
525* num_rows = maxaccess. This means we can get good performance with simple
526* buffer dump/reload logic, by making the in-memory buffer be a multiple
527* of the access height; then there will never be accesses across bufferload
528* boundaries. The code will still work with overlapping access requests,
529* but it doesn't handle bufferload overlaps very efficiently.
530*/
531
532
533METHODDEF(jvirt_sarray_ptr)534request_virt_sarray (j_common_ptr cinfo, int pool_id, boolean pre_zero,535JDIMENSION samplesperrow, JDIMENSION numrows,536JDIMENSION maxaccess)537/* Request a virtual 2-D sample array */
538{
539my_mem_ptr mem = (my_mem_ptr) cinfo->mem;540jvirt_sarray_ptr result;541
542/* Only IMAGE-lifetime virtual arrays are currently supported */543if (pool_id != JPOOL_IMAGE)544ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */545
546/* get control block */547result = (jvirt_sarray_ptr) alloc_small(cinfo, pool_id,548SIZEOF(struct jvirt_sarray_control));549
550result->mem_buffer = NULL; /* marks array not yet realized */551result->rows_in_array = numrows;552result->samplesperrow = samplesperrow;553result->maxaccess = maxaccess;554result->pre_zero = pre_zero;555result->b_s_open = FALSE; /* no associated backing-store object */556result->next = mem->virt_sarray_list; /* add to list of virtual arrays */557mem->virt_sarray_list = result;558
559return result;560}
561
562
563METHODDEF(jvirt_barray_ptr)564request_virt_barray (j_common_ptr cinfo, int pool_id, boolean pre_zero,565JDIMENSION blocksperrow, JDIMENSION numrows,566JDIMENSION maxaccess)567/* Request a virtual 2-D coefficient-block array */
568{
569my_mem_ptr mem = (my_mem_ptr) cinfo->mem;570jvirt_barray_ptr result;571
572/* Only IMAGE-lifetime virtual arrays are currently supported */573if (pool_id != JPOOL_IMAGE)574ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */575
576/* get control block */577result = (jvirt_barray_ptr) alloc_small(cinfo, pool_id,578SIZEOF(struct jvirt_barray_control));579
580result->mem_buffer = NULL; /* marks array not yet realized */581result->rows_in_array = numrows;582result->blocksperrow = blocksperrow;583result->maxaccess = maxaccess;584result->pre_zero = pre_zero;585result->b_s_open = FALSE; /* no associated backing-store object */586result->next = mem->virt_barray_list; /* add to list of virtual arrays */587mem->virt_barray_list = result;588
589return result;590}
591
592
593METHODDEF(void)594realize_virt_arrays (j_common_ptr cinfo)595/* Allocate the in-memory buffers for any unrealized virtual arrays */
596{
597my_mem_ptr mem = (my_mem_ptr) cinfo->mem;598size_t space_per_minheight, maximum_space, avail_mem;599size_t minheights, max_minheights;600jvirt_sarray_ptr sptr;601jvirt_barray_ptr bptr;602
603/* Compute the minimum space needed (maxaccess rows in each buffer)604* and the maximum space needed (full image height in each buffer).
605* These may be of use to the system-dependent jpeg_mem_available routine.
606*/
607space_per_minheight = 0;608maximum_space = 0;609for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {610if (sptr->mem_buffer == NULL) { /* if not realized yet */611space_per_minheight += (long) sptr->maxaccess *612(long) sptr->samplesperrow * SIZEOF(JSAMPLE);613maximum_space += (long) sptr->rows_in_array *614(long) sptr->samplesperrow * SIZEOF(JSAMPLE);615}616}617for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) {618if (bptr->mem_buffer == NULL) { /* if not realized yet */619space_per_minheight += (long) bptr->maxaccess *620(long) bptr->blocksperrow * SIZEOF(JBLOCK);621maximum_space += (long) bptr->rows_in_array *622(long) bptr->blocksperrow * SIZEOF(JBLOCK);623}624}625
626if (space_per_minheight <= 0)627return; /* no unrealized arrays, no work */628
629/* Determine amount of memory to actually use; this is system-dependent. */630avail_mem = jpeg_mem_available(cinfo, space_per_minheight, maximum_space,631mem->total_space_allocated);632
633/* If the maximum space needed is available, make all the buffers full634* height; otherwise parcel it out with the same number of minheights
635* in each buffer.
636*/
637if (avail_mem >= maximum_space)638max_minheights = 1000000000L;639else {640max_minheights = avail_mem / space_per_minheight;641/* If there doesn't seem to be enough space, try to get the minimum642* anyway. This allows a "stub" implementation of jpeg_mem_available().
643*/
644if (max_minheights <= 0)645max_minheights = 1;646}647
648/* Allocate the in-memory buffers and initialize backing store as needed. */649
650for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {651if (sptr->mem_buffer == NULL) { /* if not realized yet */652minheights = ((long) sptr->rows_in_array - 1L) / sptr->maxaccess + 1L;653if (minheights <= max_minheights) {654/* This buffer fits in memory */655sptr->rows_in_mem = sptr->rows_in_array;656} else {657/* It doesn't fit in memory, create backing store. */658sptr->rows_in_mem = (JDIMENSION) (max_minheights * sptr->maxaccess);659jpeg_open_backing_store(cinfo, & sptr->b_s_info,660(long) sptr->rows_in_array *661(long) sptr->samplesperrow *662(long) SIZEOF(JSAMPLE));663sptr->b_s_open = TRUE;664}665sptr->mem_buffer = alloc_sarray(cinfo, JPOOL_IMAGE,666sptr->samplesperrow, sptr->rows_in_mem);667sptr->rowsperchunk = mem->last_rowsperchunk;668sptr->cur_start_row = 0;669sptr->first_undef_row = 0;670sptr->dirty = FALSE;671}672}673
674for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) {675if (bptr->mem_buffer == NULL) { /* if not realized yet */676minheights = ((long) bptr->rows_in_array - 1L) / bptr->maxaccess + 1L;677if (minheights <= max_minheights) {678/* This buffer fits in memory */679bptr->rows_in_mem = bptr->rows_in_array;680} else {681/* It doesn't fit in memory, create backing store. */682bptr->rows_in_mem = (JDIMENSION) (max_minheights * bptr->maxaccess);683jpeg_open_backing_store(cinfo, & bptr->b_s_info,684(long) bptr->rows_in_array *685(long) bptr->blocksperrow *686(long) SIZEOF(JBLOCK));687bptr->b_s_open = TRUE;688}689bptr->mem_buffer = alloc_barray(cinfo, JPOOL_IMAGE,690bptr->blocksperrow, bptr->rows_in_mem);691bptr->rowsperchunk = mem->last_rowsperchunk;692bptr->cur_start_row = 0;693bptr->first_undef_row = 0;694bptr->dirty = FALSE;695}696}697}
698
699
700LOCAL(void)701do_sarray_io (j_common_ptr cinfo, jvirt_sarray_ptr ptr, boolean writing)702/* Do backing store read or write of a virtual sample array */
703{
704long bytesperrow, file_offset, byte_count, rows, thisrow, i;705
706bytesperrow = (long) ptr->samplesperrow * SIZEOF(JSAMPLE);707file_offset = ptr->cur_start_row * bytesperrow;708/* Loop to read or write each allocation chunk in mem_buffer */709for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) {710/* One chunk, but check for short chunk at end of buffer */711rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i);712/* Transfer no more than is currently defined */713thisrow = (long) ptr->cur_start_row + i;714rows = MIN(rows, (long) ptr->first_undef_row - thisrow);715/* Transfer no more than fits in file */716rows = MIN(rows, (long) ptr->rows_in_array - thisrow);717if (rows <= 0) /* this chunk might be past end of file! */718break;719byte_count = rows * bytesperrow;720if (writing)721(*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info,722(void FAR *) ptr->mem_buffer[i],723file_offset, byte_count);724else725(*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info,726(void FAR *) ptr->mem_buffer[i],727file_offset, byte_count);728file_offset += byte_count;729}730}
731
732
733LOCAL(void)734do_barray_io (j_common_ptr cinfo, jvirt_barray_ptr ptr, boolean writing)735/* Do backing store read or write of a virtual coefficient-block array */
736{
737long bytesperrow, file_offset, byte_count, rows, thisrow, i;738
739bytesperrow = (long) ptr->blocksperrow * SIZEOF(JBLOCK);740file_offset = ptr->cur_start_row * bytesperrow;741/* Loop to read or write each allocation chunk in mem_buffer */742for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) {743/* One chunk, but check for short chunk at end of buffer */744rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i);745/* Transfer no more than is currently defined */746thisrow = (long) ptr->cur_start_row + i;747rows = MIN(rows, (long) ptr->first_undef_row - thisrow);748/* Transfer no more than fits in file */749rows = MIN(rows, (long) ptr->rows_in_array - thisrow);750if (rows <= 0) /* this chunk might be past end of file! */751break;752byte_count = rows * bytesperrow;753if (writing)754(*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info,755(void FAR *) ptr->mem_buffer[i],756file_offset, byte_count);757else758(*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info,759(void FAR *) ptr->mem_buffer[i],760file_offset, byte_count);761file_offset += byte_count;762}763}
764
765
766METHODDEF(JSAMPARRAY)767access_virt_sarray (j_common_ptr cinfo, jvirt_sarray_ptr ptr,768JDIMENSION start_row, JDIMENSION num_rows,769boolean writable)770/* Access the part of a virtual sample array starting at start_row */
771/* and extending for num_rows rows. writable is true if */
772/* caller intends to modify the accessed area. */
773{
774JDIMENSION end_row = start_row + num_rows;775JDIMENSION undef_row;776
777/* debugging check */778if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess ||779ptr->mem_buffer == NULL)780ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);781
782/* Make the desired part of the virtual array accessible */783if (start_row < ptr->cur_start_row ||784end_row > ptr->cur_start_row+ptr->rows_in_mem) {785if (! ptr->b_s_open)786ERREXIT(cinfo, JERR_VIRTUAL_BUG);787/* Flush old buffer contents if necessary */788if (ptr->dirty) {789do_sarray_io(cinfo, ptr, TRUE);790ptr->dirty = FALSE;791}792/* Decide what part of virtual array to access.793* Algorithm: if target address > current window, assume forward scan,
794* load starting at target address. If target address < current window,
795* assume backward scan, load so that target area is top of window.
796* Note that when switching from forward write to forward read, will have
797* start_row = 0, so the limiting case applies and we load from 0 anyway.
798*/
799if (start_row > ptr->cur_start_row) {800ptr->cur_start_row = start_row;801} else {802/* use long arithmetic here to avoid overflow & unsigned problems */803long ltemp;804
805ltemp = (long) end_row - (long) ptr->rows_in_mem;806if (ltemp < 0)807ltemp = 0; /* don't fall off front end of file */808ptr->cur_start_row = (JDIMENSION) ltemp;809}810/* Read in the selected part of the array.811* During the initial write pass, we will do no actual read
812* because the selected part is all undefined.
813*/
814do_sarray_io(cinfo, ptr, FALSE);815}816/* Ensure the accessed part of the array is defined; prezero if needed.817* To improve locality of access, we only prezero the part of the array
818* that the caller is about to access, not the entire in-memory array.
819*/
820if (ptr->first_undef_row < end_row) {821if (ptr->first_undef_row < start_row) {822if (writable) /* writer skipped over a section of array */823ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);824undef_row = start_row; /* but reader is allowed to read ahead */825} else {826undef_row = ptr->first_undef_row;827}828if (writable)829ptr->first_undef_row = end_row;830if (ptr->pre_zero) {831size_t bytesperrow = (size_t) ptr->samplesperrow * SIZEOF(JSAMPLE);832undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */833end_row -= ptr->cur_start_row;834while (undef_row < end_row) {835jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow);836undef_row++;837}838} else {839if (! writable) /* reader looking at undefined data */840ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);841}842}843/* Flag the buffer dirty if caller will write in it */844if (writable)845ptr->dirty = TRUE;846/* Return address of proper part of the buffer */847return ptr->mem_buffer + (start_row - ptr->cur_start_row);848}
849
850
851METHODDEF(JBLOCKARRAY)852access_virt_barray (j_common_ptr cinfo, jvirt_barray_ptr ptr,853JDIMENSION start_row, JDIMENSION num_rows,854boolean writable)855/* Access the part of a virtual block array starting at start_row */
856/* and extending for num_rows rows. writable is true if */
857/* caller intends to modify the accessed area. */
858{
859JDIMENSION end_row = start_row + num_rows;860JDIMENSION undef_row;861
862/* debugging check */863if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess ||864ptr->mem_buffer == NULL)865ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);866
867/* Make the desired part of the virtual array accessible */868if (start_row < ptr->cur_start_row ||869end_row > ptr->cur_start_row+ptr->rows_in_mem) {870if (! ptr->b_s_open)871ERREXIT(cinfo, JERR_VIRTUAL_BUG);872/* Flush old buffer contents if necessary */873if (ptr->dirty) {874do_barray_io(cinfo, ptr, TRUE);875ptr->dirty = FALSE;876}877/* Decide what part of virtual array to access.878* Algorithm: if target address > current window, assume forward scan,
879* load starting at target address. If target address < current window,
880* assume backward scan, load so that target area is top of window.
881* Note that when switching from forward write to forward read, will have
882* start_row = 0, so the limiting case applies and we load from 0 anyway.
883*/
884if (start_row > ptr->cur_start_row) {885ptr->cur_start_row = start_row;886} else {887/* use long arithmetic here to avoid overflow & unsigned problems */888long ltemp;889
890ltemp = (long) end_row - (long) ptr->rows_in_mem;891if (ltemp < 0)892ltemp = 0; /* don't fall off front end of file */893ptr->cur_start_row = (JDIMENSION) ltemp;894}895/* Read in the selected part of the array.896* During the initial write pass, we will do no actual read
897* because the selected part is all undefined.
898*/
899do_barray_io(cinfo, ptr, FALSE);900}901/* Ensure the accessed part of the array is defined; prezero if needed.902* To improve locality of access, we only prezero the part of the array
903* that the caller is about to access, not the entire in-memory array.
904*/
905if (ptr->first_undef_row < end_row) {906if (ptr->first_undef_row < start_row) {907if (writable) /* writer skipped over a section of array */908ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);909undef_row = start_row; /* but reader is allowed to read ahead */910} else {911undef_row = ptr->first_undef_row;912}913if (writable)914ptr->first_undef_row = end_row;915if (ptr->pre_zero) {916size_t bytesperrow = (size_t) ptr->blocksperrow * SIZEOF(JBLOCK);917undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */918end_row -= ptr->cur_start_row;919while (undef_row < end_row) {920jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow);921undef_row++;922}923} else {924if (! writable) /* reader looking at undefined data */925ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);926}927}928/* Flag the buffer dirty if caller will write in it */929if (writable)930ptr->dirty = TRUE;931/* Return address of proper part of the buffer */932return ptr->mem_buffer + (start_row - ptr->cur_start_row);933}
934
935
936/*
937* Release all objects belonging to a specified pool.
938*/
939
940METHODDEF(void)941free_pool (j_common_ptr cinfo, int pool_id)942{
943my_mem_ptr mem = (my_mem_ptr) cinfo->mem;944small_pool_ptr shdr_ptr;945large_pool_ptr lhdr_ptr;946size_t space_freed;947
948if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS)949ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */950
951#ifdef MEM_STATS952if (cinfo->err->trace_level > 1)953print_mem_stats(cinfo, pool_id); /* print pool's memory usage statistics */954#endif955
956/* If freeing IMAGE pool, close any virtual arrays first */957if (pool_id == JPOOL_IMAGE) {958jvirt_sarray_ptr sptr;959jvirt_barray_ptr bptr;960
961for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {962if (sptr->b_s_open) { /* there may be no backing store */963sptr->b_s_open = FALSE; /* prevent recursive close if error */964(*sptr->b_s_info.close_backing_store) (cinfo, & sptr->b_s_info);965}966}967mem->virt_sarray_list = NULL;968for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) {969if (bptr->b_s_open) { /* there may be no backing store */970bptr->b_s_open = FALSE; /* prevent recursive close if error */971(*bptr->b_s_info.close_backing_store) (cinfo, & bptr->b_s_info);972}973}974mem->virt_barray_list = NULL;975}976
977/* Release large objects */978lhdr_ptr = mem->large_list[pool_id];979mem->large_list[pool_id] = NULL;980
981while (lhdr_ptr != NULL) {982large_pool_ptr next_lhdr_ptr = lhdr_ptr->hdr.next;983space_freed = lhdr_ptr->hdr.bytes_used +984lhdr_ptr->hdr.bytes_left +985SIZEOF(large_pool_hdr);986jpeg_free_large(cinfo, (void FAR *) lhdr_ptr, space_freed);987mem->total_space_allocated -= space_freed;988lhdr_ptr = next_lhdr_ptr;989}990
991/* Release small objects */992shdr_ptr = mem->small_list[pool_id];993mem->small_list[pool_id] = NULL;994
995while (shdr_ptr != NULL) {996small_pool_ptr next_shdr_ptr = shdr_ptr->hdr.next;997space_freed = shdr_ptr->hdr.bytes_used +998shdr_ptr->hdr.bytes_left +999SIZEOF(small_pool_hdr);1000jpeg_free_small(cinfo, (void *) shdr_ptr, space_freed);1001mem->total_space_allocated -= space_freed;1002shdr_ptr = next_shdr_ptr;1003}1004}
1005
1006
1007/*
1008* Close up shop entirely.
1009* Note that this cannot be called unless cinfo->mem is non-NULL.
1010*/
1011
1012METHODDEF(void)1013self_destruct (j_common_ptr cinfo)1014{
1015int pool;1016
1017/* Close all backing store, release all memory.1018* Releasing pools in reverse order might help avoid fragmentation
1019* with some (brain-damaged) malloc libraries.
1020*/
1021for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) {1022free_pool(cinfo, pool);1023}1024
1025/* Release the memory manager control block too. */1026jpeg_free_small(cinfo, (void *) cinfo->mem, SIZEOF(my_memory_mgr));1027cinfo->mem = NULL; /* ensures I will be called only once */1028
1029jpeg_mem_term(cinfo); /* system-dependent cleanup */1030}
1031
1032
1033/*
1034* Memory manager initialization.
1035* When this is called, only the error manager pointer is valid in cinfo!
1036*/
1037
1038GLOBAL(void)1039jinit_memory_mgr (j_common_ptr cinfo)1040{
1041my_mem_ptr mem;1042size_t max_to_use;1043int pool;1044size_t test_mac;1045
1046cinfo->mem = NULL; /* for safety if init fails */1047
1048/* Check for configuration errors.1049* SIZEOF(ALIGN_TYPE) should be a power of 2; otherwise, it probably
1050* doesn't reflect any real hardware alignment requirement.
1051* The test is a little tricky: for X>0, X and X-1 have no one-bits
1052* in common if and only if X is a power of 2, ie has only one one-bit.
1053* Some compilers may give an "unreachable code" warning here; ignore it.
1054*/
1055if ((SIZEOF(ALIGN_TYPE) & (SIZEOF(ALIGN_TYPE)-1)) != 0)1056ERREXIT(cinfo, JERR_BAD_ALIGN_TYPE);1057/* MAX_ALLOC_CHUNK must be representable as type size_t, and must be1058* a multiple of SIZEOF(ALIGN_TYPE).
1059* Again, an "unreachable code" warning may be ignored here.
1060* But a "constant too large" warning means you need to fix MAX_ALLOC_CHUNK.
1061*/
1062test_mac = (size_t) MAX_ALLOC_CHUNK;1063if ((long) test_mac != MAX_ALLOC_CHUNK ||1064(MAX_ALLOC_CHUNK % SIZEOF(ALIGN_TYPE)) != 0)1065ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK);1066
1067max_to_use = jpeg_mem_init(cinfo); /* system-dependent initialization */1068
1069/* Attempt to allocate memory manager's control block */1070mem = (my_mem_ptr) jpeg_get_small(cinfo, SIZEOF(my_memory_mgr));1071
1072if (mem == NULL) {1073jpeg_mem_term(cinfo); /* system-dependent cleanup */1074ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 0);1075}1076
1077/* OK, fill in the method pointers */1078mem->pub.alloc_small = alloc_small;1079mem->pub.alloc_large = alloc_large;1080mem->pub.alloc_sarray = alloc_sarray;1081mem->pub.alloc_barray = alloc_barray;1082mem->pub.request_virt_sarray = request_virt_sarray;1083mem->pub.request_virt_barray = request_virt_barray;1084mem->pub.realize_virt_arrays = realize_virt_arrays;1085mem->pub.access_virt_sarray = access_virt_sarray;1086mem->pub.access_virt_barray = access_virt_barray;1087mem->pub.free_pool = free_pool;1088mem->pub.self_destruct = self_destruct;1089
1090/* Make MAX_ALLOC_CHUNK accessible to other modules */1091mem->pub.max_alloc_chunk = MAX_ALLOC_CHUNK;1092
1093/* Initialize working state */1094mem->pub.max_memory_to_use = max_to_use;1095
1096for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) {1097mem->small_list[pool] = NULL;1098mem->large_list[pool] = NULL;1099}1100mem->virt_sarray_list = NULL;1101mem->virt_barray_list = NULL;1102
1103mem->total_space_allocated = SIZEOF(my_memory_mgr);1104
1105/* Declare ourselves open for business */1106cinfo->mem = & mem->pub;1107
1108/* Check for an environment variable JPEGMEM; if found, override the1109* default max_memory setting from jpeg_mem_init. Note that the
1110* surrounding application may again override this value.
1111* If your system doesn't support getenv(), define NO_GETENV to disable
1112* this feature.
1113*/
1114#ifndef NO_GETENV1115{ char * memenv;1116
1117if ((memenv = getenv("JPEGMEM")) != NULL) {1118char ch = 'x';1119unsigned int mem_max = 0u;1120
1121if (sscanf(memenv, "%u%c", &mem_max, &ch) > 0) {1122max_to_use = (size_t)mem_max;1123if (ch == 'm' || ch == 'M')1124max_to_use *= 1000L;1125mem->pub.max_memory_to_use = max_to_use * 1000L;1126}1127}1128}1129#endif1130
1131}
1132