gc-2.4 tarball import
[platform/upstream/libgc.git] / finalize.c
1 /*
2  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
3  * Copyright (c) 1991, 1992 by Xerox Corporation.  All rights reserved.
4
5  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
6  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
7  *
8  * Permission is hereby granted to copy this garbage collector for any purpose,
9  * provided the above notices are retained on all copies.
10  */
11 # define I_HIDE_POINTERS
12 # include "gc.h"
13 # include "gc_private.h"
14 # ifdef __STDC__
15     typedef void * void_star;
16 # else
17     typedef char * void_star;
18 # endif
19
20 # define LOG_TSIZE 7
21 # define TSIZE (1 << LOG_TSIZE)
22 # define HASH(addr) \
23     ((((word)(addr) >> 3) ^ ((word)(addr) >> (3+LOG_TSIZE))) \
24     & (TSIZE - 1))
25     
26 static struct disappearing_link {
27     word dl_hidden_base;        /* Pointer to object base       */
28     word dl_offset;     /* byte offset within object.   */
29     struct disappearing_link * dl_next;
30 } * dl_head[TSIZE] = {0};
31
32 static struct finalizable_object {
33     word fo_hidden_base;        /* Pointer to object base       */
34     GC_finalization_proc fo_fn; /* Finalizer.                   */
35     ptr_t fo_client_data;
36     word fo_object_size;        /* In bytes.                    */
37     struct finalizable_object * fo_next;
38 } * fo_head[TSIZE] = {0};
39
40 # define ALLOC(x, t) t *x = (t *)GC_malloc(sizeof (t))
41
42 int GC_register_disappearing_link(link)
43 void_star * link;
44 {
45     ptr_t base;
46     unsigned long offset;
47     struct disappearing_link *curr_dl;
48     int index;
49     /* Allocate before acquiring lock */
50       ALLOC(new_dl, struct disappearing_link);
51     DCL_LOCK_STATE;
52       
53     DISABLE_SIGNALS();
54     LOCK();
55     base = (ptr_t)GC_base((void_star)link);
56     index = HASH(base);
57     offset = (ptr_t)link - base;
58     if (base == 0 || ((word)link & (ALIGNMENT-1)))
59                 ABORT("Bad arg to GC_register_disappearing_link");
60     curr_dl = dl_head[index];
61     for (curr_dl = dl_head[index]; curr_dl != 0; curr_dl = curr_dl -> dl_next) {
62         if (curr_dl -> dl_hidden_base == HIDE_POINTER(base)
63             && curr_dl -> dl_offset == offset) {
64             UNLOCK();
65             ENABLE_SIGNALS();
66             GC_free((extern_ptr_t)new_dl);
67             return(1);
68         }
69     }
70     {
71         new_dl -> dl_hidden_base = HIDE_POINTER(base);
72         new_dl -> dl_offset = offset;
73         new_dl -> dl_next = dl_head[index];
74         dl_head[index] = new_dl;
75         UNLOCK();
76         ENABLE_SIGNALS();
77         return(0);
78     }
79 }
80
81
82 int GC_unregister_disappearing_link(link)
83 void_star * link;
84 {
85     ptr_t base;
86     unsigned long offset;
87     struct disappearing_link *curr_dl, *prev_dl;
88     int index;
89     DCL_LOCK_STATE;
90     
91     DISABLE_SIGNALS();
92     LOCK();
93     base = (ptr_t)GC_base((void_star)link);
94     index = HASH(base);
95     offset = (ptr_t)link - base;
96     if (base == 0 || ((unsigned long)link & (ALIGNMENT-1)))
97         return(0);
98     prev_dl = 0; curr_dl = dl_head[index];
99     while (curr_dl != 0) {
100         if (curr_dl -> dl_hidden_base == HIDE_POINTER(base)
101             && curr_dl -> dl_offset == offset) {
102             if (prev_dl == 0) {
103                 dl_head[index] = curr_dl -> dl_next;
104             } else {
105                prev_dl -> dl_next = curr_dl -> dl_next;
106             }
107             UNLOCK();
108             ENABLE_SIGNALS();
109             GC_free((extern_ptr_t)curr_dl);
110             return(1);
111         }
112         curr_dl = curr_dl -> dl_next;
113         prev_dl = curr_dl;
114     }
115     UNLOCK();
116     ENABLE_SIGNALS();
117     return(0);
118 }
119
120 bool GC_is_marked(p)
121 ptr_t p;
122 {
123     register struct hblk *h = HBLKPTR(p);
124     register hdr * hhdr = HDR(h);
125     register int word_no = (word *)p - (word *)h;
126     
127     return(mark_bit_from_hdr(hhdr, word_no));
128 }
129
130 void GC_set_mark_bit(p)
131 ptr_t p;
132 {
133     register struct hblk *h = HBLKPTR(p);
134     register hdr * hhdr = HDR(h);
135     register int word_no = (word *)p - (word *)h;
136     
137     set_mark_bit_from_hdr(hhdr, word_no);
138 }
139
140 void GC_clear_mark_bit(p)
141 ptr_t p;
142 {
143     register struct hblk *h = HBLKPTR(p);
144     register hdr * hhdr = HDR(h);
145     register int word_no = (word *)p - (word *)h;
146     
147     clear_mark_bit_from_hdr(hhdr, word_no);
148 }
149
150 void GC_register_finalizer(obj, fn, cd, ofn, ocd)
151 void_star obj;
152 GC_finalization_proc fn;
153 void_star cd;
154 GC_finalization_proc * ofn;
155 void_star * ocd;
156 {
157     ptr_t base;
158     struct finalizable_object * curr_fo, * prev_fo;
159     int index;
160     /* Allocate before acquiring lock */
161       ALLOC(new_fo, struct finalizable_object);
162     DCL_LOCK_STATE;
163     
164     DISABLE_SIGNALS();
165     LOCK();
166     base = (ptr_t)GC_base((void_star)obj);
167     index = HASH(base);
168     if (base != obj)
169                 ABORT("Bad arg to GC_register_finalizer");
170     prev_fo = 0; curr_fo = fo_head[index];
171     while (curr_fo != 0) {
172         if (curr_fo -> fo_hidden_base == HIDE_POINTER(base)) {
173             if (ofn) *ofn = curr_fo -> fo_fn;
174             if (ocd) *ocd = (void_star) curr_fo -> fo_client_data;
175             if (fn == 0) {
176                 /* Delete the structure for base. */
177                   if (prev_fo == 0) {
178                     fo_head[index] = curr_fo -> fo_next;
179                   } else {
180                     prev_fo -> fo_next = curr_fo -> fo_next;
181                   }
182                   UNLOCK();
183                   ENABLE_SIGNALS();
184                   GC_free((extern_ptr_t)curr_fo);
185             } else {
186                 curr_fo -> fo_fn = fn;
187                 curr_fo -> fo_client_data = (ptr_t)cd;
188                 UNLOCK();
189                 ENABLE_SIGNALS();
190             }
191             GC_free((extern_ptr_t)new_fo);
192             return;
193         }
194         curr_fo = curr_fo -> fo_next;
195         prev_fo = curr_fo;
196     }
197     {
198         if (ofn) *ofn = 0;
199         if (ocd) *ocd = 0;
200         if (fn == 0) {
201             UNLOCK();
202             ENABLE_SIGNALS();
203             GC_free((extern_ptr_t)new_fo);
204             return;
205         }
206         new_fo -> fo_hidden_base = (word)HIDE_POINTER(base);
207         new_fo -> fo_fn = fn;
208         new_fo -> fo_client_data = (ptr_t)cd;
209         new_fo -> fo_object_size = GC_size(base);
210         new_fo -> fo_next = fo_head[index];
211         fo_head[index] = new_fo;
212     }
213     UNLOCK();
214     ENABLE_SIGNALS();
215 }
216
217 /* Called with world stopped.  Cause disappearing links to disappear,   */
218 /* and invoke finalizers.                                               */
219 void GC_finalize()
220 {
221     struct disappearing_link * curr_dl, * prev_dl, * next_dl;
222     struct finalizable_object * curr_fo, * prev_fo, * next_fo;
223     ptr_t real_ptr;
224     register int i;
225     
226   /* Make disappearing links disappear */
227     for (i = 0; i < TSIZE; i++) {
228       curr_dl = dl_head[i];
229       prev_dl = 0;
230       while (curr_dl != 0) {
231         real_ptr = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_base);
232         if (!GC_is_marked(real_ptr)) {
233             *(word *)(real_ptr + curr_dl -> dl_offset) = 0;
234             next_dl = curr_dl -> dl_next;
235             if (prev_dl == 0) {
236                 dl_head[i] = next_dl;
237             } else {
238                 prev_dl -> dl_next = next_dl;
239             }
240             GC_clear_mark_bit((ptr_t)curr_dl);
241             curr_dl = next_dl;
242         } else {
243             prev_dl = curr_dl;
244             curr_dl = curr_dl -> dl_next;
245         }
246       }
247     }
248   /* Mark all objects reachable via chains of 1 or more pointers        */
249   /* from finalizable objects.                                          */
250     for (i = 0; i < TSIZE; i++) {
251       for (curr_fo = fo_head[i]; curr_fo != 0; curr_fo = curr_fo -> fo_next) {
252         real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
253         if (!GC_is_marked(real_ptr)) {
254             GC_mark_all(real_ptr, real_ptr + curr_fo -> fo_object_size);
255         }
256         /* 
257         if (GC_is_marked(real_ptr)) {
258             --> Report finalization cycle here, if desired
259         }
260         */
261       }
262     }
263   /* Invoke finalization code for all objects that are still            */
264   /* unreachable.                                                       */
265     for (i = 0; i < TSIZE; i++) {
266       curr_fo = fo_head[i];
267       prev_fo = 0;
268       while (curr_fo != 0) {
269         real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
270         if (!GC_is_marked(real_ptr)) {
271             (*(curr_fo -> fo_fn))(real_ptr, curr_fo -> fo_client_data);
272             GC_set_mark_bit(real_ptr);
273             next_fo = curr_fo -> fo_next;
274             if (prev_fo == 0) {
275                 fo_head[i] = next_fo;
276             } else {
277                 prev_fo -> fo_next = next_fo;
278             }
279             if (!GC_is_marked((ptr_t)curr_fo)) {
280                 ABORT("GC_finalize: found accessible unmarked object\n");
281             }
282             GC_clear_mark_bit((ptr_t)curr_fo);
283             curr_fo = next_fo;
284         } else {
285             prev_fo = curr_fo;
286             curr_fo = curr_fo -> fo_next;
287         }
288       }
289     }
290 }
291
292 # ifdef __STDC__
293     void_star GC_call_with_alloc_lock(GC_fn_type fn, void_star client_data)
294 # else
295     void_star GC_call_with_alloc_lock(fn, client_data)
296     GC_fn_type fn;
297     void_star client_data;
298 # endif
299 {
300     DCL_LOCK_STATE;
301     
302     DISABLE_SIGNALS();
303     LOCK();
304     (*fn)(client_data);
305     UNLOCK();
306     ENABLE_SIGNALS();
307 }
308