]> git.llucax.com Git - software/dgc/naive.git/blob - gc/gc.d
5f341f0de4751d0adc5c2370278f91cb9a2335ab
[software/dgc/naive.git] / gc / gc.d
1 /**
2  * Naive Garbage Collector implementation.
3  *
4  * This module implements a Naive Garbage Collector. The idea behind this
5  * implementation is to document all the bookkeeping and considerations that
6  * has to be taken in order to implement a garbage collector for D.
7  *
8  * The garbage collector algorithm itself is extremely simple so focus can be
9  * held in the specifics of D, and not the algorithm. A completely naive mark
10  * and sweep algorithm is used, with a recursive mark phase. The code is
11  * extremely inefficient in order to keep the code clean and easy to read and
12  * understand.
13  *
14  * The implementation is split in several modules to ease even more the
15  * lecture. All architecture/compiler specific code is done in the arch module,
16  * in order to avoid confusing version statements all over the places. The cell
17  * module has all the code related to the memory cells header. dynarray is
18  * another support module which holds the implementation of a simple dynamic
19  * array used to store root pointers and ranges. The list module holds a simple
20  * singly linked list (of cells) implementation to store the live and free
21  * lists. Finally, the iface module is the one with the C interface to comply
22  * with the Tango/Druntime GC specification.
23  *
24  * Copyright: Public Domain
25  * License:   Public Domain
26  * Authors:   Leandro Lucarella <llucax@gmail.com>
27  */
28
29 module gc.gc;
30
31 private:
32
33 // Internal imports
34 import gc.cell: Cell, BlkAttr, op_apply_ptr_range;
35 import gc.list: List;
36 import gc.dynarray: DynArray;
37 import gc.arch: push_registers, pop_registers;
38
39 // Standard imports
40 import cstdlib = tango.stdc.stdlib;
41 import cstring = tango.stdc.string;
42
43 // Debug imports
44
45 /*
46  * These are external functions coming from the D/Tango runtime. It's pretty
47  * intuitive what they do based on their names, for more details please
48  * refer to the functions documentation.
49  */
50 alias void delegate(void*, void*) mark_function;
51 extern (C) void onOutOfMemoryError();
52 extern (C) void rt_finalize(void* p, bool det=true);
53 extern (C) void rt_scanStaticData(mark_function mark);
54 extern (C) void thread_init();
55 extern (C) bool thread_needLock();
56 extern (C) void thread_suspendAll();
57 extern (C) void thread_resumeAll();
58 extern (C) void thread_scanAll(mark_function mark, void* stack_top=null);
59
60 /**
61  * A range of memory that should be scanned for pointers.
62  *
63  * This object is iterable, yielding a pointer (void*) for each iteration.
64  */
65 struct RootRange
66 {
67
68     /// Start of the memory range
69     void* from;
70
71     /// End of the memory range
72     void* to;
73
74     /// Iterate over a memory range applying dg to its elements
75     int opApply(int delegate(ref void*) dg)
76     {
77         return op_apply_ptr_range(this.from, this.to, dg);
78     }
79
80 }
81
82
83 package:
84
85
86 /**
87  * Information on a block of memory.
88  *
89  * This is part of the GC specification, it's used for the query() method.
90  *
91  * Standards: Tango/Druntime specs
92  */
93 struct BlkInfo
94 {
95
96     /// Base address of the block
97     void* base;
98
99     /// Size of the block (this is the total capacity, not the requested size)
100     size_t size;
101
102     /**
103      * Memory block attributes
104      *
105      * See_Also: cell.BlkAttr for possible values
106      */
107     uint attr;
108
109 }
110
111
112 /**
113  * GC implementation.
114  *
115  * This object contains the whole GC implementation. This is instantiated in
116  * the iface module as a global variable to provide the GC services.
117  *
118  * This implementation is designed to be extremely simple. The algorithm
119  * implemented is the most basic stop-the-world mark-sweep known.
120  *
121  * Memory is organized in cells. Each cell has a header where all the
122  * bookkeeping information is stored (like the mark bit, cell attributes,
123  * capacity, etc.), and the memory allocated for the requested memory itself.
124  *
125  * Two lists of cells are kept: free list and live list.
126  *
127  * The free list store cells known not to be referenced by the program. The
128  * live list stores cells that were referenced by the program at the end of
129  * the last collection (and just allocated cells).
130  *
131  * The root set is composed by several elements:
132  *
133  * $(UL
134  *      $(LI Static data)
135  *      $(LI Threads stack)
136  *      $(LI Registers)
137  *      $(LI Root pointers)
138  *      $(LI Root ranges)
139  * )
140  *
141  * Root pointers and ranges are user-defined.
142  *
143  * See_Also:
144  *
145  *  $(UL
146  *      $(LI cell.Cell for the cell header layout)
147  *      $(LI collect() for the main collection algorithm)
148  *      $(LI )
149  * )
150  *
151  */
152 struct GC
153 {
154
155 // TODO: GC Lock
156
157 private:
158
159     /// List of free cells.
160     List free_list;
161
162     /// List of live cells.
163     List live_list;
164
165     /// Single root pointers.
166     DynArray!(void*) root_pointers;
167
168     /// Single root pointers.
169     DynArray!(RootRange) root_ranges;
170
171     /**
172      * "Flag" to indicate when the GC is disabled.
173      *
174      * This is a number because calls to enable() and disable() can be
175      * recursive. The number of calls to enable() should match the number of
176      * calls to disable(), though, if you want the GC to be effectively
177      * enabled again.
178      */
179     uint disabled = 0;
180
181     /**
182      * Remove the mark bit to all the live cells.
183      *
184      * This is done before starting the mark phase.
185      *
186      * See_Also:
187      *
188      *  $(UL
189      *      $(LI collect() for the main collect algorithm)
190      *      $(LI mark_all() for details on the marking phase)
191      *  )
192      */
193     void unmark()
194     {
195         foreach (cell; this.live_list)
196             cell.marked = false;
197     }
198
199     /**
200      * Marks all live data (pausing all threads)
201      *
202      * This methods start marking following all the known roots:
203      *
204      *  $(UL
205      *      $(LI Static data)
206      *      $(LI Threads stack)
207      *      $(LI Registers)
208      *      $(LI Root pointers)
209      *      $(LI Root ranges)
210      *  )
211      *
212      * Note that the registers are pushed into the stack to get scanned.
213      *
214      * This is the complete mark phase. The algorithm roughly does:
215      *
216      *  $(OL
217      *      $(LI Push registers into the stack)
218      *      $(LI Pause all threads (but the current one, of course))
219      *      $(LI Scan the static data)
220      *      $(LI Scan all threads stack)
221      *      $(LI Scan the root pointers and ranges)
222      *      $(LI Resume all threads)
223      *      $(LI Pop the registers from the stack)
224      *  )
225      *
226      *
227      * See_Also:
228      *
229      *  $(UL
230      *      $(LI collect() for the main collect algorithm)
231      *      $(LI mark() for details on the marking algorithm)
232      *      $(LI sweep() for details on the sweep phase)
233      *  )
234      */
235     void mark_all()
236     {
237         void* stack_top;
238         mixin (push_registers("stack_top"));
239         thread_suspendAll();
240         rt_scanStaticData(&mark_range);
241         thread_scanAll(&mark_range, stack_top);
242         foreach (ptr; this.root_pointers) {
243             this.mark(ptr);
244         }
245         foreach (range; this.root_ranges) {
246             this.mark_range(range.from, range.to);
247         }
248         thread_resumeAll();
249         mixin (pop_registers("stack_top"));
250     }
251
252     /**
253      * Wrapper for mark() over a range, needed by some runtime functions.
254      *
255      * This function is used as a delegate to be passed to rt_scanStaticData()
256      * and thread_scanAll(), because they expects a function taking
257      * 2 pointers.
258      *
259      * This extremely inefficient on purpose. The goal of this implementation
260      * is simplicity, nor performance.
261      *
262      * See_Also:
263      *  $(UL
264      *      $(LI mark() for details on the marking algorithm)
265      *  )
266      */
267     void mark_range(void* from, void* to)
268     {
269         foreach (ptr; RootRange(from, to))
270             mark(ptr);
271     }
272
273     /**
274      * Marks all cells accessible from a pointer.
275      *
276      * This is the mark algorithm itself. It's recursive and dumb as a log. No
277      * care is taken in regards to stack overflows. This is the first example
278      * in text books.
279      *
280      * Marking is done with all threads stopped.
281      *
282      * See_Also:
283      *  $(UL
284      *      $(LI collect() for the main collect algorithm)
285      *      $(LI mark_all() for details on the marking phase)
286      *      $(LI sweep() for details on the sweep phase)
287      *  )
288      */
289     void mark(void* ptr)
290     {
291         Cell* cell = Cell.from_ptr(this.addrOf(ptr));
292         if (cell is null)
293             return;
294         if (!cell.marked) {
295             cell.marked = true;
296             if (cell.has_pointers) {
297                 foreach (ptr; *cell)
298                     mark(ptr);
299             }
300         }
301     }
302
303     /**
304      * Move unreferenced live objects to the free list (calling finalizers).
305      *
306      * This is the sweep phase. It's very simple, it just searches the live
307      * list and move unmarked cells to the free list. This function is in
308      * charge of calling finalizers too, through the rt_finalize() runtime
309      * function.
310      *
311      * Sweeping is done concurrently with the mutator threads.
312      *
313      * See_Also:
314      *  $(UL
315      *      $(LI collect() for the main collect algorithm)
316      *      $(LI mark_all() for details on the marking phase)
317      *  )
318      */
319     void sweep()
320     {
321         foreach (cell; this.live_list) {
322             if (!cell.marked) {
323                 this.live_list.unlink(cell);
324                 if (cell.has_finalizer)
325                     rt_finalize(cell.ptr, false);
326                 this.free_list.link(cell);
327             }
328         }
329     }
330
331
332 public:
333
334     /**
335      * Initialize the GC.
336      *
337      * This initializes the thread library too, as requested by the
338      * Tango/Druntime specs.
339      */
340     void init()
341     {
342         this.disabled = 0;
343         thread_init();
344     }
345
346     /**
347      * Terminate the GC.
348      *
349      * Finalization of unreferenced cells is not mandatory by the specs.
350      * This implementation guarantees that all finalizers are called, at least
351      * at program exit (i.e. at GC termination).
352      *
353      * The specs says that "objects referenced from the data segment never get
354      * collected by the GC". While this is true for this implementation,
355      * finalizers are called for objects referenced from the data segment at
356      * program exit.
357      *
358      * There could be some problems with this, in very strange situations. For
359      * a more complete discussion about the topic please take a look at the
360      * bug 2858: http://d.puremagic.com/issues/show_bug.cgi?id=2858
361      */
362     void term()
363     {
364         foreach (cell; this.live_list)
365             if (cell.has_finalizer)
366                 rt_finalize(cell.ptr, false);
367         // Let the OS free the memory on exit.
368     }
369
370     /**
371      * Enable the GC.
372      *
373      * When the GC is enabled, a collection is triggered when malloc() can't
374      * find room in the free list to fulfill the requested size.
375      *
376      * enable() and disable() can be called recursively. The number of calls
377      * to enable() should match the number of calls to disable(), though, if
378      * you want the GC to be effectively enabled again.
379      *
380      * See_Also: disable()
381      */
382     void enable()
383     {
384         assert (this.disabled > 0);
385         this.disabled--;
386     }
387
388     /**
389      * Disable the GC.
390      *
391      * See_Also: enable()
392      */
393     void disable()
394     {
395         this.disabled++;
396         assert (this.disabled > 0);
397     }
398
399     /**
400      * Run a GC collection in order to find unreferenced objects.
401      *
402      * This is the simplest stop-the-world mark-sweep algorithm ever. It first
403      * removes the mark bit from all the live cells, then it mark the cells
404      * that are reachable through the root set (static data, stack, registers
405      * and custom root), and finally sweeps the live list looking for unmarked
406      * cells to free.
407      *
408      * The world is stopped only for the mark phase.
409      *
410      * See_Also:
411      *  $(UL
412      *      $(LI mark_all() for details on the marking phase)
413      *      $(LI sweep() for details on the sweep phase)
414      *  )
415      */
416     void collect()
417     {
418         this.unmark();
419         this.mark_all();
420         this.sweep();
421     }
422
423     /**
424      * Minimize free space usage.
425      *
426      * This method returns to the OS memory that is not longer used by
427      * the program. Usually calling this method manually is not
428      * necessary, because unused cells are recycled for future
429      * allocations. But if there is some small part of the program that
430      * requires a lot of memory and it's known that it won't be used
431      * further, calling this can reduce the memory footprint of the program
432      * considerably (at the expense of some performance lost in future
433      * allocations).
434      *
435      * This implementation just return to the OS all the cells in the free
436      * list.
437      */
438     void minimize()
439     {
440         foreach (cell; this.free_list) {
441             this.free_list.unlink(cell);
442             cstdlib.free(cell);
443         }
444     }
445
446     /**
447      * Get attributes associated to the cell pointed by ptr.
448      *
449      * Attributes is a bitmap that can have theses values:
450      *
451      *  $(UL
452      *      $(LI 1: The object stored in the cell have to be finalized)
453      *      $(LI 2: The cell should not be scanned for pointers)
454      *      $(LI 4: The cell should not be moved during a collection
455      *           (unimplemented))
456      *  )
457      *
458      * See_Also: cell.BlkAttr, setAttr(), clrAttr()
459      */
460     uint getAttr(void* ptr)
461     {
462         auto cell = this.live_list.find(ptr);
463         if (cell)
464             return cell.attr;
465         return 0;
466     }
467
468     /**
469      * Set the attributes of the cell pointed by ptr.
470      *
471      * All bits present in attr are set, other bits are untouched. The old
472      * attributes are returned.
473      *
474      * See_Also: cell.BlkAttr, getAttr(), clrAttr()
475      */
476     uint setAttr(void* ptr, uint attr)
477     {
478         auto cell = this.live_list.find(ptr);
479         if (cell) {
480             auto old = cell.attr;
481             cell.attr |= attr;
482             return cell.attr;
483         }
484         return 0;
485     }
486
487     /**
488      * Clear the attributes of the cell pointed by ptr.
489      *
490      * All bits present in attr are cleared, other bits are untouched. The old
491      * attributes are returned.
492      *
493      * See_Also: cell.BlkAttr, getAttr(), setAttr()
494      */
495     uint clrAttr(void* ptr, uint attr)
496     {
497         auto cell = this.live_list.find(ptr);
498         if (cell) {
499             auto old = cell.attr;
500             cell.attr &= ~attr;
501             return cell.attr;
502         }
503         return 0;
504     }
505
506     /**
507      * Allocate memory.
508      *
509      * This is the main allocator of the GC. The algorithm is really
510      * simple. It does a first-fit search in the free list, if no free cell is
511      * found with enough room, it runs a collection and retry (unless the GC
512      * is disabled). If there is no room still, it uses C malloc to allocate
513      * a new cell. If all that fails, then onOutOfMemoryError() runtime
514      * function is called to handle the error.
515      *
516      * attr are the attributes to associate to the new cell (see getAttr() for
517      * details).
518      */
519     void* malloc(size_t size, uint attr=0)
520     {
521         if (size == 0)
522             return null;
523
524         // Find a free cell in the free list with enough space
525         auto cell = this.free_list.pop(size);
526         if (cell)
527             goto success;
528
529         // No room in the free list found, if the GC is enabled, trigger
530         // a collection and try again
531         if (!this.disabled) {
532             this.collect();
533             cell = this.free_list.pop(size);
534             if (cell)
535                 goto success;
536         }
537
538         // No luck still, allocate new memory
539         cell = cast(Cell*) cstdlib.malloc(size + Cell.sizeof);
540         if (cell)
541             goto success;
542
543         // No memory
544         onOutOfMemoryError();
545
546         return null;
547
548     success:
549         cell.size = size;
550         if (cell.capacity == 0) // fresh cell
551             cell.capacity = size;
552         cell.attr = cast(BlkAttr) attr;
553         this.live_list.link(cell);
554
555         return cell.ptr;
556     }
557
558     /**
559      * Allocate memory (set memory to zero).
560      *
561      * Same as malloc() but set the allocated memory cell to zero.
562      */
563     void* calloc(size_t size, uint attr=0)
564     {
565         void* ptr = this.malloc(size, attr);
566
567         if (ptr is null)
568             onOutOfMemoryError();
569         else
570             cstring.memset(ptr, 0, size);
571
572         return ptr;
573     }
574
575     /**
576      * Reallocate memory.
577      *
578      * This implementation is very simple, if size less or equals than the
579      * cells capacity, the cell's size is changed and the same address is
580      * returned. Otherwise a new cell is allocated using malloc() (this can
581      * trigger a collection), the contents are moved and the old cell is freed.
582      *
583      * attr are the same as malloc().
584      */
585     void* realloc(void* ptr, size_t size, uint attr=0)
586     {
587
588         // Undercover malloc()
589         if (ptr is null)
590             return this.malloc(size, attr);
591
592         // Undercover free()
593         if (size == 0) {
594             this.free(ptr);
595             return null;
596         }
597
598         auto cell = this.live_list.find(ptr);
599         assert (cell);
600
601         // We have enough capacity already, just change the size
602         if (cell.capacity >= size) {
603             cell.size = size;
604             return cell.ptr;
605         }
606
607         // We need to move the cell because of the lack of capacity, find
608         // a free cell with the requested capacity (at least)
609         Cell* new_cell = Cell.from_ptr(this.malloc(size));
610         assert (!(new_cell is null)); // out of memory is handled by malloc()
611
612         // Move cell attributes and contents
613         new_cell.attr = cell.attr;
614         cstring.memcpy(new_cell.ptr, cell.ptr, cell.size);
615
616         // Free the old cell
617         this.free(cell);
618
619         return new_cell.ptr;
620     }
621
622     /**
623      * Attempt to in-place enlarge a memory block pointed to by ptr.
624      *
625      * The memory should be enlarged to at least min_size beyond its current
626      * capacity, up to a maximum of max_size. This does not attempt to move
627      * the memory block (like realloc() does).
628      *
629      * Returns:
630      *  0 if could not extend ptr, total size of entire memory block if
631      *  successful.
632      */
633     size_t extend(void* ptr, size_t min_size, size_t max_size)
634     {
635         assert (min_size <= max_size);
636         // There is no possible extension of the capacity for this
637         // implementation.
638         return 0;
639     }
640
641     /**
642      * Reserve memory to anticipate memory allocations.
643      *
644      * This implementation is really dumb, a single cell is allocated with
645      * size bytes. If 2 mallocs() follows a call to reserve(size), requesting
646      * size/2 bytes each, one allocation will be done still (and  half the
647      * memory of the first malloc will be wasted =) Since this is a trivial
648      * implementation, we don't care about this.
649      *
650      * The actual number of bytes reserver are returned, or 0 on error.
651      */
652     size_t reserve(size_t size)
653     {
654         assert (size > 0);
655         auto cell = cast(Cell*) cstdlib.malloc(size + Cell.sizeof);
656         if (!cell)
657             return 0;
658         cell.size = size;
659         cell.capacity = size;
660         this.free_list.link(cell);
661         return size;
662     }
663
664     /**
665      * Free unused memory.
666      *
667      * This method tells the GC that a cell is not longer used. The GC don't
668      * perform any connectivity check, if the cell was referenced by others,
669      * nasty things will happen (much like C/C++).
670      *
671      * Note that finalizers are not called by this method. Finalizers are
672      * called by the runtime when the delete operator is used, and the delete
673      * operator calls this method through the runtime.
674      */
675     void free(void* ptr)
676     {
677         if (ptr is null)
678             return;
679
680         auto cell = this.live_list.pop(ptr);
681         assert (cell);
682
683         this.free_list.link(cell);
684     }
685
686     /**
687      * Get the base address of an interior pointer into the GC heap.
688      *
689      * If ptr is not pointing into the GC heap null is returned.
690      */
691     void* addrOf(void* ptr)
692     {
693         if (ptr is null)
694             return null;
695
696         bool in_range(Cell* cell)
697         {
698             return ptr >= cell.ptr && ptr < (cell.ptr + cell.size);
699         }
700
701         auto cell = this.live_list.find(&in_range);
702         if (cell)
703             return cell.ptr;
704
705         return null;
706     }
707
708     /**
709      * Return the real size (capacity) for the cell pointed by ptr.
710      *
711      * ptr should be the base address of a heap allocated object, interior
712      * pointers are not supported (use addrOf() if you have an interior
713      * pointer). If this is not true, this method returns 0.
714      *
715      * realloc(ptr, sizeOf(ptr), attr) is guaranteed not to allocate/move
716      * memory.
717      */
718     size_t sizeOf(void* ptr)
719     {
720         auto cell = this.live_list.find(ptr);
721         if (cell)
722             return cell.capacity;
723         return 0;
724     }
725
726     /**
727      * Get information about the cell pointed by ptr.
728      *
729      * ptr should be the base address of a heap allocated object, interior
730      * pointers are not supported (use addrOf() if you have an interior
731      * pointer). If this is not true, this method returns BlkInfo.init.
732      *
733      * See BlkInfo for the information provided by this method.
734      */
735     BlkInfo query(void* ptr)
736     {
737         BlkInfo blk_info;
738
739         auto cell = this.live_list.find(ptr);
740         if (cell) {
741             blk_info.base = cell.ptr;
742             blk_info.size = cell.capacity;
743             blk_info.attr = cell.attr;
744         }
745
746         return blk_info;
747     }
748
749     /**
750      * Add a root pointer to the root set.
751      *
752      * This method can be used to register new root to the GC heap. This is
753      * only needed when the user has custom memory that has pointers into the
754      * GC heap (for example for interfacing with C programs, which allocates
755      * memory using malloc() directly).
756      *
757      * See_Also: removeRoot(), addRange(), removeRange()
758      */
759     void addRoot(void* ptr)
760     {
761         this.root_pointers.append(ptr);
762     }
763
764     /**
765      * Add a root range to the root set.
766      *
767      * This method can be used to register new root range (a memory chunk
768      * that should be scanned for pointers into the GC heap). This is
769      * only needed when the user has custom memory that has pointers into the
770      * GC heap (for example for interfacing with C programs, which allocates
771      * memory using malloc() directly).
772      *
773      * Pointers will be scanned assuming they are aligned.
774      *
775      * See_Also: removeRange(), addRoot(), removeRoot()
776      */
777     void addRange(void* ptr, size_t size)
778     {
779         this.root_ranges.append(RootRange(ptr, ptr + size));
780     }
781
782     /**
783      * Remove a root pointer from the root set.
784      *
785      * ptr has to be previously registered using addRoot(), in other case the
786      * results of this method is undefined.
787      *
788      * See_Also: addRoot(), addRange(), removeRange()
789      */
790     void removeRoot(void* ptr)
791     {
792         this.root_pointers.remove(ptr);
793     }
794
795     /**
796      * Remove a root range from the root set.
797      *
798      * ptr has to be previously registered using addRange(), in other case the
799      * results of this method is undefined.
800      *
801      * See_Also: addRange(), addRoot(), removeRoot()
802      */
803     void removeRange(void* ptr)
804     {
805         this.root_ranges.remove_if((ref RootRange range) {
806                     return range.from is ptr;
807                 });
808     }
809
810 } // struct GC
811
812 // vim: set et sw=4 sts=4 :