2000-07-06 Dirk Herrmann <D.Herrmann@tu-bs.de>
- * gh.g: Don't include <stdio.h>. Thanks to Han-Wen Nienhuys for
+ * gc.c (policy_on_error): Added in order to allow alloc_some_heap
+ to react to malloc failures in a context dependent way.
+
+ (scm_check_freelist): No need to flush streams before abort().
+
+ (scm_gc_for_newcell): Try to allocate new memory in three phases:
+ grow heap if preferred, if still no memory available collect
+ garbage, if still no memory available grow heap.
+
+ (heap_segment_table_size): Added to always reflect the actual
+ size of the heap segment table, because scm_n_heap_segs may differ
+ from the heap segment table size.
+
+ (alloc_some_heap): In case of malloc failure, react according to
+ the new policy_on_error parameter (either return to caller or
+ abort immediately). Further, keep heap_segment_table_size up to
+ date.
+
+ (scm_init_storage): Initialize heap_segment_table_size.
+
+2000-07-06 Dirk Herrmann <D.Herrmann@tu-bs.de>
+
+ * gh.h: Don't include <stdio.h>. Thanks to Han-Wen Nienhuys for
the hint.
2000-06-30 Dirk Herrmann <D.Herrmann@tu-bs.de>
static scm_sizet init_heap_seg (SCM_CELLPTR, scm_sizet, scm_freelist_t *);
-static void alloc_some_heap (scm_freelist_t *);
+
+typedef enum { return_on_error, abort_on_error } policy_on_error;
+static void alloc_some_heap (scm_freelist_t *, policy_on_error);
\f
{
fprintf (stderr, "Bad cell in freelist on newcell %lu: %d'th elt\n",
scm_newcell_count, i);
- fflush (stderr);
abort ();
}
}
}
}
+
/* When we get POSIX threads support, the master will be global and
* common while the freelist will be individual for each thread.
*/
{
if (master->grow_heap_p || scm_block_gc)
{
+ /* In order to reduce gc frequency, try to allocate a new heap
+ * segment first, even if gc might find some free cells. If we
+ * can't obtain a new heap segment, we will try gc later.
+ */
master->grow_heap_p = 0;
- alloc_some_heap (master);
+ alloc_some_heap (master, return_on_error);
}
- else
+ if (SCM_NULLP (master->clusters))
{
+ /* The heap was not grown, either because it wasn't scheduled to
+ * grow, or because there was not enough memory available. In
+ * both cases we have to try gc to get some free cells.
+ */
#ifdef DEBUGINFO
fprintf (stderr, "allocated = %d, ",
scm_cells_allocated
adjust_min_yield (master);
if (SCM_NULLP (master->clusters))
{
- /* gc could not free any cells */
- master->grow_heap_p = 0;
- alloc_some_heap (master);
+ /* gc could not free any cells. Now, we _must_ allocate a
+ * new heap segment, because there is no other possibility
+ * to provide a new cell for the caller.
+ */
+ alloc_some_heap (master, abort_on_error);
}
}
}
return cell;
}
+
#if 0
/* This is a support routine which can be used to reserve a cluster
* for some special use, such as debugging. It won't be useful until
scm_c_hook_t scm_after_sweep_c_hook;
scm_c_hook_t scm_after_gc_c_hook;
+
void
scm_igc (const char *what)
{
SCM_CELLPTR scm_heap_org;
scm_heap_seg_data_t * scm_heap_table = 0;
+static unsigned int heap_segment_table_size = 0;
int scm_n_heap_segs = 0;
/* init_heap_seg
}
static void
-alloc_some_heap (scm_freelist_t *freelist)
+alloc_some_heap (scm_freelist_t *freelist, policy_on_error error_policy)
#define FUNC_NAME "alloc_some_heap"
{
- scm_heap_seg_data_t * tmptable;
SCM_CELLPTR ptr;
long len;
- /* Critical code sections (such as the garbage collector)
- * aren't supposed to add heap segments.
- */
- if (scm_gc_heap_lock)
- SCM_MISC_ERROR ("can not grow heap while locked", SCM_EOL);
-
- /* Expand the heap tables to have room for the new segment.
- * Do not yet increment scm_n_heap_segs -- that is done by init_heap_seg
- * only if the allocation of the segment itself succeeds.
- */
- len = (1 + scm_n_heap_segs) * sizeof (scm_heap_seg_data_t);
+ if (scm_gc_heap_lock)
+ {
+ /* Critical code sections (such as the garbage collector) aren't
+ * supposed to add heap segments.
+ */
+ fprintf (stderr, "alloc_some_heap: Can not extend locked heap.\n");
+ abort ();
+ }
- SCM_SYSCALL (tmptable = ((scm_heap_seg_data_t *)
- realloc ((char *)scm_heap_table, len)));
- if (!tmptable)
- /* Dirk:FIXME:: scm_memory_error needs an additional message parameter.
- * Here: "could not grow heap segment table".
- */
- scm_memory_error (FUNC_NAME);
- else
- scm_heap_table = tmptable;
+ if (scm_n_heap_segs == heap_segment_table_size)
+ {
+ /* We have to expand the heap segment table to have room for the new
+ * segment. Do not yet increment scm_n_heap_segs -- that is done by
+ * init_heap_seg only if the allocation of the segment itself succeeds.
+ */
+ unsigned int new_table_size = scm_n_heap_segs + 1;
+ size_t size = new_table_size * sizeof (scm_heap_seg_data_t);
+ scm_heap_seg_data_t * new_heap_table;
+
+ SCM_SYSCALL (new_heap_table = ((scm_heap_seg_data_t *)
+ realloc ((char *)scm_heap_table, size)));
+ if (!new_heap_table)
+ {
+ if (error_policy == abort_on_error)
+ {
+ fprintf (stderr, "alloc_some_heap: Could not grow heap segment table.\n");
+ abort ();
+ }
+ else
+ {
+ return;
+ }
+ }
+ else
+ {
+ scm_heap_table = new_heap_table;
+ heap_segment_table_size = new_table_size;
+ }
+ }
/* Pick a size for the new heap segment.
}
}
- /* Dirk:FIXME:: scm_memory_error needs an additional message parameter.
- * Here: "could not grow heap".
- */
- scm_memory_error (FUNC_NAME);
+ if (error_policy == abort_on_error)
+ {
+ fprintf (stderr, "alloc_some_heap: Could not grow heap.\n");
+ abort ();
+ }
}
#undef FUNC_NAME
scm_mtrigger = SCM_INIT_MALLOC_LIMIT;
scm_heap_table = ((scm_heap_seg_data_t *)
scm_must_malloc (sizeof (scm_heap_seg_data_t) * 2, "hplims"));
+ heap_segment_table_size = 2;
if (make_initial_segment (init_heap_size_1, &scm_master_freelist) ||
make_initial_segment (init_heap_size_2, &scm_master_freelist2))