summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/pdfapp.c2
-rw-r--r--apps/pdfdraw.c2
-rw-r--r--fitz/base_memory.c57
-rw-r--r--fitz/fitz.h3
-rw-r--r--fitz/res_store.c96
-rw-r--r--scripts/cmapdump.c5
6 files changed, 139 insertions, 26 deletions
diff --git a/apps/pdfapp.c b/apps/pdfapp.c
index c1e026fe..849b0d18 100644
--- a/apps/pdfapp.c
+++ b/apps/pdfapp.c
@@ -342,8 +342,6 @@ static void pdfapp_loadpage_pdf(pdfapp_t *app)
fz_free_device(mdev);
pdf_free_page(app->ctx, page);
-
- fz_age_store(app->ctx, 3);
}
static void pdfapp_loadpage_xps(pdfapp_t *app)
diff --git a/apps/pdfdraw.c b/apps/pdfdraw.c
index f7867bf0..1e71181e 100644
--- a/apps/pdfdraw.c
+++ b/apps/pdfdraw.c
@@ -263,8 +263,6 @@ static void drawpage(pdf_xref *xref, int pagenum)
if (showmd5 || showtime)
printf("\n");
- fz_age_store(ctx, 3);
-
fz_flush_warnings(ctx);
}
diff --git a/fitz/base_memory.c b/fitz/base_memory.c
index 79ae38b0..17a701e2 100644
--- a/fitz/base_memory.c
+++ b/fitz/base_memory.c
@@ -1,9 +1,48 @@
#include "fitz.h"
+static void *
+do_scavenging_malloc(fz_context *ctx, unsigned int size)
+{
+ void *p;
+ int phase = 0;
+
+ /* LOCK */
+ do {
+ p = ctx->alloc->malloc(ctx->alloc->user, size);
+ if (p != NULL)
+ return p;
+ } while (fz_store_scavenge(ctx, size, &phase));
+ /* UNLOCK */
+
+ return NULL;
+}
+
+static void *
+do_scavenging_realloc(fz_context *ctx, void *p, unsigned int size)
+{
+ void *q;
+ int phase = 0;
+
+ /* LOCK */
+ do {
+ q = ctx->alloc->realloc(ctx->alloc->user, p, size);
+ if (q != NULL)
+ return q;
+ } while (fz_store_scavenge(ctx, size, &phase));
+ /* UNLOCK */
+
+ return NULL;
+}
+
void *
fz_malloc(fz_context *ctx, unsigned int size)
{
- void *p = ctx->alloc->malloc(ctx->alloc->user, size);
+ void *p;
+
+ if (size == 0)
+ return NULL;
+
+ p = do_scavenging_malloc(ctx, size);
if (!p)
fz_throw(ctx, "malloc of %d bytes failed", size);
return p;
@@ -12,7 +51,7 @@ fz_malloc(fz_context *ctx, unsigned int size)
void *
fz_malloc_no_throw(fz_context *ctx, unsigned int size)
{
- return ctx->alloc->malloc(ctx->alloc->user, size);
+ return do_scavenging_malloc(ctx, size);
}
void *
@@ -26,7 +65,7 @@ fz_malloc_array(fz_context *ctx, unsigned int count, unsigned int size)
if (count > UINT_MAX / size)
fz_throw(ctx, "malloc of array (%d x %d bytes) failed (integer overflow)", count, size);
- p = ctx->alloc->malloc(ctx->alloc->user, count * size);
+ p = do_scavenging_malloc(ctx, count * size);
if (!p)
fz_throw(ctx, "malloc of array (%d x %d bytes) failed", count, size);
return p;
@@ -44,7 +83,7 @@ fz_malloc_array_no_throw(fz_context *ctx, unsigned int count, unsigned int size)
return NULL;
}
- return ctx->alloc->malloc(ctx->alloc->user, count * size);
+ return do_scavenging_malloc(ctx, count * size);
}
void *
@@ -60,7 +99,7 @@ fz_calloc(fz_context *ctx, unsigned int count, unsigned int size)
fz_throw(ctx, "calloc (%d x %d bytes) failed (integer overflow)", count, size);
}
- p = ctx->alloc->malloc(ctx->alloc->user, count * size);
+ p = do_scavenging_malloc(ctx, count * size);
if (!p)
{
fz_throw(ctx, "calloc (%d x %d bytes) failed", count, size);
@@ -83,7 +122,7 @@ fz_calloc_no_throw(fz_context *ctx, unsigned int count, unsigned int size)
return NULL;
}
- p = ctx->alloc->malloc(ctx->alloc->user, count * size);
+ p = do_scavenging_malloc(ctx, count * size);
if (p)
{
memset(p, 0, count*size);
@@ -105,7 +144,7 @@ fz_resize_array(fz_context *ctx, void *p, unsigned int count, unsigned int size)
if (count > UINT_MAX / size)
fz_throw(ctx, "resize array (%d x %d bytes) failed (integer overflow)", count, size);
- np = ctx->alloc->realloc(ctx->alloc->user, p, count * size);
+ np = do_scavenging_realloc(ctx, p, count * size);
if (!np)
fz_throw(ctx, "resize array (%d x %d bytes) failed", count, size);
return np;
@@ -126,13 +165,15 @@ fz_resize_array_no_throw(fz_context *ctx, void *p, unsigned int count, unsigned
return NULL;
}
- return ctx->alloc->realloc(ctx->alloc->user, p, count * size);
+ return do_scavenging_realloc(ctx, p, count * size);
}
void
fz_free(fz_context *ctx, void *p)
{
+ /* LOCK */
ctx->alloc->free(ctx->alloc->user, p);
+ /* UNLOCK */
}
char *
diff --git a/fitz/fitz.h b/fitz/fitz.h
index 81743d0a..aad4b9a2 100644
--- a/fitz/fitz.h
+++ b/fitz/fitz.h
@@ -525,7 +525,8 @@ void fz_drop_storable(fz_context *, fz_storable *);
void fz_store_item(fz_context *ctx, fz_obj *key, void *val, unsigned int itemsize);
void *fz_find_item(fz_context *ctx, fz_store_free_fn *freefn, fz_obj *key);
void fz_remove_item(fz_context *ctx, fz_store_free_fn *freefn, fz_obj *key);
-void fz_age_store(fz_context *ctx, int maxage);
+void fz_empty_store(fz_context *ctx);
+int fz_store_scavenge(fz_context *ctx, unsigned int size, int *phase);
/*
* Buffered reader.
diff --git a/fitz/res_store.c b/fitz/res_store.c
index 08885c30..6c1c628d 100644
--- a/fitz/res_store.c
+++ b/fitz/res_store.c
@@ -9,7 +9,6 @@ struct fz_item_s
fz_item *next;
fz_item *prev;
fz_store *store;
- int age;
};
struct refkey
@@ -83,8 +82,10 @@ fz_drop_storable(fz_context *ctx, fz_storable *s)
}
static void
-evict(fz_context *ctx, fz_store *store, fz_item *item)
+evict(fz_context *ctx, fz_item *item)
{
+ fz_store *store = ctx->store;
+
store->size -= item->size;
/* Unlink from the linked list */
if (item->next)
@@ -104,8 +105,10 @@ evict(fz_context *ctx, fz_store *store, fz_item *item)
refkey.gen = fz_to_gen(item->key);
fz_hash_remove(store->hash, &refkey);
}
- /* Drop the value, key and item */
- item->val->free(ctx, item->val);
+ /* Drop a reference to the value (freeing if required) */
+ if (item->val->refs > 0 && --item->val->refs == 0)
+ item->val->free(ctx, item->val);
+ /* Always drops the key and free the item */
fz_drop_obj(item->key);
fz_free(ctx, item);
}
@@ -143,7 +146,7 @@ ensure_space(fz_context *ctx, unsigned int tofree)
{
/* Free this item */
count += item->size;
- evict(ctx, store, item);
+ evict(ctx, item);
if (count >= tofree)
break;
@@ -308,7 +311,7 @@ fz_remove_item(fz_context *ctx, fz_store_free_fn *free, fz_obj *key)
}
void
-fz_age_store(fz_context *ctx, int maxage)
+fz_empty_store(fz_context *ctx)
{
fz_item *item, *next;
fz_store *store = ctx->store;
@@ -321,11 +324,7 @@ fz_age_store(fz_context *ctx, int maxage)
for (item = store->head; item; item = next)
{
next = item->next;
- /* If we've only got 1 reference, then we must be the only
- * holders. Age the item. If it's older than the maximum,
- * bin it. */
- if (item->val->refs == 1 && ++item->age > maxage)
- evict(ctx, store, item);
+ evict(ctx, item);
}
/* UNLOCK */
}
@@ -335,7 +334,7 @@ fz_free_store_context(fz_context *ctx)
{
if (ctx == NULL || ctx->store == NULL)
return;
- fz_age_store(ctx, 0);
+ fz_empty_store(ctx);
fz_free_hash(ctx->store->hash);
fz_free(ctx, ctx->store);
ctx->store = NULL;
@@ -352,7 +351,7 @@ fz_debug_store(fz_context *ctx)
/* LOCK */
for (item = store->head; item; item = item->next)
{
- printf("store[*][claim=%d] ", item->val->refs);
+ printf("store[*][refs=%d][size=%d] ", item->val->refs, item->size);
if (fz_is_indirect(item->key))
{
printf("(%d %d R) ", fz_to_num(item->key), fz_to_gen(item->key));
@@ -362,3 +361,74 @@ fz_debug_store(fz_context *ctx)
}
/* UNLOCK */
}
+
+static int
+scavenge(fz_context *ctx, unsigned int tofree)
+{
+ fz_store *store = ctx->store;
+ unsigned int count = 0;
+ fz_item *item, *prev;
+
+ /* Free the items */
+ for (item = store->tail; item; item = prev)
+ {
+ prev = item->prev;
+ if (item->val->refs == 1)
+ {
+ /* Free this item */
+ count += item->size;
+ evict(ctx, item);
+
+ if (count >= tofree)
+ break;
+ }
+ }
+ /* Success is managing to evict any blocks */
+ return count != 0;
+}
+
+int fz_store_scavenge(fz_context *ctx, unsigned int size, int *phase)
+{
+ fz_store *store;
+ unsigned int max;
+
+ if (ctx == NULL)
+ return 0;
+ store = ctx->store;
+ if (store == NULL)
+ return 0;
+
+#ifdef DEBUG_SCAVENGING
+ printf("Scavenging: store=%d size=%d phase=%d\n", store->size, size, *phase);
+ fz_debug_store(ctx);
+ Memento_stats();
+#endif
+ do
+ {
+ /* Calculate 'max' as the maximum size of the store for this phase */
+ if (store->max != FZ_STORE_UNLIMITED)
+ max = store->max / 16 * (16 - *phase);
+ else
+ max = store->size / (16 - *phase) * (15 - *phase);
+ *phase++;
+
+ if (size + store->size > max)
+ if (scavenge(ctx, size + store->size - max))
+ {
+#ifdef DEBUG_SCAVENGING
+ printf("scavenged: store=%d\n", store->size);
+ fz_debug_store(ctx);
+ Memento_stats();
+#endif
+ return 1;
+ }
+ }
+ while (max > 0);
+
+#ifdef DEBUG_SCAVENGING
+ printf("scavenging failed\n");
+ fz_debug_store(ctx);
+ Memento_listBlocks();
+#endif
+ return 0;
+}
diff --git a/scripts/cmapdump.c b/scripts/cmapdump.c
index c8ae8134..dc5d93e6 100644
--- a/scripts/cmapdump.c
+++ b/scripts/cmapdump.c
@@ -192,3 +192,8 @@ void fz_new_store_context(fz_context *ctx, unsigned int max)
void fz_free_store_context(fz_context *ctx)
{
}
+
+int fz_store_scavenge(fz_context *ctx, unsigned int size, int *phase)
+{
+ return 0;
+}