Code

When canvas cannot update quickly, ensure that nodes being dragged will stay selected.
[inkscape.git] / src / gc.cpp
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     }
182 void die_because_not_initialized() {
183     g_error("Attempt to use GC allocator before call to Inkscape::GC::init()");
186 void *stub_malloc(std::size_t) {
187     die_because_not_initialized();
188     return NULL;
191 void *stub_base(void *) {
192     die_because_not_initialized();
193     return NULL;
196 void stub_register_finalizer_ignore_self(void *, CleanupFunc, void *,
197                                                  CleanupFunc *, void **)
199     die_because_not_initialized();
202 int stub_general_register_disappearing_link(void **, void *) {
203     die_because_not_initialized();
204     return 0;
207 int stub_unregister_disappearing_link(void **) {
208     die_because_not_initialized();
209     return 0;
212 std::size_t stub_get_heap_size() {
213     die_because_not_initialized();
214     return 0;
217 std::size_t stub_get_free_bytes() {
218     die_because_not_initialized();
219     return 0;
222 void stub_gcollect() {
223     die_because_not_initialized();
226 void stub_enable() {
227     die_because_not_initialized();
230 void stub_disable() {
231     die_because_not_initialized();
234 void stub_free(void *) {
235     die_because_not_initialized();
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();
270 namespace {
272 bool collection_requested=false;
273 bool collection_task() {
274     Core::gcollect();
275     Core::gcollect();
276     collection_requested=false;
277     return false;
282 void request_early_collection() {
283     if (!collection_requested) {
284         collection_requested=true;
285         Glib::signal_idle().connect(sigc::ptr_fun(&collection_task));
286     }
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 :