1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-07-02 23:50:47 +02:00

Replace after-gc-hook with {add,remove}-after-gc-callback!

* libguile/gc.c:
(scm_gc_event_listener_restarting_mutators):
(after_gc_async_thunk):
(scm_init_gc): Instead of using a hook for after-gc callbacks, just use
a list of thunks.  Will allow us to move hooks to Scheme.
(add-after-gc-callback!, remove-after-gc-callback!): New functions.
* libguile/gc.h (scm_after_gc_hook): Remove.
* libguile/scmsigs.c (signal_delivery_thread): Update comment.
* module/statprof.scm (gcprof):
* test-suite/tests/gc.test ("gc"): Update to use new functions.
This commit is contained in:
Andy Wingo 2025-06-16 10:01:16 +02:00
parent f436e550ea
commit 04fdc33a54
6 changed files with 41 additions and 23 deletions

View file

@ -40,13 +40,13 @@
#include "gen-scmconfig.h" #include "gen-scmconfig.h"
#include "gsubr.h" #include "gsubr.h"
#include "hashtab.h" #include "hashtab.h"
#include "hooks.h"
#include "init.h" #include "init.h"
#include "list.h" #include "list.h"
#include "modules.h" #include "modules.h"
#include "numbers.h" #include "numbers.h"
#include "pairs.h" #include "pairs.h"
#include "ports.h" #include "ports.h"
#include "procs.h"
#include "simpos.h" #include "simpos.h"
#include "smob.h" #include "smob.h"
#include "stackchk.h" #include "stackchk.h"
@ -106,8 +106,7 @@ scm_t_c_hook scm_before_sweep_c_hook;
scm_t_c_hook scm_after_sweep_c_hook; scm_t_c_hook scm_after_sweep_c_hook;
scm_t_c_hook scm_after_gc_c_hook; scm_t_c_hook scm_after_gc_c_hook;
SCM scm_after_gc_hook; static SCM after_gc_thunks = SCM_EOL;
static SCM after_gc_async_cell; static SCM after_gc_async_cell;
/* This counter is decremented at each off-heap allocation. When it /* This counter is decremented at each off-heap allocation. When it
@ -195,9 +194,7 @@ scm_gc_event_listener_restarting_mutators (void *data)
/* If there are Scheme hooks and we have a current Guile thread, /* If there are Scheme hooks and we have a current Guile thread,
enqueue those to be run on the current thread. */ enqueue those to be run on the current thread. */
scm_thread *t = SCM_I_CURRENT_THREAD; scm_thread *t = SCM_I_CURRENT_THREAD;
if (t && scm_initialized_p && if (t && !scm_is_null (after_gc_thunks))
scm_is_false (SCM_CDR (after_gc_async_cell)) &&
scm_is_false (scm_hook_empty_p (scm_after_gc_hook)))
{ {
SCM_SETCDR (after_gc_async_cell, t->pending_asyncs); SCM_SETCDR (after_gc_async_cell, t->pending_asyncs);
t->pending_asyncs = after_gc_async_cell; t->pending_asyncs = after_gc_async_cell;
@ -381,6 +378,32 @@ SCM_DEFINE (scm_gc_stats, "gc-stats", 0, 0, 0,
#undef FUNC_NAME #undef FUNC_NAME
SCM_DEFINE_STATIC (scm_add_after_gc_callback_x, "add-after-gc-callback!",
1, 0, 0, (SCM thunk),
"Add @var{thunk} to the set of functions that will be "
"called after GC, by the thread that caused GC.")
#define FUNC_NAME s_scm_add_after_gc_callback_x
{
SCM_VALIDATE_THUNK (1, thunk);
after_gc_thunks = scm_cons (thunk, after_gc_thunks);
return SCM_UNSPECIFIED;
}
#undef FUNC_NAME
SCM_DEFINE_STATIC (scm_remove_after_gc_callback_x, "remove-after-gc-callback!",
1, 0, 0, (SCM thunk),
"Remove @var{thunk} from the set of functions that will be "
"called after GC.")
#define FUNC_NAME s_scm_remove_after_gc_callback_x
{
SCM_VALIDATE_THUNK (1, thunk);
after_gc_thunks = scm_delq1_x (thunk, after_gc_thunks);
return SCM_UNSPECIFIED;
}
#undef FUNC_NAME
SCM_DEFINE (scm_gc_dump, "gc-dump", 0, 0, 0, SCM_DEFINE (scm_gc_dump, "gc-dump", 0, 0, 0,
(void), (void),
"Dump information about the garbage collector's internal data " "Dump information about the garbage collector's internal data "
@ -672,8 +695,8 @@ scm_gc_register_allocation (size_t size)
static SCM static SCM
after_gc_async_thunk (void) after_gc_async_thunk (void)
{ {
/* Fun, no? Hook-run *and* run-hook? */ for (SCM ls = after_gc_thunks; !scm_is_null (ls); ls = scm_cdr (ls))
scm_c_run_hook (scm_after_gc_hook, SCM_EOL); scm_call_0 (scm_car (ls));
return SCM_UNSPECIFIED; return SCM_UNSPECIFIED;
} }
@ -681,9 +704,6 @@ after_gc_async_thunk (void)
void void
scm_init_gc () scm_init_gc ()
{ {
scm_after_gc_hook = scm_make_hook (SCM_INUM0);
scm_c_define ("after-gc-hook", scm_after_gc_hook);
/* When the async is to run, the cdr of the gc_async pair gets set to /* When the async is to run, the cdr of the gc_async pair gets set to
the asyncs queue of the current thread. */ the asyncs queue of the current thread. */
after_gc_async_cell = scm_cons (scm_c_make_gsubr ("%after-gc-thunk", 0, 0, 0, after_gc_async_cell = scm_cons (scm_c_make_gsubr ("%after-gc-thunk", 0, 0, 0,

View file

@ -88,8 +88,6 @@ typedef struct scm_t_cell
SCM_API unsigned long scm_gc_ports_collected; SCM_API unsigned long scm_gc_ports_collected;
SCM_API SCM scm_after_gc_hook;
SCM_API scm_t_c_hook scm_before_gc_c_hook; SCM_API scm_t_c_hook scm_before_gc_c_hook;
SCM_API scm_t_c_hook scm_before_mark_c_hook; SCM_API scm_t_c_hook scm_before_mark_c_hook;
SCM_API scm_t_c_hook scm_before_sweep_c_hook; SCM_API scm_t_c_hook scm_before_sweep_c_hook;

View file

@ -174,8 +174,8 @@ signal_delivery_thread (void *data)
block indefinitely waiting for a signal to arrive. For example block indefinitely waiting for a signal to arrive. For example
it can happen that the garbage collector is triggered while it can happen that the garbage collector is triggered while
marking the signal handler for future execution. Due to the marking the signal handler for future execution. Due to the
way the after-gc-hook is designed, without a call to way the after-gc callback is designed, without a call to
scm_async_tick, the after-gc-hook will not be triggered. */ scm_async_tick, the after-gc callback will not be triggered. */
scm_async_tick (); scm_async_tick ();
scm_without_guile (read_signal_pipe_data, &sigdata); scm_without_guile (read_signal_pipe_data, &sigdata);

View file

@ -139,7 +139,7 @@ the allocation limit."
(lambda () (lambda ()
(dynamic-wind (dynamic-wind
(lambda () (lambda ()
(add-hook! after-gc-hook check-allocation)) (add-after-gc-callback! check-allocation))
(lambda () (lambda ()
(call-with-stack-overflow-handler (call-with-stack-overflow-handler
;; The limit is in "words", which used to be 4 or 8 but now ;; The limit is in "words", which used to be 4 or 8 but now
@ -148,7 +148,7 @@ the allocation limit."
thunk thunk
(lambda () (abort-to-prompt tag)))) (lambda () (abort-to-prompt tag))))
(lambda () (lambda ()
(remove-hook! after-gc-hook check-allocation)))) (remove-after-gc-callback! check-allocation))))
(lambda (k) (lambda (k)
(limit-reached))))) (limit-reached)))))

View file

@ -1,7 +1,7 @@
;;;; (statprof) -- a statistical profiler for Guile ;;;; (statprof) -- a statistical profiler for Guile
;;;; -*-scheme-*- ;;;; -*-scheme-*-
;;;; ;;;;
;;;; Copyright (C) 2009, 2010, 2011, 2013-2018, 2020 Free Software Foundation, Inc. ;;;; Copyright (C) 2009, 2010, 2011, 2013-2018, 2020, 2025 Free Software Foundation, Inc.
;;;; Copyright (C) 2004, 2009 Andy Wingo <wingo at pobox dot com> ;;;; Copyright (C) 2004, 2009 Andy Wingo <wingo at pobox dot com>
;;;; Copyright (C) 2001 Rob Browning <rlb at defaultvalue dot org> ;;;; Copyright (C) 2001 Rob Browning <rlb at defaultvalue dot org>
;;;; ;;;;
@ -888,14 +888,14 @@ times."
(set-profile-level! state 1) (set-profile-level! state 1)
(set-last-start-time! state (get-internal-run-time)) (set-last-start-time! state (get-internal-run-time))
(set-gc-time-taken! state (assq-ref (gc-stats) 'gc-time-taken)) (set-gc-time-taken! state (assq-ref (gc-stats) 'gc-time-taken))
(add-hook! after-gc-hook gc-callback)) (add-after-gc-callback! gc-callback))
(lambda () (lambda ()
(let lp ((i loop)) (let lp ((i loop))
(unless (zero? i) (unless (zero? i)
(call-thunk thunk) (call-thunk thunk)
(lp (1- i))))) (lp (1- i)))))
(lambda () (lambda ()
(remove-hook! after-gc-hook gc-callback) (remove-after-gc-callback! gc-callback)
(set-gc-time-taken! state (set-gc-time-taken! state
(- (assq-ref (gc-stats) 'gc-time-taken) (- (assq-ref (gc-stats) 'gc-time-taken)
(gc-time-taken state))) (gc-time-taken state)))

View file

@ -63,12 +63,12 @@
(with-test-prefix "gc" (with-test-prefix "gc"
(pass-if "after-gc-hook gets called" (pass-if "after-gc callback gets called"
(let* ((foo #f) (let* ((foo #f)
(thunk (lambda () (set! foo #t)))) (thunk (lambda () (set! foo #t))))
(add-hook! after-gc-hook thunk) (add-after-gc-callback! thunk)
(gc) (gc)
(remove-hook! after-gc-hook thunk) (remove-after-gc-callback! thunk)
foo)) foo))
(pass-if "Unused modules are removed" (pass-if "Unused modules are removed"