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