1 /* Copyright (C) 2012, 2014 Free Software Foundation, Inc.
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 #include "libguile/bdw-gc.h"
27 #include "libguile/_scm.h"
28 #include "libguile/finalizers.h"
29 #include "libguile/gc.h"
30 #include "libguile/threads.h"
34 static int automatic_finalization_p
= 1;
36 static size_t finalization_count
;
42 scm_i_set_finalizer (void *obj
, scm_t_finalizer_proc proc
, void *data
)
44 GC_finalization_proc prev
;
46 GC_REGISTER_FINALIZER_NO_ORDER (obj
, proc
, data
, &prev
, &prev_data
);
49 struct scm_t_chained_finalizer
52 scm_t_finalizer_proc proc
;
54 scm_t_finalizer_proc prev
;
59 chained_finalizer (void *obj
, void *data
)
61 struct scm_t_chained_finalizer
*chained_data
= data
;
62 if (chained_data
->resuscitating_p
)
64 if (chained_data
->prev
)
65 scm_i_set_finalizer (obj
, chained_data
->prev
, chained_data
->prev_data
);
66 chained_data
->proc (obj
, chained_data
->data
);
70 chained_data
->proc (obj
, chained_data
->data
);
71 if (chained_data
->prev
)
72 chained_data
->prev (obj
, chained_data
->prev_data
);
77 scm_i_add_resuscitator (void *obj
, scm_t_finalizer_proc proc
, void *data
)
79 struct scm_t_chained_finalizer
*chained_data
;
80 chained_data
= scm_gc_malloc (sizeof (*chained_data
), "chained finalizer");
81 chained_data
->resuscitating_p
= 1;
82 chained_data
->proc
= proc
;
83 chained_data
->data
= data
;
84 GC_REGISTER_FINALIZER_NO_ORDER (obj
, chained_finalizer
, chained_data
,
86 &chained_data
->prev_data
);
90 shuffle_resuscitators_to_front (struct scm_t_chained_finalizer
*cd
)
92 while (cd
->prev
== chained_finalizer
)
94 struct scm_t_chained_finalizer
*prev
= cd
->prev_data
;
95 scm_t_finalizer_proc proc
= cd
->proc
;
96 void *data
= cd
->data
;
98 if (!prev
->resuscitating_p
)
101 cd
->resuscitating_p
= 1;
102 cd
->proc
= prev
->proc
;
103 cd
->data
= prev
->data
;
105 prev
->resuscitating_p
= 0;
114 scm_i_add_finalizer (void *obj
, scm_t_finalizer_proc proc
, void *data
)
116 struct scm_t_chained_finalizer
*chained_data
;
117 chained_data
= scm_gc_malloc (sizeof (*chained_data
), "chained finalizer");
118 chained_data
->resuscitating_p
= 0;
119 chained_data
->proc
= proc
;
120 chained_data
->data
= data
;
121 GC_REGISTER_FINALIZER_NO_ORDER (obj
, chained_finalizer
, chained_data
,
123 &chained_data
->prev_data
);
124 shuffle_resuscitators_to_front (chained_data
);
130 static SCM finalizer_async_cell
;
133 run_finalizers_async_thunk (void)
135 scm_run_finalizers ();
136 return SCM_UNSPECIFIED
;
140 /* The function queue_finalizer_async is run by the GC when there are
141 * objects to finalize. It will enqueue an asynchronous call to
142 * GC_invoke_finalizers() at the next SCM_TICK in this thread.
145 queue_finalizer_async (void)
147 scm_i_thread
*t
= SCM_I_CURRENT_THREAD
;
148 static scm_i_pthread_mutex_t lock
= SCM_I_PTHREAD_MUTEX_INITIALIZER
;
150 scm_i_pthread_mutex_lock (&lock
);
151 /* If t is NULL, that could be because we're allocating in
152 threads.c:guilify_self_1. In that case, rely on the
153 GC_invoke_finalizers call there after the thread spins up. */
154 if (t
&& scm_is_false (SCM_CDR (finalizer_async_cell
)))
156 SCM_SETCDR (finalizer_async_cell
, t
->active_asyncs
);
157 t
->active_asyncs
= finalizer_async_cell
;
158 t
->pending_asyncs
= 1;
160 scm_i_pthread_mutex_unlock (&lock
);
166 #ifndef HAVE_GC_SET_FINALIZER_NOTIFIER
168 GC_set_finalizer_notifier (void (*notifier
) (void))
170 GC_finalizer_notifier
= notifier
;
178 scm_set_automatic_finalization_enabled (int enabled_p
)
180 int was_enabled_p
= automatic_finalization_p
;
182 if (enabled_p
== was_enabled_p
)
183 return was_enabled_p
;
185 if (!scm_initialized_p
)
187 automatic_finalization_p
= enabled_p
;
188 return was_enabled_p
;
191 GC_set_finalizer_notifier (enabled_p
? queue_finalizer_async
: 0);
193 automatic_finalization_p
= enabled_p
;
195 return was_enabled_p
;
199 scm_run_finalizers (void)
201 int finalized
= GC_invoke_finalizers ();
203 finalization_count
+= finalized
;
212 scm_init_finalizers (void)
214 /* When the async is to run, the cdr of the pair gets set to the
215 asyncs queue of the current thread. */
216 finalizer_async_cell
=
217 scm_cons (scm_c_make_gsubr ("%run-finalizers", 0, 0, 0,
218 run_finalizers_async_thunk
),
221 if (automatic_finalization_p
)
222 GC_set_finalizer_notifier (queue_finalizer_async
);