Code

Respect "relink duplicates clones" setting with linked offsets.
[inkscape.git] / src / gc.cpp
1 /** @file
2  * @brief 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 <cstring>
15 #include <string>
16 #include <glib/gmessages.h>
17 #include <sigc++/functors/ptr_fun.h>
18 #include <glibmm/main.h>
20 namespace Inkscape {
21 namespace GC {
23 namespace {
25 void display_warning(char *msg, GC_word arg) {
26     g_warning(msg, arg);
27 }
29 void do_init() {
30     GC_no_dls = 1;
31     GC_all_interior_pointers = 1;
32     GC_finalize_on_demand = 0;
34     GC_INIT();
36     GC_set_warn_proc(&display_warning);
37 }
39 void *debug_malloc(std::size_t size) {
40     return GC_debug_malloc(size, GC_EXTRAS);
41 }
43 void *debug_malloc_atomic(std::size_t size) {
44     return GC_debug_malloc_atomic(size, GC_EXTRAS);
45 }
47 void *debug_malloc_uncollectable(std::size_t size) {
48     return GC_debug_malloc_uncollectable(size, GC_EXTRAS);
49 }
51 void *debug_malloc_atomic_uncollectable(std::size_t size) {
52     return GC_debug_malloc_uncollectable(size, GC_EXTRAS);
53 }
55 std::ptrdiff_t compute_debug_base_fixup() {
56     char *base=reinterpret_cast<char *>(GC_debug_malloc(1, GC_EXTRAS));
57     char *real_base=reinterpret_cast<char *>(GC_base(base));
58     GC_debug_free(base);
59     return base - real_base;
60 }
62 inline std::ptrdiff_t const &debug_base_fixup() {
63     static std::ptrdiff_t fixup=compute_debug_base_fixup();
64     return fixup;
65 }
67 void *debug_base(void *ptr) {
68     char *base=reinterpret_cast<char *>(GC_base(ptr));
69     return base + debug_base_fixup();
70 }
72 int debug_general_register_disappearing_link(void **p_ptr, void *base) {
73     char *real_base=reinterpret_cast<char *>(base) - debug_base_fixup();
74     return GC_general_register_disappearing_link(p_ptr, real_base);
75 }
77 void dummy_do_init() {}
79 void *dummy_base(void *) { return NULL; }
81 void dummy_register_finalizer(void *, CleanupFunc, void *,
82                                       CleanupFunc *old_func, void **old_data)
83 {
84     if (old_func) {
85         *old_func = NULL;
86     }
87     if (old_data) {
88         *old_data = NULL;
89     }
90 }
92 int dummy_general_register_disappearing_link(void **, void *) { return false; }
94 int dummy_unregister_disappearing_link(void **/*link*/) { return false; }
96 std::size_t dummy_get_heap_size() { return 0; }
98 std::size_t dummy_get_free_bytes() { return 0; }
100 void dummy_gcollect() {}
102 void dummy_enable() {}
104 void dummy_disable() {}
106 Ops enabled_ops = {
107     &do_init,
108     &GC_malloc,
109     &GC_malloc_atomic,
110     &GC_malloc_uncollectable,
111     &GC_malloc_atomic_uncollectable,
112     &GC_base,
113     &GC_register_finalizer_ignore_self,
114     &GC_general_register_disappearing_link,
115     &GC_unregister_disappearing_link,
116     &GC_get_heap_size,
117     &GC_get_free_bytes,
118     &GC_gcollect,
119     &GC_enable,
120     &GC_disable,
121     &GC_free
122 };
124 Ops debug_ops = {
125     &do_init,
126     &debug_malloc,
127     &debug_malloc_atomic,
128     &debug_malloc_uncollectable,
129     &debug_malloc_atomic_uncollectable,
130     &debug_base,
131     &GC_debug_register_finalizer_ignore_self,
132     &debug_general_register_disappearing_link,
133     &GC_unregister_disappearing_link,
134     &GC_get_heap_size,
135     &GC_get_free_bytes,
136     &GC_gcollect,
137     &GC_enable,
138     &GC_disable,
139     &GC_debug_free
140 };
142 Ops disabled_ops = {
143     &dummy_do_init,
144     &std::malloc,
145     &std::malloc,
146     &std::malloc,
147     &std::malloc,
148     &dummy_base,
149     &dummy_register_finalizer,
150     &dummy_general_register_disappearing_link,
151     &dummy_unregister_disappearing_link,
152     &dummy_get_heap_size,
153     &dummy_get_free_bytes,
154     &dummy_gcollect,
155     &dummy_enable,
156     &dummy_disable,
157     &std::free
158 };
160 class InvalidGCModeError : public std::runtime_error {
161 public:
162     InvalidGCModeError(const char *mode)
163     : runtime_error(std::string("Unknown GC mode \"") + mode + "\"")
164     {}
165 };
167 Ops const &get_ops() throw (InvalidGCModeError) {
168     char *mode_string=std::getenv("_INKSCAPE_GC");
169     if (mode_string) {
170         if (!std::strcmp(mode_string, "enable")) {
171             return enabled_ops;
172         } else if (!std::strcmp(mode_string, "debug")) {
173             return debug_ops;
174         } else if (!std::strcmp(mode_string, "disable")) {
175             return disabled_ops;
176         } else {
177             throw InvalidGCModeError(mode_string);
178         }
179     } else {
180         return enabled_ops;
181     }
184 void die_because_not_initialized() {
185     g_error("Attempt to use GC allocator before call to Inkscape::GC::init()");
188 void *stub_malloc(std::size_t) {
189     die_because_not_initialized();
190     return NULL;
193 void *stub_base(void *) {
194     die_because_not_initialized();
195     return NULL;
198 void stub_register_finalizer_ignore_self(void *, CleanupFunc, void *,
199                                                  CleanupFunc *, void **)
201     die_because_not_initialized();
204 int stub_general_register_disappearing_link(void **, void *) {
205     die_because_not_initialized();
206     return 0;
209 int stub_unregister_disappearing_link(void **) {
210     die_because_not_initialized();
211     return 0;
214 std::size_t stub_get_heap_size() {
215     die_because_not_initialized();
216     return 0;
219 std::size_t stub_get_free_bytes() {
220     die_because_not_initialized();
221     return 0;
224 void stub_gcollect() {
225     die_because_not_initialized();
228 void stub_enable() {
229     die_because_not_initialized();
232 void stub_disable() {
233     die_because_not_initialized();
236 void stub_free(void *) {
237     die_because_not_initialized();
242 Ops Core::_ops = {
243     NULL,
244     &stub_malloc,
245     &stub_malloc,
246     &stub_malloc,
247     &stub_malloc,
248     &stub_base,
249     &stub_register_finalizer_ignore_self,
250     &stub_general_register_disappearing_link,
251     &stub_unregister_disappearing_link,
252     &stub_get_heap_size,
253     &stub_get_free_bytes,
254     &stub_gcollect,
255     &stub_enable,
256     &stub_disable,
257     &stub_free
258 };
260 void Core::init() {
261     try {
262         _ops = get_ops();
263     } catch (InvalidGCModeError &e) {
264         g_warning("%s; enabling normal collection", e.what());
265         _ops = enabled_ops;
266     }
268     _ops.do_init();
272 namespace {
274 bool collection_requested=false;
275 bool collection_task() {
276     Core::gcollect();
277     Core::gcollect();
278     collection_requested=false;
279     return false;
284 void request_early_collection() {
285     if (!collection_requested) {
286         collection_requested=true;
287         Glib::signal_idle().connect(sigc::ptr_fun(&collection_task));
288     }
294 /*
295   Local Variables:
296   mode:c++
297   c-file-style:"stroustrup"
298   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
299   indent-tabs-mode:nil
300   fill-column:99
301   End:
302 */
303 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :