gc3.6 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_obj;         /* Pointer to object base       */
28     word dl_hidden_link;        /* Field to be cleared.         */
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 # ifdef SRC_M3
41 void GC_push_finalizer_structures()
42 {
43     GC_push_all((ptr_t)dl_head, (ptr_t)(dl_head + TSIZE));
44     GC_push_all((ptr_t)fo_head, (ptr_t)(fo_head + TSIZE));
45 }
46 # endif
47
48 # define ALLOC(x, t) t *x = (t *)GC_malloc(sizeof (t))
49
50 int GC_register_disappearing_link(link)
51 void_star * link;
52 {
53     ptr_t base;
54     
55     base = (ptr_t)GC_base((void_star)link);
56     if (base == 0)
57         ABORT("Bad arg to GC_register_disappearing_link");
58     return(GC_general_register_disappearing_link(link, base));
59 }
60
61 int GC_general_register_disappearing_link(link, obj)
62 void_star * link;
63 void_star obj;
64 {
65     struct disappearing_link *curr_dl;
66     int index;
67     /* Allocate before acquiring lock */
68       ALLOC(new_dl, struct disappearing_link);
69     DCL_LOCK_STATE;
70     
71     index = HASH(link);
72     if ((word)link & (ALIGNMENT-1))
73         ABORT("Bad arg to GC_general_register_disappearing_link");
74     DISABLE_SIGNALS();
75     LOCK();
76     curr_dl = dl_head[index];
77     for (curr_dl = dl_head[index]; curr_dl != 0; curr_dl = curr_dl -> dl_next) {
78         if (curr_dl -> dl_hidden_link == HIDE_POINTER(link)) {
79             curr_dl -> dl_hidden_obj = HIDE_POINTER(obj);
80             UNLOCK();
81             ENABLE_SIGNALS();
82             GC_free((extern_ptr_t)new_dl);
83             return(1);
84         }
85     }
86     {
87         new_dl -> dl_hidden_obj = HIDE_POINTER(obj);
88         new_dl -> dl_hidden_link = HIDE_POINTER(link);
89         new_dl -> dl_next = dl_head[index];
90         dl_head[index] = new_dl;
91         UNLOCK();
92         ENABLE_SIGNALS();
93         return(0);
94     }
95 }
96
97 int GC_unregister_disappearing_link(link)
98 void_star * link;
99 {
100     struct disappearing_link *curr_dl, *prev_dl;
101     int index;
102     DCL_LOCK_STATE;
103     
104     index = HASH(link);
105     if (((unsigned long)link & (ALIGNMENT-1)))
106         return(0);
107     DISABLE_SIGNALS();
108     LOCK();
109     prev_dl = 0; curr_dl = dl_head[index];
110     while (curr_dl != 0) {
111         if (curr_dl -> dl_hidden_link == HIDE_POINTER(link)) {
112             if (prev_dl == 0) {
113                 dl_head[index] = curr_dl -> dl_next;
114             } else {
115                prev_dl -> dl_next = curr_dl -> dl_next;
116             }
117             UNLOCK();
118             ENABLE_SIGNALS();
119             GC_free((extern_ptr_t)curr_dl);
120             return(1);
121         }
122         prev_dl = curr_dl;
123         curr_dl = curr_dl -> dl_next;
124     }
125     UNLOCK();
126     ENABLE_SIGNALS();
127     return(0);
128 }
129
130 void GC_register_finalizer(obj, fn, cd, ofn, ocd)
131 void_star obj;
132 GC_finalization_proc fn;
133 void_star cd;
134 GC_finalization_proc * ofn;
135 void_star * ocd;
136 {
137     ptr_t base;
138     struct finalizable_object * curr_fo, * prev_fo;
139     int index;
140     /* Allocate before acquiring lock */
141       ALLOC(new_fo, struct finalizable_object);
142     DCL_LOCK_STATE;
143     
144     DISABLE_SIGNALS();
145     LOCK();
146     base = (ptr_t)GC_base((void_star)obj);
147     index = HASH(base);
148     if (base != obj)
149                 ABORT("Bad arg to GC_register_finalizer");
150     prev_fo = 0; curr_fo = fo_head[index];
151     while (curr_fo != 0) {
152         if (curr_fo -> fo_hidden_base == HIDE_POINTER(base)) {
153             if (ofn) *ofn = curr_fo -> fo_fn;
154             if (ocd) *ocd = (void_star) curr_fo -> fo_client_data;
155             if (fn == 0) {
156                 /* Delete the structure for base. */
157                   if (prev_fo == 0) {
158                     fo_head[index] = curr_fo -> fo_next;
159                   } else {
160                     prev_fo -> fo_next = curr_fo -> fo_next;
161                   }
162                   UNLOCK();
163                   ENABLE_SIGNALS();
164                   GC_free((extern_ptr_t)curr_fo);
165             } else {
166                 curr_fo -> fo_fn = fn;
167                 curr_fo -> fo_client_data = (ptr_t)cd;
168                 UNLOCK();
169                 ENABLE_SIGNALS();
170             }
171             GC_free((extern_ptr_t)new_fo);
172             return;
173         }
174         prev_fo = curr_fo;
175         curr_fo = curr_fo -> fo_next;
176     }
177     {
178         if (ofn) *ofn = 0;
179         if (ocd) *ocd = 0;
180         if (fn == 0) {
181             UNLOCK();
182             ENABLE_SIGNALS();
183             GC_free((extern_ptr_t)new_fo);
184             return;
185         }
186         new_fo -> fo_hidden_base = (word)HIDE_POINTER(base);
187         new_fo -> fo_fn = fn;
188         new_fo -> fo_client_data = (ptr_t)cd;
189         new_fo -> fo_object_size = GC_size(base);
190         new_fo -> fo_next = fo_head[index];
191         fo_head[index] = new_fo;
192     }
193     UNLOCK();
194     ENABLE_SIGNALS();
195 }
196
197 /* Called with world stopped.  Cause disappearing links to disappear,   */
198 /* and invoke finalizers.                                               */
199 void GC_finalize()
200 {
201     struct disappearing_link * curr_dl, * prev_dl, * next_dl;
202     struct finalizable_object * curr_fo, * prev_fo, * next_fo;
203     ptr_t real_ptr;
204     register int i;
205     
206   /* Make disappearing links disappear */
207     for (i = 0; i < TSIZE; i++) {
208       curr_dl = dl_head[i];
209       prev_dl = 0;
210       while (curr_dl != 0) {
211         real_ptr = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_obj);
212         if (!GC_is_marked(real_ptr)) {
213             *(word *)(REVEAL_POINTER(curr_dl -> dl_hidden_link)) = 0;
214             next_dl = curr_dl -> dl_next;
215             if (prev_dl == 0) {
216                 dl_head[i] = next_dl;
217             } else {
218                 prev_dl -> dl_next = next_dl;
219             }
220             GC_clear_mark_bit((ptr_t)curr_dl);
221             curr_dl = next_dl;
222         } else {
223             prev_dl = curr_dl;
224             curr_dl = curr_dl -> dl_next;
225         }
226       }
227     }
228   /* Mark all objects reachable via chains of 1 or more pointers        */
229   /* from finalizable objects.                                          */
230     for (i = 0; i < TSIZE; i++) {
231       for (curr_fo = fo_head[i]; curr_fo != 0; curr_fo = curr_fo -> fo_next) {
232         real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
233         if (!GC_is_marked(real_ptr)) {
234             GC_push_all(real_ptr, real_ptr + curr_fo -> fo_object_size);
235             while (!GC_mark_stack_empty()) GC_mark_from_mark_stack();
236         }
237         /* 
238         if (GC_is_marked(real_ptr)) {
239             --> Report finalization cycle here, if desired
240         }
241         */
242       }
243     }
244   /* Invoke finalization code for all objects that are still            */
245   /* unreachable.                                                       */
246     for (i = 0; i < TSIZE; i++) {
247       curr_fo = fo_head[i];
248       prev_fo = 0;
249       while (curr_fo != 0) {
250         real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
251         if (!GC_is_marked(real_ptr)) {
252             (*(curr_fo -> fo_fn))(real_ptr, curr_fo -> fo_client_data);
253             GC_set_mark_bit(real_ptr);
254             next_fo = curr_fo -> fo_next;
255             if (prev_fo == 0) {
256                 fo_head[i] = next_fo;
257             } else {
258                 prev_fo -> fo_next = next_fo;
259             }
260             if (!GC_is_marked((ptr_t)curr_fo)) {
261                 ABORT("GC_finalize: found accessible unmarked object\n");
262             }
263             GC_clear_mark_bit((ptr_t)curr_fo);
264             curr_fo = next_fo;
265         } else {
266             prev_fo = curr_fo;
267             curr_fo = curr_fo -> fo_next;
268         }
269       }
270     }
271 }
272
273 # ifdef __STDC__
274     void_star GC_call_with_alloc_lock(GC_fn_type fn, void_star client_data)
275 # else
276     void_star GC_call_with_alloc_lock(fn, client_data)
277     GC_fn_type fn;
278     void_star client_data;
279 # endif
280 {
281     void_star result;
282     DCL_LOCK_STATE;
283     
284     DISABLE_SIGNALS();
285     LOCK();
286     result = (*fn)(client_data);
287     UNLOCK();
288     ENABLE_SIGNALS();
289     return(result);
290 }
291