1 /*
2 * Inkscape::GC - Wrapper for Boehm GC
3 *
4 * Authors:
5 * MenTaLguY <mental@rydia.net>
6 *
7 * Copyright (C) 2004 MenTaLguY
8 *
9 * Released under GNU GPL, read the file 'COPYING' for more information
10 */
12 #include "gc-core.h"
13 #include <stdexcept>
14 #include <glib/gmessages.h>
15 #include <sigc++/functors/ptr_fun.h>
16 #include <glibmm/main.h>
18 namespace Inkscape {
19 namespace GC {
21 namespace {
23 void display_warning(char *msg, GC_word arg) {
24 g_warning(msg, arg);
25 }
27 void do_init() {
28 GC_no_dls = 1;
29 GC_all_interior_pointers = 1;
30 GC_finalize_on_demand = 0;
32 GC_INIT();
34 GC_set_warn_proc(&display_warning);
35 }
37 void *debug_malloc(std::size_t size) {
38 return GC_debug_malloc(size, GC_EXTRAS);
39 }
41 void *debug_malloc_atomic(std::size_t size) {
42 return GC_debug_malloc_atomic(size, GC_EXTRAS);
43 }
45 void *debug_malloc_uncollectable(std::size_t size) {
46 return GC_debug_malloc_uncollectable(size, GC_EXTRAS);
47 }
49 void *debug_malloc_atomic_uncollectable(std::size_t size) {
50 return GC_debug_malloc_uncollectable(size, GC_EXTRAS);
51 }
53 std::ptrdiff_t compute_debug_base_fixup() {
54 char *base=reinterpret_cast<char *>(GC_debug_malloc(1, GC_EXTRAS));
55 char *real_base=reinterpret_cast<char *>(GC_base(base));
56 GC_debug_free(base);
57 return base - real_base;
58 }
60 inline std::ptrdiff_t const &debug_base_fixup() {
61 static std::ptrdiff_t fixup=compute_debug_base_fixup();
62 return fixup;
63 }
65 void *debug_base(void *ptr) {
66 char *base=reinterpret_cast<char *>(GC_base(ptr));
67 return base + debug_base_fixup();
68 }
70 int debug_general_register_disappearing_link(void **p_ptr, void *base) {
71 char *real_base=reinterpret_cast<char *>(base) - debug_base_fixup();
72 return GC_general_register_disappearing_link(p_ptr, real_base);
73 }
75 void dummy_do_init() {}
77 void *dummy_base(void *) { return NULL; }
79 void dummy_register_finalizer(void *, CleanupFunc, void *,
80 CleanupFunc *old_func, void **old_data)
81 {
82 if (old_func) {
83 *old_func = NULL;
84 }
85 if (old_data) {
86 *old_data = NULL;
87 }
88 }
90 int dummy_general_register_disappearing_link(void **, void *) { return false; }
92 int dummy_unregister_disappearing_link(void **link) { return false; }
94 std::size_t dummy_get_heap_size() { return 0; }
96 std::size_t dummy_get_free_bytes() { return 0; }
98 void dummy_gcollect() {}
100 void dummy_enable() {}
102 void dummy_disable() {}
104 Ops enabled_ops = {
105 &do_init,
106 &GC_malloc,
107 &GC_malloc_atomic,
108 &GC_malloc_uncollectable,
109 &GC_malloc_atomic_uncollectable,
110 &GC_base,
111 &GC_register_finalizer_ignore_self,
112 &GC_general_register_disappearing_link,
113 &GC_unregister_disappearing_link,
114 &GC_get_heap_size,
115 &GC_get_free_bytes,
116 &GC_gcollect,
117 &GC_enable,
118 &GC_disable,
119 &GC_free
120 };
122 Ops debug_ops = {
123 &do_init,
124 &debug_malloc,
125 &debug_malloc_atomic,
126 &debug_malloc_uncollectable,
127 &debug_malloc_atomic_uncollectable,
128 &debug_base,
129 &GC_debug_register_finalizer_ignore_self,
130 &debug_general_register_disappearing_link,
131 &GC_unregister_disappearing_link,
132 &GC_get_heap_size,
133 &GC_get_free_bytes,
134 &GC_gcollect,
135 &GC_enable,
136 &GC_disable,
137 &GC_debug_free
138 };
140 Ops disabled_ops = {
141 &dummy_do_init,
142 &std::malloc,
143 &std::malloc,
144 &std::malloc,
145 &std::malloc,
146 &dummy_base,
147 &dummy_register_finalizer,
148 &dummy_general_register_disappearing_link,
149 &dummy_unregister_disappearing_link,
150 &dummy_get_heap_size,
151 &dummy_get_free_bytes,
152 &dummy_gcollect,
153 &dummy_enable,
154 &dummy_disable,
155 &std::free
156 };
158 class InvalidGCModeError : public std::runtime_error {
159 public:
160 InvalidGCModeError(const char *mode)
161 : runtime_error(std::string("Unknown GC mode \"") + mode + "\"")
162 {}
163 };
165 Ops const &get_ops() throw (InvalidGCModeError) {
166 char *mode_string=std::getenv("_INKSCAPE_GC");
167 if (mode_string) {
168 if (!std::strcmp(mode_string, "enable")) {
169 return enabled_ops;
170 } else if (!std::strcmp(mode_string, "debug")) {
171 return debug_ops;
172 } else if (!std::strcmp(mode_string, "disable")) {
173 return disabled_ops;
174 } else {
175 throw InvalidGCModeError(mode_string);
176 }
177 } else {
178 return enabled_ops;
179 }
180 }
182 void die_because_not_initialized() {
183 g_error("Attempt to use GC allocator before call to Inkscape::GC::init()");
184 }
186 void *stub_malloc(std::size_t) {
187 die_because_not_initialized();
188 return NULL;
189 }
191 void *stub_base(void *) {
192 die_because_not_initialized();
193 return NULL;
194 }
196 void stub_register_finalizer_ignore_self(void *, CleanupFunc, void *,
197 CleanupFunc *, void **)
198 {
199 die_because_not_initialized();
200 }
202 int stub_general_register_disappearing_link(void **, void *) {
203 die_because_not_initialized();
204 return 0;
205 }
207 int stub_unregister_disappearing_link(void **) {
208 die_because_not_initialized();
209 return 0;
210 }
212 std::size_t stub_get_heap_size() {
213 die_because_not_initialized();
214 return 0;
215 }
217 std::size_t stub_get_free_bytes() {
218 die_because_not_initialized();
219 return 0;
220 }
222 void stub_gcollect() {
223 die_because_not_initialized();
224 }
226 void stub_enable() {
227 die_because_not_initialized();
228 }
230 void stub_disable() {
231 die_because_not_initialized();
232 }
234 void stub_free(void *) {
235 die_because_not_initialized();
236 }
238 }
240 Ops Core::_ops = {
241 NULL,
242 &stub_malloc,
243 &stub_malloc,
244 &stub_malloc,
245 &stub_malloc,
246 &stub_base,
247 &stub_register_finalizer_ignore_self,
248 &stub_general_register_disappearing_link,
249 &stub_unregister_disappearing_link,
250 &stub_get_heap_size,
251 &stub_get_free_bytes,
252 &stub_gcollect,
253 &stub_enable,
254 &stub_disable,
255 &stub_free
256 };
258 void Core::init() {
259 try {
260 _ops = get_ops();
261 } catch (InvalidGCModeError &e) {
262 g_warning("%s; enabling normal collection", e.what());
263 _ops = enabled_ops;
264 }
266 _ops.do_init();
267 }
270 namespace {
272 bool collection_requested=false;
273 bool collection_task() {
274 Core::gcollect();
275 Core::gcollect();
276 collection_requested=false;
277 return false;
278 }
280 }
282 void request_early_collection() {
283 if (!collection_requested) {
284 collection_requested=true;
285 Glib::signal_idle().connect(sigc::ptr_fun(&collection_task));
286 }
287 }
289 }
290 }
292 /*
293 Local Variables:
294 mode:c++
295 c-file-style:"stroustrup"
296 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
297 indent-tabs-mode:nil
298 fill-column:99
299 End:
300 */
301 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :