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>
16 namespace Inkscape {
17 namespace GC {
19 namespace {
21 void display_warning(char *msg, GC_word arg) {
22 g_warning(msg, arg);
23 }
25 void do_init() {
26 GC_no_dls = 1;
27 GC_all_interior_pointers = 1;
28 GC_finalize_on_demand = 0;
30 GC_INIT();
32 GC_set_warn_proc(&display_warning);
33 }
35 void *debug_malloc(std::size_t size) {
36 return GC_debug_malloc(size, GC_EXTRAS);
37 }
39 void *debug_malloc_atomic(std::size_t size) {
40 return GC_debug_malloc_atomic(size, GC_EXTRAS);
41 }
43 void *debug_malloc_uncollectable(std::size_t size) {
44 return GC_debug_malloc_uncollectable(size, GC_EXTRAS);
45 }
47 void *debug_malloc_atomic_uncollectable(std::size_t size) {
48 return GC_debug_malloc_uncollectable(size, GC_EXTRAS);
49 }
51 std::ptrdiff_t compute_debug_base_fixup() {
52 char *base=reinterpret_cast<char *>(GC_debug_malloc(1, GC_EXTRAS));
53 char *real_base=reinterpret_cast<char *>(GC_base(base));
54 GC_debug_free(base);
55 return base - real_base;
56 }
58 inline std::ptrdiff_t const &debug_base_fixup() {
59 static std::ptrdiff_t fixup=compute_debug_base_fixup();
60 return fixup;
61 }
63 void *debug_base(void *ptr) {
64 char *base=reinterpret_cast<char *>(GC_base(ptr));
65 return base + debug_base_fixup();
66 }
68 int debug_general_register_disappearing_link(void **p_ptr, void *base) {
69 char *real_base=reinterpret_cast<char *>(base) - debug_base_fixup();
70 return GC_general_register_disappearing_link(p_ptr, real_base);
71 }
73 void dummy_do_init() {}
75 void *dummy_base(void *) { return NULL; }
77 void dummy_register_finalizer(void *, CleanupFunc, void *,
78 CleanupFunc *old_func, void **old_data)
79 {
80 if (old_func) {
81 *old_func = NULL;
82 }
83 if (old_data) {
84 *old_data = NULL;
85 }
86 }
88 int dummy_general_register_disappearing_link(void **, void *) { return false; }
90 int dummy_unregister_disappearing_link(void **link) { return false; }
92 std::size_t dummy_get_heap_size() { return 0; }
94 std::size_t dummy_get_free_bytes() { return 0; }
96 void dummy_gcollect() {}
98 void dummy_enable() {}
100 void dummy_disable() {}
102 Ops enabled_ops = {
103 &do_init,
104 &GC_malloc,
105 &GC_malloc_atomic,
106 &GC_malloc_uncollectable,
107 &GC_malloc_atomic_uncollectable,
108 &GC_base,
109 &GC_register_finalizer_ignore_self,
110 &GC_general_register_disappearing_link,
111 &GC_unregister_disappearing_link,
112 &GC_get_heap_size,
113 &GC_get_free_bytes,
114 &GC_gcollect,
115 &GC_enable,
116 &GC_disable,
117 &GC_free
118 };
120 Ops debug_ops = {
121 &do_init,
122 &debug_malloc,
123 &debug_malloc_atomic,
124 &debug_malloc_uncollectable,
125 &debug_malloc_atomic_uncollectable,
126 &debug_base,
127 &GC_debug_register_finalizer_ignore_self,
128 &debug_general_register_disappearing_link,
129 &GC_unregister_disappearing_link,
130 &GC_get_heap_size,
131 &GC_get_free_bytes,
132 &GC_gcollect,
133 &GC_enable,
134 &GC_disable,
135 &GC_debug_free
136 };
138 Ops disabled_ops = {
139 &dummy_do_init,
140 &std::malloc,
141 &std::malloc,
142 &std::malloc,
143 &std::malloc,
144 &dummy_base,
145 &dummy_register_finalizer,
146 &dummy_general_register_disappearing_link,
147 &dummy_unregister_disappearing_link,
148 &dummy_get_heap_size,
149 &dummy_get_free_bytes,
150 &dummy_gcollect,
151 &dummy_enable,
152 &dummy_disable,
153 &std::free
154 };
156 class InvalidGCModeError : public std::runtime_error {
157 public:
158 InvalidGCModeError(const char *mode)
159 : runtime_error(std::string("Unknown GC mode \"") + mode + "\"")
160 {}
161 };
163 Ops const &get_ops() throw (InvalidGCModeError) {
164 char *mode_string=std::getenv("_INKSCAPE_GC");
165 if (mode_string) {
166 if (!std::strcmp(mode_string, "enable")) {
167 return enabled_ops;
168 } else if (!std::strcmp(mode_string, "debug")) {
169 return debug_ops;
170 } else if (!std::strcmp(mode_string, "disable")) {
171 return disabled_ops;
172 } else {
173 throw InvalidGCModeError(mode_string);
174 }
175 } else {
176 return enabled_ops;
177 }
178 }
180 void die_because_not_initialized() {
181 g_error("Attempt to use GC allocator before call to Inkscape::GC::init()");
182 }
184 void *stub_malloc(std::size_t) {
185 die_because_not_initialized();
186 return NULL;
187 }
189 void *stub_base(void *) {
190 die_because_not_initialized();
191 return NULL;
192 }
194 void stub_register_finalizer_ignore_self(void *, CleanupFunc, void *,
195 CleanupFunc *, void **)
196 {
197 die_because_not_initialized();
198 }
200 int stub_general_register_disappearing_link(void **, void *) {
201 die_because_not_initialized();
202 return 0;
203 }
205 int stub_unregister_disappearing_link(void **) {
206 die_because_not_initialized();
207 return 0;
208 }
210 std::size_t stub_get_heap_size() {
211 die_because_not_initialized();
212 return 0;
213 }
215 std::size_t stub_get_free_bytes() {
216 die_because_not_initialized();
217 return 0;
218 }
220 void stub_gcollect() {
221 die_because_not_initialized();
222 }
224 void stub_enable() {
225 die_because_not_initialized();
226 }
228 void stub_disable() {
229 die_because_not_initialized();
230 }
232 void stub_free(void *) {
233 die_because_not_initialized();
234 }
236 }
238 Ops Core::_ops = {
239 NULL,
240 &stub_malloc,
241 &stub_malloc,
242 &stub_malloc,
243 &stub_malloc,
244 &stub_base,
245 &stub_register_finalizer_ignore_self,
246 &stub_general_register_disappearing_link,
247 &stub_unregister_disappearing_link,
248 &stub_get_heap_size,
249 &stub_get_free_bytes,
250 &stub_gcollect,
251 &stub_enable,
252 &stub_disable,
253 &stub_free
254 };
256 void Core::init() {
257 try {
258 _ops = get_ops();
259 } catch (InvalidGCModeError &e) {
260 g_warning("%s; enabling normal collection", e.what());
261 _ops = enabled_ops;
262 }
264 _ops.do_init();
265 }
267 }
268 }
270 /*
271 Local Variables:
272 mode:c++
273 c-file-style:"stroustrup"
274 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
275 indent-tabs-mode:nil
276 fill-column:99
277 End:
278 */
279 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :