X-Git-Url: http://git.hcoop.net/bpt/guile.git/blobdiff_plain/6360beb28a918448ed42b0ddb905b2d9d513d8b9..03d1294977333b23b91e24c3b0b7ddf9cab26cfc:/libguile/gc.c diff --git a/libguile/gc.c b/libguile/gc.c index 16878607f..5a14fb7e5 100644 --- a/libguile/gc.c +++ b/libguile/gc.c @@ -1,4 +1,5 @@ -/* 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 @@ -27,6 +28,7 @@ #include #include #include +#include #include #ifdef __ia64__ @@ -46,7 +48,6 @@ extern unsigned long * __libc_ia64_register_backing_store_base; #include "libguile/root.h" #include "libguile/strings.h" #include "libguile/vectors.h" -#include "libguile/weaks.h" #include "libguile/hashtab.h" #include "libguile/tags.h" @@ -65,10 +66,6 @@ extern unsigned long * __libc_ia64_register_backing_store_base; #include "libguile/debug-malloc.h" #endif -#ifdef HAVE_MALLOC_H -#include -#endif - #ifdef HAVE_UNISTD_H #include #endif @@ -83,14 +80,10 @@ int scm_expensive_debug_cell_accesses_p = 0; */ 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) @@ -195,31 +188,6 @@ SCM_DEFINE (scm_set_debug_cell_accesses_x, "set-debug-cell-accesses!", 1, 0, 0, -/* 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 - - /* Hooks. */ scm_t_c_hook scm_before_gc_c_hook; scm_t_c_hook scm_before_mark_c_hook; @@ -231,6 +199,10 @@ scm_t_c_hook scm_after_gc_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); } @@ -310,7 +282,7 @@ SCM_DEFINE (scm_gc_stats, "gc-stats", 0, 0, 0, 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)), @@ -384,6 +356,9 @@ SCM_DEFINE (scm_gc, "gc", 0, 0, 0, #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 @@ -391,9 +366,6 @@ SCM_DEFINE (scm_gc, "gc", 0, 0, 0, void scm_i_gc (const char *what) { -#ifndef HAVE_GC_SET_START_CALLBACK - run_before_gc_c_hook (); -#endif GC_gcollect (); } @@ -611,11 +583,13 @@ scm_getenv_int (const char *var, int def) 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 (); @@ -774,7 +748,7 @@ static size_t get_image_size (void) { unsigned long size, resident, share; - size_t ret; + size_t ret = 0; FILE *fp = fopen ("/proc/self/statm", "r"); @@ -787,6 +761,10 @@ get_image_size (void) 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. @@ -832,10 +810,14 @@ adjust_gc_frequency (void * hook_data SCM_UNUSED, 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); @@ -895,6 +877,33 @@ adjust_gc_frequency (void * hook_data SCM_UNUSED, 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); + } +} + @@ -913,16 +922,16 @@ scm_i_tag_name (scm_t_bits tag) 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: @@ -992,11 +1001,12 @@ scm_init_gc () 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" }