* *.[hc]: add Emacs magic at the end of file, to ensure GNU
[bpt/guile.git] / libguile / guardians.c
CommitLineData
67b2561b 1/* Copyright (C) 1998, 1999 Free Software Foundation, Inc.
e1f2bf99
MD
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
40 * If you do not wish that, delete this exception notice. */
1bbd0b84
GB
41
42/* Software engineering face-lift by Greg J. Badros, 11-Dec-1999,
43 gjb@cs.washington.edu, http://www.cs.washington.edu/homes/gjb */
44
e1f2bf99
MD
45\f
46
47/* This is an implementation of guardians as described in
48 * R. Kent Dybvig, Carl Bruggeman, and David Eby (1993) "Guardians in
49 * a Generation-Based Garbage Collector" ACM SIGPLAN Conference on
50 * Programming Language Design and Implementation, June 1993
51 * ftp://ftp.cs.indiana.edu/pub/scheme-repository/doc/pubs/guardians.ps.gz
52 *
53 * Author: Michael N. Livshin
54 * Modified by: Mikael Djurfeldt
55 */
56
57#include <stdio.h>
58#include <assert.h>
59
60#include "_scm.h"
f04d8caf 61#include "ports.h"
e1f2bf99
MD
62#include "print.h"
63#include "smob.h"
003d1fd0 64#include "vectors.h"
e1f2bf99 65
b6791b2e 66#include "validate.h"
e1f2bf99
MD
67#include "guardians.h"
68
69static long scm_tc16_guardian;
70
71/* The live and zombies FIFOs are implemented as tconcs as described
72 in Dybvig's paper. This decouples addition and removal of elements
73 so that no synchronization between these needs to take place.
74*/
75#define TCONC_IN(tc, obj, pair) \
d3a6bc94 76do { \
e1f2bf99
MD
77 SCM_SETCAR ((tc).tail, obj); \
78 SCM_SETCAR (pair, SCM_BOOL_F); \
79 SCM_SETCDR (pair, SCM_BOOL_F); \
80 SCM_SETCDR ((tc).tail, pair); \
81 (tc).tail = pair; \
d3a6bc94 82} while (0)
e1f2bf99
MD
83
84#define TCONC_OUT(tc, res) \
d3a6bc94 85do { \
e1f2bf99
MD
86 (res) = SCM_CAR ((tc).head); \
87 (tc).head = SCM_CDR ((tc).head); \
d3a6bc94 88} while (0)
e1f2bf99
MD
89
90#define TCONC_EMPTYP(tc) ((tc).head == (tc).tail)
91
92typedef struct tconc_t
93{
94 SCM head;
95 SCM tail;
96} tconc_t;
97
98typedef struct guardian_t
99{
100 tconc_t live;
101 tconc_t zombies;
01a119ac 102 struct guardian_t *next;
e1f2bf99
MD
103} guardian_t;
104
105#define GUARDIAN(x) ((guardian_t *) SCM_CDR (x))
106#define GUARDIAN_LIVE(x) (GUARDIAN (x)->live)
107#define GUARDIAN_ZOMBIES(x) (GUARDIAN (x)->zombies)
01a119ac 108#define GUARDIAN_NEXT(x) (GUARDIAN (x)->next)
e1f2bf99 109
01a119ac
JB
110static guardian_t *first_live_guardian = NULL;
111static guardian_t **current_link_field = NULL;
e1f2bf99
MD
112
113static SCM
114g_mark (SCM ptr)
115{
01a119ac
JB
116 *current_link_field = GUARDIAN (ptr);
117 current_link_field = &GUARDIAN_NEXT (ptr);
118 GUARDIAN_NEXT (ptr) = NULL;
119
e1f2bf99
MD
120 /* Can't mark zombies here since they can refer to objects which are
121 living dead, thereby preventing them to join the zombies. */
122 return SCM_BOOL_F;
123}
124
e1f2bf99
MD
125static int
126g_print (SCM exp, SCM port, scm_print_state *pstate)
127{
128 char buf[256];
129 sprintf (buf, "#<guardian live objs: %lu zombies: %lu>",
130 scm_ilength (SCM_CDR (GUARDIAN_LIVE (exp).head)),
131 scm_ilength (SCM_CDR (GUARDIAN_ZOMBIES (exp).head)));
132 scm_puts (buf, port);
133
134 return 1;
135}
136
e1f2bf99
MD
137#define CCLO_G(cclo) (SCM_VELTS (cclo)[1])
138
139static SCM
140guard (SCM cclo, SCM arg)
141{
142 if (!SCM_UNBNDP (arg))
143 {
144 scm_guard (cclo, arg);
145 return SCM_UNSPECIFIED;
146 }
147 else
148 return scm_get_one_zombie (cclo);
149}
150
151static SCM guard1;
152
a1ec6916 153SCM_DEFINE (scm_make_guardian, "make-guardian", 0, 0, 0,
1bbd0b84 154 (),
da4a1dba
GB
155 "Return a new guardian object.\n"
156 "A guardian allows dynamically allocated objects to be\n"
157 "saved from deallocation by the garbage collector so that\n"
158 "clean up or other actions can be performed using the data\n"
159 "stored within the objects.\n"
160 "See R. Kent Dybvig, Carl Bruggeman, and David Eby (1993)\n"
161 "\"Guardians in a Generation-Based Garbage Collector\".\n"
162 "ACM SIGPLAN Conference on Programming Language Design\n"
b450f070 163 "and Implementation, June 1993\n.")
1bbd0b84 164#define FUNC_NAME s_scm_make_guardian
e1f2bf99
MD
165{
166 SCM cclo = scm_makcclo (guard1, 2L);
1bbd0b84 167 guardian_t *g = SCM_MUST_MALLOC_TYPE(guardian_t);
e1f2bf99
MD
168 SCM z1 = scm_cons (SCM_BOOL_F, SCM_BOOL_F);
169 SCM z2 = scm_cons (SCM_BOOL_F, SCM_BOOL_F);
170 SCM z;
e1f2bf99
MD
171 /* A tconc starts out with one tail pair. */
172 g->live.head = g->live.tail = z1;
173 g->zombies.head = g->zombies.tail = z2;
23a62151
MD
174
175 SCM_NEWSMOB (z, scm_tc16_guardian, g);
e1f2bf99
MD
176
177 CCLO_G (cclo) = z;
178
179 return cclo;
180}
1bbd0b84 181#undef FUNC_NAME
e1f2bf99
MD
182
183void
184scm_guardian_gc_init()
185{
01a119ac
JB
186 current_link_field = &first_live_guardian;
187 first_live_guardian = NULL;
e1f2bf99
MD
188}
189
190void
191scm_guardian_zombify ()
192{
01a119ac 193 guardian_t *g;
55b7e0bd
JB
194
195 /* Note that new guardians may be stuck on the end of the live
196 guardian list as we run this loop. As we move unmarked objects
197 to the zombie list and mark them, we may find some guarded
198 guardians. The guardian mark function will stick them on the end
199 of this list, so they'll be processed properly. */
01a119ac 200 for (g = first_live_guardian; g; g = g->next)
e1f2bf99 201 {
67b2561b
JB
202 /* Scan the live list for unmarked objects, and move them to the
203 zombies tconc. */
01a119ac 204 SCM tconc_tail = g->live.tail;
67b2561b 205 SCM *prev_ptr = &g->live.head;
01a119ac 206 SCM pair = g->live.head;
67b2561b 207
e1f2bf99
MD
208 while (pair != tconc_tail)
209 {
210 SCM next_pair = SCM_CDR (pair);
211
212 if (SCM_NMARKEDP (SCM_CAR (pair)))
213 {
214 /* got you, zombie! */
215
216 /* out of the live list! */
67b2561b 217 *prev_ptr = next_pair;
e1f2bf99
MD
218
219 /* to the zombie list! */
01a119ac 220 TCONC_IN (g->zombies, SCM_CAR (pair), pair);
e1f2bf99
MD
221 }
222 else
67b2561b 223 prev_ptr = SCM_CDRLOC (pair);
e1f2bf99
MD
224
225 pair = next_pair;
226 }
67b2561b
JB
227
228 /* Mark the cells of the live list. */
229 for (pair = g->live.head; SCM_NIMP (pair); pair = SCM_GCCDR (pair))
230 SCM_SETGCMARK (pair);
55b7e0bd
JB
231
232 /* Bring the zombies back from the dead. */
01a119ac 233 scm_gc_mark (g->zombies.head);
e1f2bf99
MD
234 }
235}
236
237void
238scm_guard (SCM guardian, SCM obj)
239{
240 SCM g = CCLO_G (guardian);
241
242 if (SCM_NIMP (obj))
243 {
244 SCM z;
245
246 SCM_NEWCELL (z);
247
248 /* This critical section barrier will be replaced by a mutex. */
249 SCM_DEFER_INTS;
250 TCONC_IN (GUARDIAN_LIVE (g), obj, z);
251 SCM_ALLOW_INTS;
252 }
253}
254
255SCM
256scm_get_one_zombie (SCM guardian)
257{
258 SCM g = CCLO_G (guardian);
259 SCM res = SCM_BOOL_F;
260
261 /* This critical section barrier will be replaced by a mutex. */
262 SCM_DEFER_INTS;
263 if (!TCONC_EMPTYP (GUARDIAN_ZOMBIES (g)))
264 TCONC_OUT (GUARDIAN_ZOMBIES (g), res);
265 SCM_ALLOW_INTS;
266
267 return res;
268}
269
270void
271scm_init_guardian()
272{
23a62151
MD
273 scm_tc16_guardian = scm_make_smob_type_mfpe ("guardian", sizeof (guardian_t),
274 g_mark, NULL, g_print, NULL);
e1f2bf99
MD
275 guard1 = scm_make_subr_opt ("guardian", scm_tc7_subr_2o, guard, 0);
276
277#include "guardians.x"
278}
89e00824
ML
279
280/*
281 Local Variables:
282 c-file-style: "gnu"
283 End:
284*/