2 acogc.c - simple accurate/cooperative garbage collector
4 Copyright (C) 2006, Christian Thaeter <chth@gmx.net>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License version 2 as
8 published by the Free Software Foundation.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, contact me.
25 // TODO statistic to auto-adjust the GC (freq, highwater, lowwater)
26 // TODO return value for lowmemhandler ABORT, RETRY
27 // TODO prepare for a acogc_object_touch read barrier and a incremental GC scheme
34 object_set_factory (AcogcObject self
, const_AcogcFactory factory
)
36 self
->factory
= (AcogcFactory
)factory
;
40 object_set_factory_color (AcogcObject self
,
41 const_AcogcFactory factory
,
44 self
->factory
= (AcogcFactory
)((uintptr_t)factory
| (uintptr_t)color
);
47 static inline unsigned
48 object_color_get (const_AcogcObject self
)
50 return (unsigned)!!(((uintptr_t)self
->factory
) & (uintptr_t)0x1);
55 object_to_memory (const_AcogcObject
const self
)
57 return (void*)self
+ sizeof (acogc_object
);
60 static inline AcogcObject
61 memory_to_object (const void * const self
)
63 return (AcogcObject
)(self
- sizeof (acogc_object
));
67 /* malloc / free wrapers */
69 acogc_alloc_ (void ** addr
, size_t size
, AcogcFactory factory
)
72 enum acogc_emergency_level emergency
= ACOGC_COLLECT_NORMAL
;
76 ret
= realloc (*addr
, size
);
79 ACOGC_TRACE (2, "emergency %d", emergency
+ 1);
80 if ((emergency
+= 2) >= ACOGC_COLLECT_FAILED
)
83 // TODO factory->nomemhandler ();
86 // TODO acogc_root_collect (root, emergency);
94 acogc_reserve_ (void ** addr
, size_t actual
, size_t needed
, AcogcFactory factory
)
98 for (n
= actual
>16 ? actual
: 16; n
<= needed
; n
+= (n
>>1)); /*n = n * 1.5*/
100 acogc_alloc (addr
, n
, factory
);
102 // TODO lowmem backoff handler (retry with n=needed)
108 acogc_free_ (void ** addr
)
110 if (!acogc_is_ref (*addr
))
120 acogc_marker_init (AcogcMarker self
, acogc_mark_func marker
, void* object
, void* data
)
123 self
->marker
= marker
;
124 self
->object
= object
;
130 acogc_root_register_marker (AcogcRoot self
, AcogcMarker marker
)
132 ACOGC_TRACE (2, "register marker func %p data %p",marker
->marker
, marker
->data
);
133 marker
->next
= self
->markers
;
134 self
->markers
= marker
;
138 acogc_root_marker_unregister (AcogcRoot self
, AcogcMarker marker
)
140 AcogcMarker_ref prev
= &self
->markers
;
141 AcogcMarker i
= *prev
;
148 i
->next
= i
->object
= NULL
;
160 acogc_marker_assert_unregistered_root (AcogcMarker m
)
163 ACOGC_ASSERT (m
->object
== NULL
, "root not unregistered");
170 acogc_factory_init (AcogcFactory self
,
174 unsigned object_cluster
,
175 acogc_scan_func scan
,
176 acogc_finalize_func finalize
)
178 llist_init (&self
->factories
);
180 llist_insert_after (&self
->factories
, &other
->factories
);
182 llist_init (&self
->bottom
);
183 self
->top
= self
->scan
= self
->free
= &self
->bottom
;
185 llist_init (&self
->roots
);
186 self
->scanned_roots
= &self
->roots
;
189 self
->ecru_color
= 0x1;
193 self
->scan_at_once
= object_cluster
/4?object_cluster
/4:1;
195 /* statistics counters */
196 self
->scan_counter
= 1;
197 self
->objects_allocated
= 0;
198 self
->objects_black
= 0;
199 self
->objects_white
= 0;
203 /* statistics state */
204 self
->scan_freq_avg
= 1;
207 /*size_t memory_allocated; */
209 self
->free_limit
= free_limit
;
210 self
->object_cluster
= object_cluster
;
214 self
->finalize_func
= finalize
;
215 self
->scan_func
= scan
;
216 //void * touch_data; /* supplemental user data passed to touch */
217 //void (*nomemhandler)(void); /* called when no memory can be allocated, defaults to abort() */
221 acogc_factory_new (AcogcFactory other
,
224 unsigned object_cluster
,
225 acogc_scan_func scan
,
226 acogc_finalize_func finalize
)
228 AcogcFactory self
= malloc (sizeof (acogc_factory
));
232 acogc_factory_init (self
, other
, size
, free_limit
, object_cluster
, scan
, finalize
);
238 acogc_factory_free (AcogcFactory self
)
243 acogc_factory_erase (self
);
245 llist_unlink (&self
->factories
);
250 acogc_factory_erase (AcogcFactory self
)
254 // unregister all roots
259 acogc_factory_alloc (AcogcFactory self
)
263 if (!self
->scan_counter
--)
264 acogc_factory_scan (self
);
266 if (!self
->gc_lock
&& self
->scan
== self
->top
&& !self
->objects_white
)
267 acogc_factory_flip (self
);
269 if (!self
->objects_white
)
271 if (self
->scan
== self
->top
)
276 object
= malloc (sizeof (acogc_object
) + self
->size
);
277 // TODO lowmem strategy
281 llist_init (&object
->objects
);
282 acogc_object_set_factory_flags_ (object
, self
, ACOGC_FLAG_UNINITIALIZED
);
283 object
->weakrefs
= NULL
;
285 self
->objects_allocated
++;
289 object
= LLIST_TO_STRUCTP(self
->free
, acogc_object
, objects
);
290 self
->free
= llist_get_next (self
->free
);
291 if (self
->finalize_func
)
292 self
->finalize_func (acogc_memory_from_object_ (object
));
294 acogc_object_weakreference_invalidate (object
);
296 self
->objects_white
--;
297 acogc_object_set_flags_ (object
, ACOGC_FLAG_UNINITIALIZED
);
300 self
->objects_black
++;
302 if (self
->objects_allocated
> 2 * self
->object_cluster
&&
303 ((100 * self
->objects_white
) / self
->objects_allocated
) > self
->free_limit
)
305 for (unsigned i
= self
->object_cluster
; i
; --i
)
307 // TODO remove from head or from tail?
308 //AcogcObject deleteme = LLIST_TO_STRUCTP(llist_get_prev (&self->bottom), acogc_object, objects);
309 AcogcObject deleteme
= LLIST_TO_STRUCTP(llist_get_next (self
->free
), acogc_object
, objects
);
311 if (self
->finalize_func
)
312 self
->finalize_func (acogc_memory_from_object_ (deleteme
));
314 acogc_object_weakreference_invalidate (deleteme
);
316 llist_unlink (&deleteme
->objects
);
318 self
->objects_white
--;
319 self
->objects_allocated
--;
325 return acogc_memory_from_object_ (object
);
330 acogc_factory_scan (AcogcFactory self
)
332 ACOGC_TRACE (1,"scanning %p", self
);
334 self
->scan_counter
= self
->scan_freq
;
336 for (int i
= self
->scan_at_once
; i
; --i
)
338 ACOGC_TRACE (2,"%d", i
);
341 while (self
->scan
== self
->top
&& (l
= llist_get_prev (self
->scanned_roots
)) != &self
->roots
)
343 // touch root chain until we fetched at least one gray object or we scanned all nodes in the root chain
344 ACOGC_TRACE (3, "fetching root %p", acogc_memory_from_list_ (l
));
345 acogc_object_touch (acogc_memory_from_list_ (l
));
346 self
->scanned_roots
= l
;
349 if (self
->scan
== self
->top
)
351 ACOGC_TRACE (4, "scan already completed");
356 if (!self
->objects_white
)
358 ACOGC_TRACE (4, "scan runing while freelist is empty");
362 ACOGC_TRACE (3, "touching %p", acogc_memory_from_list_ (self
->scan
));
363 acogc_object_touch (acogc_memory_from_list_ (self
->scan
));
364 self
->scan
= llist_get_prev (self
->scan
);
370 acogc_factory_flip (AcogcFactory self
)
372 assert (!self
->gc_lock
&& self
->scan
== self
->top
&& !self
->objects_white
);
374 // reestimate settings
375 // reset statistics calculate averages
386 acogc_object_touch_really_ (AcogcObject object
)
388 (void) object
; //TODO
390 // set color to black, increment black counter
392 //if (!self->scan_counter--)
393 // acogc_factory_scan (self);
399 /* register a object as GC root object, should be done as soon as possible after allocation */
401 acogc_addroot (void* object
)
403 (void) object
; //TODO
406 /* unregister a GC root object, it becomes normal collectable by this. can be expensive */
408 acogc_removeroot (void* object
)
410 (void) object
; //TODO
418 acogc_weakreference_link (AcogcWeakReference self
, void* object
)
423 if (self
->ref
!= object
)
425 ACOGC_TRACE (4, "weaklink %p to %p", self
, object
);
427 acogc_reference_weak_unlink (self
);
429 self
->next
= *member
?*member
:(AcogcReference
)member
;
436 acogc_weakreference_unlink (AcogcWeakReference self
)
440 AcogcReference_ref prev
= &self
->next
;
441 AcogcReference i
= self
->next
;
446 ACOGC_ASSERT (i
->next
, "zero in weak cycle");
450 ACOGC_TRACE (4, "unlink %p from after %p, before %p", self
, prev
, self
->next
);
452 if (*prev
== (AcogcReference
)prev
)
454 ACOGC_TRACE (3, "weaklinks now empty %p", prev
);
461 ACOGC_ASSERT (!self
->ref
, "reference not linked");
466 acogc_object_weakreference_invalidate (void * object
)
472 while ((*self
)->next
!= *self
)
474 AcogcReference tmp
= *self
;
475 ACOGC_TRACE (3, "invalidate %p, ref %p", tmp
, tmp
->ref
);
476 (*self
) = (*self
)->next
;
487 acogc_weakreference_reinstget (AcogcWeakReference self
)
495 AcogcObject o
= memory_to_object (self
->ref
);
497 if (object_swept_get (o
))
499 ACOGC_TRACE (4, "reinst %p", self
->ref
);
501 AcogcFactory ofactory
= object_factory_get (o
);
502 AcogcObject i
= ofactory
->free_head
;
503 AcogcObject prev
= NULL
;
511 // remove from freequeue
513 prev
->next
= i
->next
;
515 ofactory
->free_head
= i
->next
;
517 if (ofactory
->free_tail
== i
)
518 ofactory
->free_tail
= prev
;
521 i
->next
= ofactory
->root
->used
;
522 ofactory
->root
->used
= i
;
524 object_set_mark (i
, ofactory
->root
->mark
);
525 object_set_swept (i
, 0);
527 -- ofactory
->objects_free
;
528 ++ ofactory
->objects_used
;
530 if (ofactory
->reinst_initize
)
531 ofactory
->reinst_initize (self
->ref
, ofactory
->size
);
534 ACOGC_ASSERT (self
->ref
, "");
541 acogc_weakreference_get (AcogcWeakReference self
)
545 if (!self
|| !self
->ref
)
548 if (object_swept_get (memory_to_object (self
->ref
)))
557 acogc_reference_assert_cleared (AcogcWeakReference p
)
560 ACOGC_ASSERT (!p
->next
&& ! p
->ref
, "weak-reference %p not cleared", p
);
566 acogc_reference_get (AcogcReference self)
575 // c-file-style: "gnu"
577 // arch-tag: 2a29f53b-906e-4025-bf90-8e12b4182474