~ubuntu-branches/debian/squeeze/ghostscript/squeeze

« back to all changes in this revision

Viewing changes to src/gxclmem.c

  • Committer: Bazaar Package Importer
  • Author(s): Masayuki Hatta (mhatta)
  • Date: 2009-01-04 12:09:59 UTC
  • mfrom: (16.1.1 sid)
  • Revision ID: james.westby@ubuntu.com-20090104120959-m9lbagj775ucg0h3
Tags: 8.63.dfsg.1-2
libgs-dev: put versioned dependency on libgs8 - closes: #510691

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
   San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
12
12
*/
13
13
 
14
 
/* $Id: gxclmem.c 8488 2008-01-17 13:37:19Z leonardo $ */
 
14
/* $Id: gxclmem.c 8721 2008-05-09 02:18:14Z ray $ */
15
15
/* RAM-based command list implementation */
16
16
#include "memory_.h"
17
17
#include "gx.h"
131
131
   least as large as the fixed overhead of the compressor plus the
132
132
   decompressor, plus the expected compressed size of a block that size.
133
133
 */
134
 
static const long COMPRESSION_THRESHOLD = 32000000;
 
134
static const long COMPRESSION_THRESHOLD = 500000000;    /* 0.5 Gb for host machines */
135
135
 
136
136
#define NEED_TO_COMPRESS(f)\
137
137
  ((f)->ok_to_compress && (f)->total_space > COMPRESSION_THRESHOLD)
138
138
 
139
 
   /* FOR NOW ALLOCATE 1 raw buffer for every 32 blocks (at least 8)    */
140
 
#define GET_NUM_RAW_BUFFERS( f )                                        \
141
 
         max(f->log_length/MEMFILE_DATA_SIZE/32, 8)
 
139
   /* FOR NOW ALLOCATE 1 raw buffer for every 32 blocks (at least 8, no more than 64)    */
 
140
#define GET_NUM_RAW_BUFFERS( f ) \
 
141
         min(64, max(f->log_length/MEMFILE_DATA_SIZE/32, 8))
142
142
 
143
143
#define MALLOC(f, siz, cname)\
144
144
  (void *)gs_alloc_bytes((f)->data_memory, siz, cname)
154
154
static int memfile_init_empty(MEMFILE * f);
155
155
static int memfile_set_memory_warning(clist_file_ptr cf, int bytes_left);
156
156
static int memfile_fclose(clist_file_ptr cf, const char *fname, bool delete);
 
157
static int memfile_get_pdata(MEMFILE * f);
157
158
 
158
159
/************************************************/
159
160
/*   #define DEBUG      /- force statistics -/  */
225
226
              clist_file_ptr /*MEMFILE * */  * pf,
226
227
              gs_memory_t *mem, gs_memory_t *data_mem, bool ok_to_compress)
227
228
{
228
 
    MEMFILE *f = 0;
 
229
    MEMFILE *f = NULL;
229
230
    int code = 0;
230
231
 
231
 
    /* We don't implement reopening an existing file. */
232
 
    if (fname[0] != 0 || fmode[0] != 'w') {
233
 
        code = gs_note_error(gs_error_invalidfileaccess);
234
 
        goto finish;
 
232
    *pf = NULL;         /* in case we have an error */
 
233
 
 
234
    /* fname[0] == 0 if this is not reopening */
 
235
    /* memfile file names begin with a flag byte == 0xff */
 
236
    if (fname[0] == '\377' || fmode[0] == 'r') {
 
237
        MEMFILE *base_f = NULL;
 
238
 
 
239
        /* reopening an existing file. */
 
240
        code = sscanf(fname+1, "0x%x", &base_f);
 
241
        if (code != 1) {
 
242
            gs_note_error(gs_error_ioerror);
 
243
            goto finish;
 
244
        }
 
245
        if (fmode[0] == 'w') {
 
246
            /* Reopen an existing file for 'write' */
 
247
            /* Check first to make sure that we have exclusive access */
 
248
            if (base_f->openlist != NULL) {
 
249
                code = gs_note_error(gs_error_ioerror);
 
250
                goto finish;
 
251
            }
 
252
            f = base_f;         /* use the file */
 
253
            goto finish;
 
254
        } else {
 
255
            /* Reopen an existing file for 'read' */
 
256
            /* We need to 'clone' this memfile so that each reader instance     */
 
257
            /* will be able to maintain it's own 'state'                        */
 
258
            f = gs_alloc_struct(mem, MEMFILE, &st_MEMFILE,
 
259
                                "memfile_fopen_instance(MEMFILE)");
 
260
            if (f == NULL) {
 
261
                eprintf1("memfile_open_scratch(%s): gs_alloc_struct failed\n", fname);
 
262
                code = gs_note_error(gs_error_VMerror);
 
263
                goto finish;
 
264
            }
 
265
            memcpy(f, base_f, sizeof(MEMFILE));
 
266
            f->memory = mem;
 
267
            f->data_memory = data_mem;
 
268
            f->compress_state = 0;              /* Not used by reader instance */
 
269
            f->decompress_state = 0;    /* make clean for GC, or alloc'n failure */
 
270
            f->reservePhysBlockChain = NULL;
 
271
            f->reservePhysBlockCount = 0;
 
272
            f->reserveLogBlockChain = NULL;
 
273
            f->reserveLogBlockCount = 0;
 
274
            f->openlist = base_f->openlist;
 
275
            base_f->openlist = f;               /* link this one in to the base memfile */
 
276
            f->base_memfile = base_f;
 
277
            f->log_curr_pos = 0;
 
278
            f->raw_head = NULL;
 
279
            f->error_code = 0;
 
280
 
 
281
            if (f->log_head->phys_blk->data_limit != NULL) {
 
282
                /* The file is compressed, so we need to copy the logical block */
 
283
                /* list so that it is unique to this instance, and initialize   */
 
284
                /* the decompressor.                                            */
 
285
                LOG_MEMFILE_BLK *log_block, *new_log_block;
 
286
                int i;
 
287
                int num_log_blocks = (f->log_length + MEMFILE_DATA_SIZE - 1) / MEMFILE_DATA_SIZE;
 
288
                const stream_state *decompress_proto = clist_decompressor_state(NULL);
 
289
                const stream_template *decompress_template = decompress_proto->template;
 
290
 
 
291
                new_log_block = MALLOC(f, num_log_blocks * sizeof(LOG_MEMFILE_BLK), "memfile_fopen" );
 
292
                if (new_log_block == NULL)
 
293
                    code = gs_note_error(gs_error_VMerror);
 
294
 
 
295
                /* copy the logical blocks to the new list just allocated */
 
296
                for (log_block=f->log_head, i=0; log_block != NULL; log_block=log_block->link, i++) {
 
297
                    new_log_block[i].phys_blk = log_block->phys_blk;
 
298
                    new_log_block[i].phys_pdata = log_block->phys_pdata;
 
299
                    new_log_block[i].raw_block = NULL;
 
300
                    new_log_block[i].link = log_block->link == NULL ? NULL : new_log_block + i + 1;
 
301
                }
 
302
                f->log_head = new_log_block;
 
303
 
 
304
                /* NB: don't need compress_state for reading */
 
305
                f->decompress_state =
 
306
                    gs_alloc_struct(mem, stream_state, decompress_template->stype,
 
307
                                    "memfile_open_scratch(decompress_state)");
 
308
                if (f->decompress_state == 0) {
 
309
                    eprintf1("memfile_open_scratch(%s): gs_alloc_struct failed\n", fname);
 
310
                    code = gs_note_error(gs_error_VMerror);
 
311
                    goto finish;
 
312
                }
 
313
                memcpy(f->decompress_state, decompress_proto,
 
314
                       gs_struct_type_size(decompress_template->stype));
 
315
                f->decompress_state->memory = mem;
 
316
                if (decompress_template->set_defaults)
 
317
                    (*decompress_template->set_defaults) (f->decompress_state);
 
318
            }
 
319
            f->log_curr_blk = f->log_head;
 
320
            memfile_get_pdata(f);               /* set up the initial block */
 
321
 
 
322
            goto finish;
 
323
        }
235
324
    }
236
 
 
237
 
    /* There is no need to set fname in this implementation, */
238
 
    /* but we do it anyway. */
239
 
    fname[0] = (ok_to_compress ? 'a' : 'b');
240
 
    fname[1] = 0;
241
 
 
 
325
    fname[0] = 0;       /* no file name yet */
242
326
    f = gs_alloc_struct(mem, MEMFILE, &st_MEMFILE,
243
327
                        "memfile_open_scratch(MEMFILE)");
244
328
    if (f == NULL) {
251
335
    /* init an empty file, BEFORE allocating de/compress state */
252
336
    f->compress_state = 0;      /* make clean for GC, or alloc'n failure */
253
337
    f->decompress_state = 0;
 
338
    f->openlist = NULL;
 
339
    f->base_memfile = NULL;
254
340
    f->total_space = 0;
255
341
    f->reservePhysBlockChain = NULL;
256
342
    f->reservePhysBlockCount = 0;
298
384
    }
299
385
    f->total_space = 0;
300
386
 
 
387
    /* Return the address of this memfile as a string for use in future clist_fopen calls */
 
388
    fname[0] = 0xff;        /* a flag that this is a memfile name */
 
389
    sprintf(fname+1, "0x%0x", f);
 
390
 
301
391
#ifdef DEBUG
302
 
    /* If this is the start, init some statistics.       */
303
 
    /* Hack: we know the 'a' file is opened first. */
304
 
    if (*fname == 'a') {
305
392
        tot_compressed = 0;
306
393
        tot_raw = 0;
307
394
        tot_cache_miss = 0;
308
395
        tot_cache_hits = 0;
309
396
        tot_swap_out = 0;
310
 
    }
311
397
#endif
312
398
finish:
313
399
    if (code < 0) {
326
412
{
327
413
    MEMFILE *const f = (MEMFILE *)cf;
328
414
 
329
 
    /* We don't implement closing without deletion. */
330
 
    if (!delete)
331
 
        return_error(gs_error_invalidfileaccess);
 
415
    if (!delete) {
 
416
        if (f->base_memfile) {
 
417
            MEMFILE *prev_f;
 
418
 
 
419
            /* Here we need to delete this instance from the 'openlist' */
 
420
            /* in case this file was opened for 'read' on a previously  */
 
421
            /* written file (base_memfile != NULL)                          */
 
422
            for (prev_f = f->base_memfile; prev_f != NULL; prev_f = prev_f->openlist)
 
423
                if (prev_f->openlist == f)
 
424
                    break;
 
425
            if (prev_f == NULL) {
 
426
                eprintf1("Could not find 0x%x on memfile openlist\n", ((unsigned int)f));
 
427
                return_error(gs_error_invalidfileaccess);
 
428
            }
 
429
            prev_f->openlist = f->openlist;     /* link around the one being fclosed */
 
430
            /* Now delete this MEMFILE reader instance */
 
431
            /* NB: we don't delete 'base' instances until we delete */
 
432
            /* If the file is compressed, free the logical blocks, but not */
 
433
            /* the phys_blk info (that is still used by the base memfile   */
 
434
            if (f->log_head->phys_blk->data_limit != NULL) {
 
435
                LOG_MEMFILE_BLK *tmpbp, *bp = f->log_head;
 
436
 
 
437
                while (bp != NULL) {
 
438
                    tmpbp = bp->link;
 
439
                    FREE(f, bp, "memfile_free_mem(log_blk)");
 
440
                    bp = tmpbp;
 
441
                }
 
442
                f->log_head = NULL;
 
443
 
 
444
                /* Free any internal compressor state. */
 
445
                if (f->compressor_initialized) {
 
446
                    if (f->decompress_state->template->release != 0)
 
447
                        (*f->decompress_state->template->release) (f->decompress_state);
 
448
                    if (f->compress_state->template->release != 0)
 
449
                        (*f->compress_state->template->release) (f->compress_state);
 
450
                    f->compressor_initialized = false;
 
451
                }
 
452
                /* free the raw buffers                                           */
 
453
                while (f->raw_head != NULL) {
 
454
                    RAW_BUFFER *tmpraw = f->raw_head->fwd;
 
455
 
 
456
                    FREE(f, f->raw_head, "memfile_free_mem(raw)");
 
457
                    f->raw_head = tmpraw;
 
458
                }
 
459
            }
 
460
            /* deallocate the memfile object proper */
 
461
            gs_free_object(f->memory, f, "memfile_close_and_unlink(MEMFILE)");
 
462
        }
 
463
        return 0;
 
464
    }
 
465
 
 
466
    /* If there are open read memfile structures, set them so that  */
 
467
    /* future accesses will return errors rather than causing SEGV  */
 
468
    if (f->openlist) {
 
469
        /* TODO: do the cleanup rather than just giving an error */
 
470
        eprintf1("Attempt to delete a memfile still open for read: 0x%0x\n", ((unsigned int)f));
 
471
        return_error(gs_error_invalidfileaccess);
 
472
    }
332
473
    memfile_free_mem(f);
333
474
 
334
475
    /* Free reserve blocks; don't do it in memfile_free_mem because */
360
501
static int
361
502
memfile_unlink(const char *fname)
362
503
{
363
 
    /*
364
 
     * Since we have no way to represent a memfile other than by the
365
 
     * pointer, we don't (can't) implement unlinking.
366
 
     */
367
 
    return_error(gs_error_invalidfileaccess);
 
504
    int code; 
 
505
    MEMFILE *f;
 
506
 
 
507
    /* memfile file names begin with a flag byte == 0xff */
 
508
    if (fname[0] == '\377' && (code = sscanf(fname+1, "0x%x", &f) == 1)) {
 
509
        return memfile_fclose((clist_file_ptr)f, fname, true);
 
510
    } else
 
511
        return_error(gs_error_invalidfileaccess);
368
512
}
369
513
 
370
514
/* ---------------- Writing ---------------- */
546
690
                    code = (*f->compress_state->template->init) (f->compress_state);
547
691
                if (code < 0)
548
692
                    return_error(gs_error_VMerror);  /****** BOGUS ******/
549
 
                if (f->decompress_state->template->init != 0)
550
 
                    code = (*f->decompress_state->template->init)
551
 
                        (f->decompress_state);
552
 
                if (code < 0)
553
 
                    return_error(gs_error_VMerror);  /****** BOGUS ******/
554
693
                f->compressor_initialized = true;
555
694
            }
556
695
            /* Write into the new physical block we just allocated,        */
672
811
static int
673
812
memfile_get_pdata(MEMFILE * f)
674
813
{
675
 
    int i, num_raw_buffers, status;
 
814
    int code, i, num_raw_buffers, status;
676
815
    LOG_MEMFILE_BLK *bp = f->log_curr_blk;
677
816
 
678
817
    if (bp->phys_blk->data_limit == NULL) {
685
824
        else
686
825
            f->pdata_end = f->pdata + MEMFILE_DATA_SIZE;
687
826
    } else {
 
827
 
688
828
        /* data was compressed                                            */
689
829
        if (f->raw_head == NULL) {
 
830
            code = 0;
690
831
            /* need to allocate the raw buffer pool                        */
691
832
            num_raw_buffers = GET_NUM_RAW_BUFFERS(f);
692
833
            if (f->reservePhysBlockCount) {
699
840
                f->reservePhysBlockChain = f->reservePhysBlockChain->link;
700
841
                --f->reservePhysBlockCount;
701
842
            } else {
702
 
                int code;
703
 
 
704
843
                f->raw_head =
705
844
                    allocateWithReserve(f, sizeof(*f->raw_head), &code,
706
845
                                        "memfile raw buffer",
726
865
            num_raw_buffers = i + 1;    /* if MALLOC failed, then OK    */
727
866
            if_debug1(':', "[:]Number of raw buffers allocated=%d\n",
728
867
                      num_raw_buffers);
 
868
            if (f->decompress_state->template->init != 0)
 
869
                code = (*f->decompress_state->template->init)
 
870
                    (f->decompress_state);
 
871
            if (code < 0)
 
872
                return_error(gs_error_VMerror);
 
873
 
729
874
        }                       /* end allocating the raw buffer pool (first time only)           */
730
875
        if (bp->raw_block == NULL) {
731
876
#ifdef DEBUG
821
966
        /*        is always full size.                                    */
822
967
    }                           /* end else (when data was compressed)                             */
823
968
 
824
 
    return (0);
 
969
    return 0;
825
970
}
826
971
 
827
972
/* ---------------- Reading ---------------- */
960
1105
    /* Free up memory that was allocated for the memfile              */
961
1106
    bp = f->log_head;
962
1107
 
963
 
/******************************************************************
964
 
 * The following was the original algorithm here.  This algorithm has a bug:
965
 
 * the second loop references the physical blocks again after they have been
966
 
 * freed.
967
 
 ******************************************************************/
968
 
 
969
 
#if 0                           /**************** *************** */
970
 
 
971
 
    if (bp != NULL) {
972
 
        /* Free the physical blocks that make up the compressed data      */
973
 
        PHYS_MEMFILE_BLK *pphys = (f->log_head)->phys_blk;
974
 
 
975
 
        if (pphys->data_limit != NULL) {
976
 
            /* the data was compressed, free the chain of blocks             */
977
 
            while (pphys != NULL) {
978
 
                PHYS_MEMFILE_BLK *tmpphys = pphys->link;
979
 
 
980
 
                FREE(f, pphys, "memfile_free_mem(pphys)");
981
 
                pphys = tmpphys;
982
 
            }
983
 
        }
984
 
    }
985
 
    /* free the logical blocks                                        */
986
 
    while (bp != NULL) {
987
 
        /* if this logical block was not compressed, free the phys_blk  */
988
 
        if (bp->phys_blk->data_limit == NULL) {
989
 
            FREE(f, bp->phys_blk, "memfile_free_mem(phys_blk)");
990
 
        }
991
 
        tmpbp = bp->link;
992
 
        FREE(f, bp, "memfile_free_mem(log_blk)");
993
 
        bp = tmpbp;
994
 
    }
995
 
 
996
 
#else /**************** *************** */
997
 
# if 1                          /**************** *************** */
998
 
 
999
 
/****************************************************************
1000
 
 * This algorithm is correct (we think).
1001
 
 ****************************************************************/
1002
 
 
1003
1108
    if (bp != NULL) {
1004
1109
        /* Null out phys_blk pointers to compressed data. */
1005
1110
        PHYS_MEMFILE_BLK *pphys = bp->phys_blk;
1030
1135
        bp = tmpbp;
1031
1136
    }
1032
1137
 
1033
 
/***********************************************************************
1034
 
 * This algorithm appears to be both simpler and free of the bug that
1035
 
 * occasionally causes the older one to reference freed blocks; but in
1036
 
 * fact it can miss blocks, because the very last compressed logical block
1037
 
 * can have spill into a second physical block, which is not referenced by
1038
 
 * any logical block.
1039
 
 ***********************************************************************/
1040
 
 
1041
 
# else                          /**************** *************** */
1042
 
 
1043
 
    {
1044
 
        PHYS_MEMFILE_BLK *prev_phys = 0;
1045
 
 
1046
 
        while (bp != NULL) {
1047
 
            PHYS_MEMFILE_BLK *phys = bp->phys_blk;
1048
 
 
1049
 
            if (phys != prev_phys) {
1050
 
                FREE(f, phys, "memfile_free_mem(phys_blk)");
1051
 
                prev_phys = phys;
1052
 
            }
1053
 
            tmpbp = bp->link;
1054
 
            FREE(f, bp, "memfile_free_mem(log_blk)");
1055
 
            bp = tmpbp;
1056
 
        }
1057
 
    }
1058
 
 
1059
 
# endif                         /**************** *************** */
1060
 
#endif /**************** *************** */
1061
 
 
1062
1138
    f->log_head = NULL;
1063
1139
 
1064
1140
    /* Free any internal compressor state. */