├── .gitignore ├── Makefile ├── Makefile.lib ├── README.md ├── depends ├── docs └── index.html ├── license └── bsd_license.txt └── source ├── Collector.c ├── Collector.h ├── CollectorMarker.c ├── CollectorMarker.h ├── CollectorMarker_inline.h └── Collector_inline.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.lib 2 | *.dll 3 | *.manifest 4 | *.obj 5 | *.exp 6 | *.ilk 7 | ._* 8 | *.pdb 9 | *.hi 10 | *.o 11 | *.so 12 | *.dylib 13 | *.cmd 14 | .mod.c* 15 | *.tmp_versions 16 | *CVS 17 | *RCS 18 | *IoVMCode.c* 19 | *Io*Init.c* 20 | ~* 21 | *_darcs 22 | *_build 23 | *_ioCodeProcessed 24 | *errors 25 | *.bak* 26 | *.BAK* 27 | *.orig* 28 | *vssver.scc* 29 | *.swp* 30 | *MT 31 | *\{arch\} 32 | *.arch-ids 33 | *, 34 | *.class* 35 | *.prof* 36 | *.DS_Store* 37 | *.FBCLockFolder 38 | *BitKeeper 39 | *ChangeSet 40 | *.svn 41 | .cvsignore* 42 | .gdb_history* 43 | *Thumbs.db* 44 | .DS_Store 45 | .libs 46 | .deps* 47 | *.a 48 | *.la 49 | *.lo 50 | *.so 51 | *.dylib 52 | *.exe 53 | *.Po 54 | *.Tlo 55 | *.Plo 56 | _objs 57 | _includes 58 | *_libs 59 | *Io.*Code.c* 60 | io2c 61 | *Io.*Init.c* 62 | *pngtest* 63 | *steve.model* 64 | *skipdbtest* 65 | *config.log* 66 | *config.status* 67 | .rej* 68 | *autom4te.cache* 69 | *.cache 70 | *_include 71 | *tags* 72 | ./addons/SGML/source/libsgml/Makefile* 73 | ./addons/SGML/source/libsgml/examples/Makefile* 74 | ./addons/SGML/source/libsgml/src/Makefile* 75 | tools/editlib_test/editlib_test 76 | extras/IoPlayers/MSWindows/ioplayer/ioplayer.ncb 77 | extras/IoPlayers/MSWindows/ioplayer/ioplayer.suo 78 | extras/IoPlayers/MSWindows/ioplayer/ioplayer/Debug 79 | extras/IoPlayers/MSWindows/ioplayer/ioplayer/Release 80 | extras/IoPlayers/MSWindows/ioplayer/ioplayer/ioplayer.vcproj.CUSTOMER2007.Customer.user 81 | extras/IoPlayers/MSWindows/ioplayer/pingme.txt 82 | extras/IoPlayers/MSWindows/ioplayer/smysrv 83 | libs/iovm/docs/docs.txt 84 | addons/*/docs/docs.txt 85 | *.mode1 86 | *.pbxuser 87 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include ./Makefile.lib 2 | CFLAGS += -DBUILDING_COLLECTOR_DLL $(IOVMALLFLAGS) 3 | -------------------------------------------------------------------------------- /Makefile.lib: -------------------------------------------------------------------------------- 1 | ifeq ($(shell [ -f Makefile.local ] && echo true),true) 2 | ALL_BEGIN := $(MAKE) -f Makefile.local all_begin 3 | ALL_END := $(MAKE) -f Makefile.local all_end 4 | MAKE_LOCAL_CLEAN := $(MAKE) -f Makefile.local clean 5 | else 6 | ALL_BEGIN := 7 | ALL_END := 8 | MAKE_LOCAL_CLEAN := 9 | endif 10 | 11 | #CC ?= g++ 12 | 13 | RANLIB ?= ranlib 14 | AR ?= ar 15 | ARFLAGS := rcu 16 | AROUTFLAG := 17 | CCOUTFLAG := -o 18 | LINKDLL := $(CC) 19 | LINKDLLOUTFLAG := -o 20 | LINKDIRFLAG := -L 21 | LINKLIBFLAG := -l 22 | INSTALL_PREFIX_DEFINE := $(INSTALL_PREFIX) 23 | 24 | # may need to remove --param max-inline-insns-single=500 for older versions of gccs 25 | WARN :=-Wstrict-prototypes 26 | #-Winline 27 | #--param max-inline-insns-single=500 28 | 29 | #-ansi -pedantic 30 | OPTIMIZE :=-O3 -g 31 | #-msse2 -msse -mmmx 32 | #OPTIMIZE :=-O3 -ffast-math -ftree-vectorize -ftree-vectorizer-verbose=4 33 | DLL_SUFFIX := so 34 | DLL_COMMAND := -shared 35 | FLAT_NAMESPACE := 36 | dependson := $(shell cat depends) 37 | 38 | HEADERS :=-I. -I./source 39 | others := $(dependson) 40 | others := $(addprefix -I../,$(others)) 41 | others := $(addsuffix /_build/headers,$(others)) 42 | HEADERS += $(others) 43 | 44 | DLL_L := $(dependson) 45 | DLL_L := $(addprefix -L../,$(DLL_L)) 46 | DLL_L := $(addsuffix /_build/dll,$(DLL_L)) 47 | 48 | DLL_l := $(dependson) 49 | DLL_l := $(addprefix -l,$(DLL_l)) 50 | 51 | CFLAGS = $(OPTIMIZE) $(WARN) $(HEADERS) #--param max-inline-insns-single=500 52 | 53 | # Uncommment for Coros to register their stack with Valgrind 54 | #CFLAGS += -DUSE_VALGRIND 55 | 56 | ### PLATFORM ##################################################### 57 | 58 | SYS ?= $(shell uname -s) 59 | 60 | ifeq ($(SYS),Darwin) 61 | CFLAGS += -falign-loops=16 62 | CFLAGS += -fPIC 63 | DLL_SUFFIX := dylib 64 | DLL_COMMAND := -dynamiclib 65 | FLAT_NAMESPACE := -flat_namespace 66 | endif 67 | 68 | ifeq ($(SYS),DragonFly) 69 | LFLAGS += -lm 70 | endif 71 | 72 | ifeq ($(SYS),Linux) 73 | CFLAGS += -falign-loops=16 74 | CFLAGS += -fPIC 75 | endif 76 | 77 | ifeq ($(SYS),IRIX) 78 | RANLIB ?= touch 79 | endif 80 | 81 | ifneq (,$(findstring CYGW,$(SYS))) 82 | DLL_SUFFIX := dll 83 | endif 84 | 85 | ifneq (,$(findstring MINGW,$(SYS))) 86 | DLL_SUFFIX := dll 87 | endif 88 | 89 | ifneq (,$(findstring Windows,$(SYS))) 90 | CC := cl -nologo 91 | CCOUTFLAG :=-Fo 92 | WARN := 93 | #OPTIMIZE :=-Zi -MDd -D_USE_MATH_DEFINES -DWIN32 -D_DEBUG -D_CRT_SECURE_NO_DEPRECATE 94 | OPTIMIZE :=-O2 -EHsc -MD -D_USE_MATH_DEFINES -DWIN32 -DNDEBUG -D_CRT_SECURE_NO_DEPRECATE 95 | AR := link -lib 96 | AROUTFLAG :=-out: 97 | ARFLAGS := 98 | LINKDLL := link 99 | LINKDLLOUTFLAG :=-out: 100 | LINKDIRFLAG := -libpath: 101 | LINKLIBFLAG := 102 | DLL_LIB_SUFFIX := .lib 103 | DLL_LIB_PREFIX := 104 | DLL_COMMAND := -link /INCREMENTAL:NO -subsystem:WINDOWS -machine:X86 -DLL $(DEF_FILE) 105 | DLL_SUFFIX := dll 106 | DLL_EXTRAS := ws2_32.lib shell32.lib 107 | FLAT_NAMESPACE := 108 | RANLIB := echo no ranlib 109 | INSTALL_PREFIX_DEFINE := $(shell cygpath -am $(INSTALL_PREFIX)) 110 | endif 111 | 112 | ### FILES ######################################################### 113 | 114 | NAME := $(notdir $(subst $() ,_,$(shell pwd))) 115 | LIBR := _build/lib/lib$(NAME).a 116 | DLL := _build/dll/lib$(NAME).$(DLL_SUFFIX) 117 | infiles := $(wildcard source/*.c) 118 | #infiles += $(wildcard *.S) 119 | asmfiles := $(wildcard source/*.S) 120 | hfiles := $(wildcard source/*.h) 121 | buildhfiles := $(subst source/,_build/headers/,$(hfiles)) 122 | objects := $(notdir $(infiles)) 123 | objects := $(basename $(objects)) 124 | objects := $(addsuffix .o,$(objects)) 125 | objects := $(addprefix _build/objs/,$(objects)) 126 | 127 | vmall_objects := $(notdir $(infiles)) 128 | vmall_objects := $(basename $(vmall_objects)) 129 | vmall_objects := $(addsuffix .o,$(vmall_objects)) 130 | vmall_objects := $(addprefix _build/vmall_objs/,$(vmall_objects)) 131 | 132 | 133 | DLL_L := $(dependson) 134 | DLL_L := $(addprefix $(LINKDIRFLAG)../,$(DLL_L)) 135 | DLL_L := $(addsuffix /_build/dll,$(DLL_L)) 136 | 137 | DLL_l := $(dependson) 138 | DLL_l := $(addprefix $(LINKLIBFLAG),$(DLL_l)) 139 | DLL_l := $(addsuffix $(DLL_LIB_SUFFIX),$(DLL_l)) 140 | 141 | DEF_FILE := 142 | 143 | ### RULES ########################################################### 144 | 145 | all: _build/objs _build/headers _build/lib _build/dll $(buildhfiles) 146 | $(ALL_BEGIN) 147 | $(MAKE) $(LIBR) 148 | $(MAKE) $(DLL) 149 | ifneq (,$(findstring Windows,$(SYS))) 150 | mkdir -p _build/vmall_objs 151 | $(MAKE) vmall_objs 152 | endif 153 | $(ALL_END) 154 | 155 | _build: 156 | mkdir -p $@ 157 | 158 | _build/objs: _build 159 | mkdir -p $@ 160 | 161 | _build/headers: _build 162 | mkdir -p $@ 163 | 164 | _build/lib: _build 165 | mkdir -p $@ 166 | 167 | _build/dll: _build 168 | mkdir -p $@ 169 | 170 | # pull in dependency info for *existing* .o files 171 | -include $(objects:.o=.d) 172 | 173 | _build/objs/%.o: source/%.c 174 | ifeq (,$(findstring Windows,$(SYS))) 175 | $(CC) -MM -MT $@ -MF $(@:.o=.d) -DINSTALL_PREFIX=\"$(INSTALL_PREFIX_DEFINE)\" $(CFLAGS) -c $< $(CCOUTFLAG)$@ 176 | endif 177 | $(CC) -DINSTALL_PREFIX=\"$(INSTALL_PREFIX_DEFINE)\" $(CFLAGS) -c $< $(CCOUTFLAG)$@ 178 | 179 | _build/vmall_objs/%.o: source/%.c 180 | $(CC) -DINSTALL_PREFIX=\"$(INSTALL_PREFIX_DEFINE)\" $(CFLAGS) \ 181 | -DBUILDING_IOVMALL_DLL -c $< $(CCOUTFLAG)$@ 182 | 183 | _build/headers/%.h: source/%.h _build/headers 184 | cp $< $@ 185 | 186 | _build/vmall_objs: 187 | mkdir -p $@ 188 | 189 | vmall_objs: _build/vmall_objs $(vmall_objects) 190 | 191 | $(LIBR): $(objects) 192 | ifneq ($(asmfiles),) 193 | $(CC) $(CFLAGS) -c $(asmfiles) $(CCOUTFLAG)_build/objs/asm.o || true 194 | endif 195 | $(AR) $(ARFLAGS) $(AROUTFLAG)$@ _build/objs/*.o 196 | $(RANLIB) $@ 197 | 198 | $(DLL): $(objects) 199 | $(LINKDLL) $(DLL_COMMAND) $(FLAT_NAMESPACE) $(DLL_L) _build/objs/*.o $(LINKDLLOUTFLAG)$(DLL) $(DLL_l) $(DLL_EXTRAS) 200 | ifneq (,$(findstring Windows,$(SYS))) 201 | mt.exe -manifest $@.manifest -outputresource:$@ 202 | rm $@.manifest 203 | endif 204 | 205 | clean: 206 | rm -rf _build 207 | $(MAKE_LOCAL_CLEAN) 208 | 209 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # garbagecollector 2 | 3 | ## Overview 4 | 5 | libgarbagecollector is an incremental tricolor tracing collector using a Baker Treadmill. libgarbagecollector is not an allocator; it only keeps track of the objects you tell it about and determines when it is safe to free them. So you'll allocate objects using malloc() (or the allocator of your choice), and register them with the collector. When the collector finds that an object can be freed, it will call a function you give it to do the actual deallocation. 6 | 7 | ## Getting Started 8 | 9 | First you'll need to create a collector instance: 10 | 11 | Collector *collector = Collector_new(); 12 | 13 | 14 | Your values must contain the CollectorMarker struct as the first part of it's structure. So their struct declarations will look something like this: 15 | 16 | struct MyObjectType 17 | { 18 | CollectorMarker marker; 19 | ... 20 | }; 21 | 22 | 23 | The collector manages the CollectorMarker and your code shouldn't touch it. 24 | 25 | To tell the collector about your root value(s), call: 26 | 27 | Collector_retain_(collector, aRootValue) 28 | 29 | 30 | ## Adding Values 31 | 32 | When you allocate an object, you add the value to the collector. 33 | 34 | Collector_addValue_(collector, aValue) 35 | 36 | 37 | ## Marking 38 | 39 | You provide the means for the collector to trace the reference graph via the mark callback function. 40 | 41 | Collector_setMarkFunc_(collector, MyObjectType_mark); 42 | 43 | 44 | In your object's mark function, you'll need to call: 45 | 46 | Collector_shouldMark_(collector, referencedValue); 47 | 48 | 49 | on each of the values it references. 50 | 51 | You also need to tell the collector when a reference is added from one object to another (this is typically called the write barrier) and is required to support incremental collection. 52 | 53 | Collector_value_addingRefTo_(collector, value, referencedValue); 54 | 55 | 56 | ## Freeing 57 | 58 | Every so many Collector_addValue_() calls, the collector will do a bit of marking, and every so many marks it will do a sweep. A sweep will result in the free callback being called for each value that was found to be unreachable. 59 | 60 | You'll need to set the free callback to tell the collector which function to call when a value is found to be no longer reachable: 61 | 62 | Collector_setFreeFunc_(collector, MyObjectType_free) 63 | 64 | 65 | ## Atomic Operations 66 | 67 | When you're doing an atomic operation, like initializing a new object, it's important to call: 68 | 69 | Collector_pushPause(collector); 70 | 71 | 72 | To resume the collector, call: 73 | 74 | Collector_popPause(collector); 75 | 76 | 77 | These increment and decrement a pause count and the collector will delay any marking until the pause count is zero. 78 | 79 | ## Stacks 80 | 81 | Since the structure of the C stack is unknown, there is no way to trace it. By "stack" here I mean value stacks which hold the values being referenced by the C stack (or referenced by your language locals, if your language's stack frames aren't first class). 82 | 83 | The simplest way to deal with stacks is to call: 84 | 85 | Collector_value_addingRefTo_(collector, stackOwnerValue, newStackValue); 86 | 87 | 88 | whenever a new value is added to the stack. This will ensure that things referenced by the stack get marked. The next 2 sections describe how to ensure the stacks themselves get marked. 89 | 90 | ### Cooperative Multitasking Stacks 91 | 92 | In the case of my programming language, Io, coroutines are used for concurrency and are first class objects in the language. 93 | 94 | So if a coroutine is reachable via the root node, it will get marked and if not, no one will be able to tell it to resume, so it's safe to collect it. This works for all coroutines except the main coroutine (the one that started the program) and the current coroutine. So on startup I call: 95 | 96 | Collector_retain_(collector, mainCoroutineValue); 97 | 98 | 99 | to ensure the main coroutine won't be collected. And everytime Io resumes a coroutine, I call: 100 | 101 | Collector_setMarkBeforeSweepValue_(collector, currentCoroutineValue); 102 | 103 | 104 | Which will cause currentCoroutineValue to get marked immediately before the collector enters a sweep phase. 105 | 106 | ### Premptive Multitasking Stacks 107 | 108 | If your language uses premtive threads which cannot be collected until they are explicitly exited, then you'll need to call: 109 | 110 | Collector_retain_(collector, threadObjectValue); 111 | 112 | 113 | when a thread begins and: 114 | 115 | Collector_stopRetaining_(collector, threadObjectValue); 116 | 117 | 118 | when it ends. The retained values are stored in an array, so this is bit inefficient if you're dealing with thousands of threads that are frequently created and destroyed, but for the typical case (10s of threads with greater than one second lifetimes) it should work well. 119 | 120 | ## Globals 121 | 122 | Globals such as language primitives that should not be collected until shutdown can avoid being collected by calling: 123 | 124 | Collector_retain_(collector, someGlobalValue); 125 | 126 | 127 | on each global. 128 | 129 | ## Options 130 | 131 | The collection parameters can be adjusted with these methods: 132 | 133 | Collector_setAllocsPerMark_(collector, apm); 134 | Collector_setMarksPerSweep_(collector, mps); 135 | Collector_setSweepsPerGeneration_(collector, spg); 136 | 137 | 138 | ## Cleaning Up 139 | 140 | To free all values beign monitored by the collector, call: 141 | 142 | 143 | Collector_freeAllValues(collector); 144 | 145 | 146 | To free your collector instance, call: 147 | 148 | Collector_free(collector); 149 | 150 | 151 | ## Notes 152 | 153 | No attempt has been made to make this code safe for use when it's functions are called from multiple prememtive threads simultaniously. 154 | -------------------------------------------------------------------------------- /depends: -------------------------------------------------------------------------------- 1 | basekit -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
9 |
10 | Overview11 | 12 | libgarbagecollector is an incremental tricolor tracing collector using a Baker Treadmill. libgarbagecollector is not an allocator; it only keeps track of the objects you tell it about and determines when it is safe to free them. 13 | So you'll allocate objects using malloc() (or the allocator of your choice), and 14 | register them with the collector. When the collector finds that an object can be freed, it will call a function you give it to do the actual deallocation. 15 |16 | 17 | Getting Started18 | 19 | First you'll need to create a collector instance: 20 | 21 |22 | Collector *collector = Collector_new(); 23 |24 | 25 | Your values must contain the CollectorMarker struct as the first part of it's structure. So their struct declarations will look something like this: 26 | 27 | 28 | struct MyObjectType 29 | { 30 | CollectorMarker marker; 31 | ... 32 | }; 33 |34 | 35 | The collector manages the CollectorMarker and your code shouldn't touch it. 36 | 37 | To tell the collector about your root value(s), call: 38 | 39 | 40 | Collector_retain_(collector, aRootValue) 41 |42 | 43 | Adding Values44 | 45 |46 | When you allocate an object, you add the value to the collector. 47 | 48 | 49 | Collector_addValue_(collector, aValue) 50 |51 | 52 | 53 | Marking54 | 55 |56 | You provide the means for the collector to trace the reference graph via the mark callback function. 57 | 58 | 59 | Collector_setMarkFunc_(collector, MyObjectType_mark); 60 |61 | 62 | 63 | 64 | In your object's mark function, you'll need to call: 65 | 66 | 67 | Collector_shouldMark_(collector, referencedValue); 68 |69 | 70 | on each of the values it references. 71 | 72 | 73 | You also need to tell the collector when a reference is added from one object to another (this is typically called the write barrier) and is required to support incremental collection. 74 | 75 | 76 | Collector_value_addingRefTo_(collector, value, referencedValue); 77 |78 | 79 | 80 | Freeing81 | 82 | Every so many Collector_addValue_() calls, the collector will do a bit of marking, and every so many marks it will do a sweep. A sweep will result in the free callback being called for each value that was found to be unreachable. 83 |84 | You'll need to set the free callback to tell the collector which function to call when a value is found to be no longer reachable: 85 | 86 | Collector_setFreeFunc_(collector, MyObjectType_free) 87 |88 | 89 | Atomic Operations90 | 91 | When you're doing an atomic operation, like initializing a new object, it's important to call: 92 | 93 |94 | Collector_pushPause(collector); 95 |96 | 97 | To resume the collector, call: 98 | 99 | 100 | Collector_popPause(collector); 101 |102 | 103 | These increment and decrement a pause count and the collector will delay any marking until the pause count is zero. 104 | 105 | 106 | Stacks107 | 108 | Since the structure of the C stack is unknown, there is no way to trace it. By "stack" here I mean value stacks which hold the values being referenced by the C stack (or referenced by your language locals, if your language's stack frames aren't first class). 109 | 110 |111 | The simplest way to deal with stacks is to call: 112 | 113 | 114 | Collector_value_addingRefTo_(collector, stackOwnerValue, newStackValue); 115 |116 | 117 | whenever a new value is added to the stack. This will ensure that things referenced by the stack get marked. The next 2 sections describe how to ensure the stacks themselves get marked. 118 | 119 | 120 | Cooperative Multitasking Stacks121 | 122 | In the case of my programming language, Io, coroutines are used for concurrency and are first class objects in the language. 123 |124 | So if a coroutine is reachable via the root node, it will get marked and if not, no one will be able to tell it to resume, so it's safe to collect it. This works for all coroutines except the main coroutine (the one that started the program) and the current coroutine. So on startup I call: 125 | 126 | 127 | 128 | Collector_retain_(collector, mainCoroutineValue); 129 |130 | 131 | to ensure the main coroutine won't be collected. And everytime Io resumes a coroutine, I call: 132 | 133 | 134 | Collector_setMarkBeforeSweepValue_(collector, currentCoroutineValue); 135 |136 | 137 | Which will cause currentCoroutineValue to get marked immediately before the collector enters a sweep phase. 138 | 139 | Premptive Multitasking Stacks140 | 141 | If your language uses premtive threads which cannot be collected until they are explicitly exited, then you'll need to call: 142 |143 | Collector_retain_(collector, threadObjectValue); 144 |145 | when a thread begins and: 146 | 147 | Collector_stopRetaining_(collector, threadObjectValue); 148 |149 | when it ends. The retained values are stored in an array, so this is bit inefficient if you're dealing with thousands of threads that are frequently created and destroyed, but for the typical case (10s of threads with greater than one second lifetimes) it should work well. 150 | 151 | Globals152 | 153 | Globals such as language primitives that should not be collected until shutdown can avoid being collected by calling: 154 | 155 |156 | Collector_retain_(collector, someGlobalValue); 157 |158 | 159 | on each global. 160 | 161 | Options162 | 163 | 164 | The collection parameters can be adjusted with these methods: 165 | 166 |167 | Collector_setAllocsPerMark_(collector, apm); 168 | Collector_setMarksPerSweep_(collector, mps); 169 | Collector_setSweepsPerGeneration_(collector, spg); 170 |171 | 172 | 173 | Cleaning Up174 | 175 | To free all values beign monitored by the collector, call: 176 | 177 |178 | Collector_freeAllValues(collector); 179 |180 | 181 | 182 | To free your collector instance, call: 183 | 184 | 185 | Collector_free(collector); 186 |187 | 188 | Notes189 | 190 | No attempt has been made to make this code safe for use when it's functions are called from multiple prememtive threads simultaniously. 191 | 192 | |
193 |