diff --git a/libgst/gstpriv.h b/libgst/gstpriv.h index 68c34b9..2c6c49f 100644 --- a/libgst/gstpriv.h +++ b/libgst/gstpriv.h @@ -373,8 +373,7 @@ enum { /* Set whether an object, OOP, is readonly or readwrite. */ #define MAKE_OOP_READONLY(oop, ro) \ - (((oop)->flags &= ~F_READONLY), \ - ((oop)->flags |= (ro) ? F_READONLY : 0)) + _gst_make_oop_readonly (oop, ro) #ifdef ENABLE_SECURITY diff --git a/libgst/oop.c b/libgst/oop.c index ad264d9..ad93d34 100644 --- a/libgst/oop.c +++ b/libgst/oop.c @@ -145,9 +145,18 @@ static OOP *queue_put (surv_space *q, OOP *src, int n); /* Move an object from survivor space to oldspace. */ static void tenure_one_object (); +/* Initialize an allocation heap with a hooks set. */ +static heap_data *init_space (void *function, size_t size); + /* Initialize an allocation heap with the oldspace hooks set. */ static heap_data *init_old_space (size_t size); +/* Initialize an allocation heap with the read-only oldspace hooks set. */ +static heap_data *init_ro_old_space (size_t size); + +/* Initialize an allocation heap with the fixedspace hooks set. */ +static heap_data *init_fixed_space (size_t size); + /* Initialize a surv_space structure. */ static void init_survivor_space (struct surv_space *space, size_t size); @@ -208,6 +217,15 @@ static int oldspace_sigsegv_handler (void* fault_address, int serious); #endif /* Hook that triggers garbage collection. */ +static heap_data *grow_nomemory (heap_data *h, size_t sz); + +/* Hook that triggers garbage collection. */ +static heap_data *ro_oldspace_nomemory (heap_data *h, size_t sz); + +/* Hook that triggers garbage collection. */ +static heap_data *fixedspace_nomemory (heap_data *h, size_t sz); + +/* Hook that triggers garbage collection. */ static heap_data *oldspace_nomemory (heap_data *h, size_t sz); /* Answer the number of fields to be scanned in the object starting @@ -235,6 +253,8 @@ static inline void mark_ephemeron_oops (void); not surviving the garbage collection. Called by preare_for_sweep. */ static inline void check_weak_refs (); +static gst_object _gst_alloc_new_obj (size_t size); + void init_survivor_space (struct surv_space *space, size_t size) @@ -247,16 +267,34 @@ init_survivor_space (struct surv_space *space, size_t size) } heap_data * -init_old_space (size_t size) +init_space (void *function, size_t size) { heap_data *h = _gst_mem_new_heap (0, size); h->after_prim_allocating = oldspace_after_allocating; h->before_prim_freeing = oldspace_before_freeing; - h->nomemory = oldspace_nomemory; + h->nomemory = function; return h; } +heap_data * +init_fixed_space (size_t size) +{ + return init_space (fixedspace_nomemory, size); +} + +heap_data * +init_ro_old_space (size_t size) +{ + return init_space (ro_oldspace_nomemory, size); +} + +heap_data * +init_old_space (size_t size) +{ + return init_space (oldspace_nomemory, size); +} + void _gst_init_mem_default () { @@ -331,8 +369,9 @@ _gst_init_mem (size_t eden, size_t survivor, size_t old, { if (old) { + _gst_mem.ro_old = init_ro_old_space (old); _gst_mem.old = init_old_space (old); - _gst_mem.fixed = init_old_space (old); + _gst_mem.fixed = init_fixed_space (old); } _gst_mem.active_half = &_gst_mem.surv[0]; @@ -695,15 +734,81 @@ _gst_swap_objects (OOP oop1, _gst_make_oop_weak (oop1); } +mst_Boolean +_gst_make_oop_readonly (OOP oop, mst_Boolean ro) +{ + gst_object newObj; + int size; + + /* they are the same so I can return */ + if (((oop->flags & F_READONLY) == F_READONLY) == ro) + return ro; + + size = SIZE_TO_BYTES (TO_INT(oop->object->objSize)); + if (ro) + { + /* become read only */ + if ((oop->flags & F_LOADED) == 0) + { + newObj = (gst_object) _gst_mem_alloc (_gst_mem.ro_old, size); + + if (!newObj) + abort (); + + memcpy (newObj, oop->object, size); + + if (oop->flags & F_FIXED) + _gst_mem_free (_gst_mem.fixed, oop->object); + else if (oop->flags & F_OLD) + _gst_mem_free (_gst_mem.old, oop->object); + + oop->object = newObj; + } + + oop->flags |= F_READONLY; + } + else + { + /* become writeable */ + if ((oop->flags & F_LOADED) == 0) + { + if (oop->flags & F_FIXED) + newObj = (gst_object) _gst_mem_alloc (_gst_mem.fixed, size); + else if (oop->flags & F_OLD) + newObj = (gst_object) _gst_mem_alloc (_gst_mem.old, size); + else + newObj = (gst_object) _gst_alloc_new_obj (size); + + if (!newObj) + abort (); + + memcpy (newObj, oop->object, size); + _gst_mem_free (_gst_mem.ro_old, oop->object); + + oop->object = newObj; + } + + oop->flags &= ~(F_READONLY); + } + + return ro; +} void _gst_make_oop_fixed (OOP oop) { gst_object newObj; int size; + if (oop->flags & F_FIXED) return; + if (oop->flags & F_READONLY) + { + oop->flags |= F_FIXED; + return ; + } + if ((oop->flags & F_LOADED) == 0) { size = SIZE_TO_BYTES (TO_INT(oop->object->objSize)); @@ -731,15 +836,17 @@ _gst_tenure_oop (OOP oop) if (oop->flags & F_OLD) return; - if (!(oop->flags & F_FIXED)) + if (!((oop->flags & F_FIXED) || (oop->flags & F_READONLY))) { int size = SIZE_TO_BYTES (TO_INT(oop->object->objSize)); + newObj = (gst_object) _gst_mem_alloc (_gst_mem.old, size); + _gst_mem.numOldOOPs++; + if (!newObj) abort (); memcpy (newObj, oop->object, size); - _gst_mem.numOldOOPs++; oop->object = newObj; } @@ -750,6 +857,31 @@ _gst_tenure_oop (OOP oop) gst_object +_gst_alloc_new_obj (size_t size) +{ + OOP *newAllocPtr; + gst_object p_instance; + + size = ROUNDED_BYTES (size); + + /* We don't want to have allocPtr pointing to the wrong thing during + GC, so we use a local var to hold its new value */ + newAllocPtr = _gst_mem.eden.allocPtr + BYTES_TO_SIZE (size); + + if UNCOMMON (newAllocPtr >= _gst_mem.eden.maxPtr) + { + _gst_scavenge (); + newAllocPtr = _gst_mem.eden.allocPtr + size; + } + + p_instance = (gst_object) _gst_mem.eden.allocPtr; + _gst_mem.eden.allocPtr = newAllocPtr; + p_instance->objSize = FROM_INT (BYTES_TO_SIZE (size)); + + return p_instance; +} + +gst_object _gst_alloc_obj (size_t size, OOP *p_oop) { @@ -780,6 +912,39 @@ _gst_alloc_obj (size_t size, } gst_object +_gst_alloc_ro_obj (size_t size, + OOP *p_oop) +{ + gst_object p_instance; + + size = ROUNDED_BYTES (size); + + /* If the object is big enough, we put it directly in oldspace. */ + p_instance = (gst_object) _gst_mem_alloc (_gst_mem.ro_old, size); + if COMMON (p_instance) + goto ok; + + _gst_global_gc (size); + p_instance = (gst_object) _gst_mem_alloc (_gst_mem.ro_old, size); + if COMMON (p_instance) + goto ok; + + _gst_compact (0); + p_instance = (gst_object) _gst_mem_alloc (_gst_mem.ro_old, size); + if UNCOMMON (!p_instance) + { + /* !!! do something more reasonable in the future */ + _gst_errorf ("Cannot recover, exiting..."); + exit (1); + } + +ok: + *p_oop = alloc_oop (p_instance, F_OLD | F_FIXED | F_READONLY); + p_instance->objSize = FROM_INT (BYTES_TO_SIZE (size)); + return p_instance; +} + +gst_object _gst_alloc_old_obj (size_t size, OOP *p_oop) { @@ -889,25 +1054,43 @@ oldspace_before_freeing (heap_data *h, heap_block *blk, size_t sz) } heap_data * -oldspace_nomemory (heap_data *h, size_t sz) +grow_nomemory (heap_data *h, size_t sz) { if (!_gst_gc_running) _gst_global_gc (sz); else { /* Already garbage collecting, emergency growth just to satisfy - tenuring necessities. */ - int grow_amount_to_satisfy_rate = _gst_mem.old->heap_limit + tenuring necessities. */ + int grow_amount_to_satisfy_rate = h->heap_limit * (100.0 + _gst_mem.space_grow_rate) / 100; - int grow_amount_to_satisfy_threshold = - (sz + _gst_mem.old->heap_total) - * 100.0 /_gst_mem.grow_threshold_percent; + int grow_amount_to_satisfy_threshold = + (sz + h->heap_total) + * 100.0 /_gst_mem.grow_threshold_percent; - _gst_mem.old->heap_limit = MAX (grow_amount_to_satisfy_rate, - grow_amount_to_satisfy_threshold); + h->heap_limit = MAX (grow_amount_to_satisfy_rate, + grow_amount_to_satisfy_threshold); } - return _gst_mem.old; + return h; +} + +heap_data * +ro_oldspace_nomemory (heap_data *h, size_t sz) +{ + return grow_nomemory (_gst_mem.ro_old, sz); +} + +heap_data * +fixedspace_nomemory (heap_data *h, size_t sz) +{ + return grow_nomemory (_gst_mem.fixed, sz); +} + +heap_data * +oldspace_nomemory (heap_data *h, size_t sz) +{ + return grow_nomemory (_gst_mem.old, sz); } #ifndef NO_SIGSEGV_HANDLING @@ -979,6 +1162,7 @@ void grow_memory_no_compact (size_t new_heap_limit) { _gst_mem.old->heap_limit = new_heap_limit; + _gst_mem.ro_old->heap_limit = new_heap_limit; _gst_mem.fixed->heap_limit = new_heap_limit; _gst_mem.numGrowths++; update_stats (&stats.timeOfLastGrowth, @@ -996,6 +1180,7 @@ _gst_compact (size_t new_heap_limit) if (new_heap_limit) { _gst_mem.fixed->heap_limit = new_heap_limit; + _gst_mem.ro_old->heap_limit = new_heap_limit; _gst_mem.numGrowths++; update_stats (&stats.timeOfLastGrowth, &_gst_mem.timeBetweenGrowths, NULL); @@ -1037,7 +1222,7 @@ _gst_compact (size_t new_heap_limit) oop < &_gst_mem.ot[_gst_mem.ot_size]; oop++) { PREFETCH_LOOP (oop, PREF_READ | PREF_NTA); - if ((oop->flags & (F_OLD | F_FIXED | F_LOADED)) == F_OLD) + if ((oop->flags & (F_OLD | F_FIXED | F_LOADED | F_READONLY)) == F_OLD) { gst_object new; size_t size = SIZE_TO_BYTES (TO_INT (oop->object->objSize)); @@ -1049,6 +1234,7 @@ _gst_compact (size_t new_heap_limit) } xfree (_gst_mem.old); + _gst_mem.old = new_heap; new_heap->nomemory = oldspace_nomemory; @@ -1146,7 +1332,9 @@ _gst_global_gc (int next_allocation) if UNCOMMON ((next_allocation + _gst_mem.old->heap_total) * 100.0 / old_limit > _gst_mem.grow_threshold_percent || (next_allocation + _gst_mem.fixed->heap_total) - * 100.0 / _gst_mem.fixed->heap_limit > _gst_mem.grow_threshold_percent) + * 100.0 / _gst_mem.fixed->heap_limit > _gst_mem.grow_threshold_percent + || (next_allocation + _gst_mem.ro_old->heap_total) + * 100.0 / _gst_mem.ro_old->heap_limit > _gst_mem.grow_threshold_percent) { int grow_amount_to_satisfy_rate = old_limit * (100.0 + _gst_mem.space_grow_rate) / 100; @@ -1190,7 +1378,9 @@ _gst_scavenge (void) || _gst_mem.old->heap_total * 100.0 / _gst_mem.old->heap_limit > _gst_mem.grow_threshold_percent || _gst_mem.fixed->heap_total * 100.0 / _gst_mem.fixed->heap_limit > - _gst_mem.grow_threshold_percent) + _gst_mem.grow_threshold_percent + || _gst_mem.ro_old->heap_total * 100.0 / _gst_mem.ro_old->heap_limit > + _gst_mem.grow_threshold_percent) { _gst_global_gc (0); _gst_incremental_gc_step (); @@ -1452,20 +1642,20 @@ _gst_sweep_oop (OOP oop) _gst_make_oop_non_weak (oop); /* Free unreachable oldspace objects. */ - if UNCOMMON (oop->flags & F_FIXED) + if (oop->flags & F_OLD) { _gst_mem.numOldOOPs--; stats.reclaimedOldSpaceBytesSinceLastGlobalGC += - SIZE_TO_BYTES (TO_INT (OOP_TO_OBJ (oop)->objSize)); - if ((oop->flags & F_LOADED) == 0) - _gst_mem_free (_gst_mem.fixed, oop->object); + SIZE_TO_BYTES (TO_INT (OOP_TO_OBJ (oop)->objSize)); } - else if UNCOMMON (oop->flags & F_OLD) + + if ((oop->flags & F_LOADED) == 0) { - _gst_mem.numOldOOPs--; - stats.reclaimedOldSpaceBytesSinceLastGlobalGC += - SIZE_TO_BYTES (TO_INT (OOP_TO_OBJ (oop)->objSize)); - if ((oop->flags & F_LOADED) == 0) + if UNCOMMON (oop->flags & F_READONLY) + _gst_mem_free (_gst_mem.ro_old, oop->object); + else if UNCOMMON (oop->flags & F_FIXED) + _gst_mem_free (_gst_mem.fixed, oop->object); + else if UNCOMMON (oop->flags & F_OLD) _gst_mem_free (_gst_mem.old, oop->object); } @@ -1617,7 +1807,9 @@ tenure_one_object () _gst_tenure_oop (oop); queue_get (&_gst_mem.tenuring_queue, 1); - queue_get (_gst_mem.active_half, TO_INT (oop->object->objSize)); + + if (!((oop->flags & F_FIXED) || (oop->flags & F_READONLY))) + queue_get (_gst_mem.active_half, TO_INT (oop->object->objSize)); } void @@ -2061,8 +2253,10 @@ _gst_copy_an_oop (OOP oop) #endif queue_put (&_gst_mem.tenuring_queue, &oop, 1); - obj = oop->object = (gst_object) - queue_put (_gst_mem.active_half, pData, TO_INT (obj->objSize)); + + if (!((oop->flags & F_FIXED) || (oop->flags & F_READONLY))) + obj = oop->object = (gst_object) + queue_put (_gst_mem.active_half, pData, TO_INT (obj->objSize)); oop->flags &= ~(F_SPACES | F_POOLED); oop->flags |= _gst_mem.active_flag; diff --git a/libgst/oop.h b/libgst/oop.h index 6816b3f..fd9ea9f 100644 --- a/libgst/oop.h +++ b/libgst/oop.h @@ -189,7 +189,7 @@ typedef struct cheney_scan_state { struct memory_space { - heap_data *old, *fixed; + heap_data *ro_old, *old, *fixed; struct new_space eden; struct surv_space surv[2], tenuring_queue; @@ -414,6 +414,11 @@ extern gst_object _gst_alloc_old_obj (size_t size, OOP *p_oop) ATTRIBUTE_HIDDEN; +/* The same, but for a read-only oldspace object */ +extern gst_object _gst_alloc_ro_obj (size_t size, + OOP *p_oop) + ATTRIBUTE_HIDDEN; + /* Allocate and return space for an object of SIZE words, without creating an OOP. This is a special operation that is only needed at bootstrap time, so it does not care about garbage collection. */ @@ -437,6 +442,10 @@ extern mst_Boolean _gst_realloc_oop_table (size_t newSize) extern void _gst_tenure_oop (OOP oop) ATTRIBUTE_HIDDEN; +/* Set whether an object, OOP, is readonly or readwrite. */ +extern mst_Boolean _gst_make_oop_readonly (OOP oop, mst_Boolean ro) + ATTRIBUTE_HIDDEN; + /* Move OOP to fixedspace. */ extern void _gst_make_oop_fixed (OOP oop) ATTRIBUTE_HIDDEN; diff --git a/libgst/save.c b/libgst/save.c index 77cc8b9..70f41ed 100644 --- a/libgst/save.c +++ b/libgst/save.c @@ -646,7 +646,9 @@ load_normal_oops (int imageFd) else { - if (flags & F_FIXED) + if (flags & F_READONLY) + object = (gst_object) _gst_mem_alloc (_gst_mem.ro_old, size); + else if (flags & F_FIXED) { _gst_mem.numFixedOOPs++; object = (gst_object) _gst_mem_alloc (_gst_mem.fixed, size); diff --git a/libgst/sym.c b/libgst/sym.c index a3cfd65..e0d7c8a 100644 --- a/libgst/sym.c +++ b/libgst/sym.c @@ -1460,11 +1460,10 @@ alloc_symbol_oop (const char *str, int len) numBytes = sizeof(gst_object_header) + len; alignedBytes = ROUNDED_BYTES (numBytes); - symbol = (gst_symbol) _gst_alloc_obj (alignedBytes, &symbolOOP); + symbol = (gst_symbol) _gst_alloc_ro_obj (alignedBytes, &symbolOOP); INIT_UNALIGNED_OBJECT (symbolOOP, alignedBytes - numBytes); memcpy (symbol->symString, str, len); - symbolOOP->flags |= F_READONLY; return symbolOOP; } diff --git a/snprintfv/snprintfv/filament.h b/snprintfv/snprintfv/filament.h index 4a91eb6..8a7ce6c 100644 --- a/snprintfv/snprintfv/filament.h +++ b/snprintfv/snprintfv/filament.h @@ -1,4 +1,4 @@ -#line 1 "../../../snprintfv/snprintfv/filament.in" +#line 1 "./filament.in" /* -*- Mode: C -*- */ /* filament.h --- a bit like a string but different =)O| @@ -118,7 +118,7 @@ extern char * fildelete (Filament *fil); extern void _fil_extend (Filament *fil, size_t len, boolean copy); -#line 61 "../../../snprintfv/snprintfv/filament.in" +#line 61 "./filament.in" /* Save the overhead of a function call in the great majority of cases. */ #define fil_maybe_extend(fil, len, copy) \ diff --git a/snprintfv/snprintfv/printf.h b/snprintfv/snprintfv/printf.h index 49a2e9f..1437dd5 100644 --- a/snprintfv/snprintfv/printf.h +++ b/snprintfv/snprintfv/printf.h @@ -1,4 +1,4 @@ -#line 1 "../../../snprintfv/snprintfv/printf.in" +#line 1 "./printf.in" /* -*- Mode: C -*- */ /* printf.in --- printf clone for argv arrays @@ -266,7 +266,7 @@ enum } \ } SNV_STMT_END -#line 269 "../../../snprintfv/snprintfv/printf.in" +#line 269 "./printf.in" /** * printf_generic_info: * @pinfo: the current state information for the format @@ -302,7 +302,7 @@ extern int printf_generic_info (struct printf_info *const pinfo, size_t n, int * extern int printf_generic (STREAM *stream, struct printf_info *const pinfo, union printf_arg const *args); -#line 270 "../../../snprintfv/snprintfv/printf.in" +#line 270 "./printf.in" /** * register_printf_function: * @spec: the character which will trigger @func, cast to an unsigned int. @@ -789,7 +789,7 @@ extern int snv_vasprintf (char **result, const char *format, va_list ap); extern int snv_asprintfv (char **result, const char *format, snv_constpointer const args[]); -#line 271 "../../../snprintfv/snprintfv/printf.in" +#line 271 "./printf.in" /* If you don't want to use snprintfv functions for *all* of your string formatting API, then define COMPILING_SNPRINTFV_C and use the snv_ diff --git a/snprintfv/snprintfv/stream.h b/snprintfv/snprintfv/stream.h index 496bd33..0bebce1 100644 --- a/snprintfv/snprintfv/stream.h +++ b/snprintfv/snprintfv/stream.h @@ -1,4 +1,4 @@ -#line 1 "../../../snprintfv/snprintfv/stream.in" +#line 1 "./stream.in" /* -*- Mode: C -*- */ /* stream.h --- customizable stream routines @@ -180,7 +180,7 @@ extern int stream_puts (char *s, STREAM *stream); extern int stream_get (STREAM *stream); -#line 88 "../../../snprintfv/snprintfv/stream.in" +#line 88 "./stream.in" #ifdef __cplusplus #if 0 /* This brace is so that emacs can still indent properly: */