-/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002, 2003, 2006, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002, 2003, 2006,
+ * 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
#include <stdio.h>
#include <errno.h>
#include <string.h>
+#include <stdlib.h>
#include <math.h>
#ifdef __ia64__
#include "libguile/root.h"
#include "libguile/strings.h"
#include "libguile/vectors.h"
-#include "libguile/weaks.h"
#include "libguile/hashtab.h"
#include "libguile/tags.h"
#include "libguile/debug-malloc.h"
#endif
-#ifdef HAVE_MALLOC_H
-#include <malloc.h>
-#endif
-
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
*/
int scm_debug_cells_gc_interval = 0;
-#if SCM_ENABLE_DEPRECATED == 1
/* Hash table that keeps a reference to objects the user wants to protect from
- garbage collection. It could arguably be private but applications have come
- to rely on it (e.g., Lilypond 2.13.9). */
-SCM scm_protects;
-#else
+ garbage collection. */
static SCM scm_protects;
-#endif
+
#if (SCM_DEBUG_CELL_ACCESSES == 1)
\f
-/* Compatibility. */
-
-#ifndef HAVE_GC_GET_HEAP_USAGE_SAFE
-static void
-GC_get_heap_usage_safe (GC_word *pheap_size, GC_word *pfree_bytes,
- GC_word *punmapped_bytes, GC_word *pbytes_since_gc,
- GC_word *ptotal_bytes)
-{
- *pheap_size = GC_get_heap_size ();
- *pfree_bytes = GC_get_free_bytes ();
- *punmapped_bytes = GC_get_unmapped_bytes ();
- *pbytes_since_gc = GC_get_bytes_since_gc ();
- *ptotal_bytes = GC_get_total_bytes ();
-}
-#endif
-
-#ifndef HAVE_GC_GET_FREE_SPACE_DIVISOR
-static GC_word
-GC_get_free_space_divisor (void)
-{
- return GC_free_space_divisor;
-}
-#endif
-
-\f
/* Hooks. */
scm_t_c_hook scm_before_gc_c_hook;
scm_t_c_hook scm_before_mark_c_hook;
static void
run_before_gc_c_hook (void)
{
+ if (!SCM_I_CURRENT_THREAD)
+ /* GC while a thread is spinning up; punt. */
+ return;
+
scm_c_hook_run (&scm_before_gc_c_hook, NULL);
}
GC_get_heap_usage_safe (&heap_size, &free_bytes, &unmapped_bytes,
&bytes_since_gc, &total_bytes);
- gc_times = GC_gc_no;
+ gc_times = GC_get_gc_no ();
answer =
scm_list_n (scm_cons (sym_gc_time_taken, scm_from_long (gc_time_taken)),
#define FUNC_NAME s_scm_gc
{
scm_i_gc ("call");
+ /* If you're calling scm_gc(), you probably want synchronous
+ finalization. */
+ GC_invoke_finalizers ();
return SCM_UNSPECIFIED;
}
#undef FUNC_NAME
void
scm_i_gc (const char *what)
{
-#ifndef HAVE_GC_SET_START_CALLBACK
- run_before_gc_c_hook ();
-#endif
GC_gcollect ();
}
void
scm_storage_prehistory ()
{
- GC_all_interior_pointers = 0;
+ GC_set_all_interior_pointers (0);
+
free_space_divisor = scm_getenv_int ("GC_FREE_SPACE_DIVISOR", 3);
minimum_free_space_divisor = free_space_divisor;
target_free_space_divisor = free_space_divisor;
GC_set_free_space_divisor (free_space_divisor);
+ GC_set_finalize_on_demand (1);
GC_INIT ();
get_image_size (void)
{
unsigned long size, resident, share;
- size_t ret;
+ size_t ret = 0;
FILE *fp = fopen ("/proc/self/statm", "r");
return ret;
}
+/* These are discussed later. */
+static size_t bytes_until_gc;
+static scm_i_pthread_mutex_t bytes_until_gc_lock = SCM_I_PTHREAD_MUTEX_INITIALIZER;
+
/* Make GC run more frequently when the process image size is growing,
measured against the number of bytes allocated through the GC.
size_t image_size;
size_t bytes_alloced;
+ scm_i_pthread_mutex_lock (&bytes_until_gc_lock);
+ bytes_until_gc = GC_get_heap_size ();
+ scm_i_pthread_mutex_unlock (&bytes_until_gc_lock);
+
image_size = get_image_size ();
bytes_alloced = GC_get_total_bytes ();
-#define HEURISTICS_DEBUG 1
+#define HEURISTICS_DEBUG 0
#if HEURISTICS_DEBUG
fprintf (stderr, "prev image / alloced: %lu / %lu\n", prev_image_size, prev_bytes_alloced);
return NULL;
}
+/* The adjust_gc_frequency routine handles transients in the process
+ image size. It can't handle instense non-GC-managed steady-state
+ allocation though, as it decays the FSD at steady-state down to its
+ minimum value.
+
+ The only real way to handle continuous, high non-GC allocation is to
+ let the GC know about it. This routine can handle non-GC allocation
+ rates that are similar in size to the GC-managed heap size.
+ */
+
+void
+scm_gc_register_allocation (size_t size)
+{
+ scm_i_pthread_mutex_lock (&bytes_until_gc_lock);
+ if (bytes_until_gc - size > bytes_until_gc)
+ {
+ bytes_until_gc = GC_get_heap_size ();
+ scm_i_pthread_mutex_unlock (&bytes_until_gc_lock);
+ GC_gcollect ();
+ }
+ else
+ {
+ bytes_until_gc -= size;
+ scm_i_pthread_mutex_unlock (&bytes_until_gc_lock);
+ }
+}
+
\f
return "foreign";
case scm_tc7_hashtable:
return "hashtable";
+ case scm_tc7_weak_set:
+ return "weak-set";
+ case scm_tc7_weak_table:
+ return "weak-table";
case scm_tc7_fluid:
return "fluid";
case scm_tc7_dynamic_state:
return "dynamic state";
case scm_tc7_frame:
return "frame";
- case scm_tc7_objcode:
- return "objcode";
- case scm_tc7_vm:
- return "vm";
case scm_tc7_vm_cont:
return "vm continuation";
case scm_tc7_wvect:
scm_c_hook_add (&scm_before_gc_c_hook, queue_after_gc_hook, NULL, 0);
scm_c_hook_add (&scm_before_gc_c_hook, start_gc_timer, NULL, 0);
scm_c_hook_add (&scm_after_gc_c_hook, accumulate_gc_timer, NULL, 0);
- scm_c_hook_add (&scm_after_gc_c_hook, adjust_gc_frequency, NULL, 0);
-#ifdef HAVE_GC_SET_START_CALLBACK
+ /* GC_get_heap_usage does not take a lock, and so can run in the GC
+ start hook. */
+ scm_c_hook_add (&scm_before_gc_c_hook, adjust_gc_frequency, NULL, 0);
+
GC_set_start_callback (run_before_gc_c_hook);
-#endif
#include "libguile/gc.x"
}