Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
gc.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
5/* Authors:
6 * MenTaLguY <mental@rydia.net>
7 *
8 * Copyright (C) 2004 MenTaLguY
9 *
10 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
11 */
12
13#include "inkgc/gc-core.h"
14#include <stdexcept>
15#include <cstring>
16#include <string>
17#include <glib.h>
18#include <sigc++/functors/ptr_fun.h>
19#include <glibmm/main.h>
20#include <cstddef>
21
22namespace Inkscape {
23namespace GC {
24
25namespace {
26
27void display_warning(char *msg, GC_word arg) {
28 g_warning(msg, arg);
29}
30
31void do_init() {
32 GC_set_no_dls(1);
33 GC_set_all_interior_pointers(1);
34 GC_set_finalize_on_demand(0);
35
36 GC_INIT();
37
38 GC_set_warn_proc(&display_warning);
39}
40
41void *debug_malloc(std::size_t size) {
42 return GC_debug_malloc(size, GC_EXTRAS);
43}
44
45void *debug_malloc_atomic(std::size_t size) {
46 return GC_debug_malloc_atomic(size, GC_EXTRAS);
47}
48
49void *debug_malloc_uncollectable(std::size_t size) {
50 return GC_debug_malloc_uncollectable(size, GC_EXTRAS);
51}
52
53void *debug_malloc_atomic_uncollectable(std::size_t size) {
54 return GC_debug_malloc_uncollectable(size, GC_EXTRAS);
55}
56
57std::ptrdiff_t compute_debug_base_fixup() {
58 char *base=reinterpret_cast<char *>(GC_debug_malloc(1, GC_EXTRAS));
59 char *real_base=reinterpret_cast<char *>(GC_base(base));
60 GC_debug_free(base);
61 return base - real_base;
62}
63
64inline std::ptrdiff_t const &debug_base_fixup() {
65 static std::ptrdiff_t fixup=compute_debug_base_fixup();
66 return fixup;
67}
68
69void *debug_base(void *ptr) {
70 char *base=reinterpret_cast<char *>(GC_base(ptr));
71 return base + debug_base_fixup();
72}
73
74int debug_general_register_disappearing_link(void **p_ptr, void const *base) {
75 char const *real_base = reinterpret_cast<char const *>(base) - debug_base_fixup();
76#if (GC_MAJOR_VERSION >= 7 && GC_MINOR_VERSION >= 4)
77 return GC_general_register_disappearing_link(p_ptr, real_base);
78#else // compatibility with older Boehm GC versions
79 return GC_general_register_disappearing_link(p_ptr, const_cast<char *>(real_base));
80#endif
81}
82
83void dummy_do_init() {}
84
85void *dummy_base(void *) { return nullptr; }
86
87void dummy_register_finalizer(void *, CleanupFunc, void *,
88 CleanupFunc *old_func, void **old_data)
89{
90 if (old_func) {
91 *old_func = nullptr;
92 }
93 if (old_data) {
94 *old_data = nullptr;
95 }
96}
97
98int dummy_general_register_disappearing_link(void **, void const *) { return false; }
99
100int dummy_unregister_disappearing_link(void **/*link*/) { return false; }
101
102std::size_t dummy_get_heap_size() { return 0; }
103
104std::size_t dummy_get_free_bytes() { return 0; }
105
106void dummy_gcollect() {}
107
108void dummy_enable() {}
109
110void dummy_disable() {}
111
112Ops enabled_ops = {
113 &do_init,
114 &GC_malloc,
115 &GC_malloc_atomic,
116 &GC_malloc_uncollectable,
117 &GC_malloc_atomic_uncollectable,
118 &GC_base,
119 &GC_register_finalizer_ignore_self,
120#if (GC_MAJOR_VERSION >= 7 && GC_MINOR_VERSION >= 4)
121 &GC_general_register_disappearing_link,
122#else // compatibility with older Boehm GC versions
123 (int (*)(void**, const void*))(&GC_general_register_disappearing_link),
124#endif
125 &GC_unregister_disappearing_link,
126 &GC_get_heap_size,
127 &GC_get_free_bytes,
128 &GC_gcollect,
129 &GC_enable,
130 &GC_disable,
131 &GC_free
132};
133
134Ops debug_ops = {
135 &do_init,
136 &debug_malloc,
137 &debug_malloc_atomic,
138 &debug_malloc_uncollectable,
139 &debug_malloc_atomic_uncollectable,
140 &debug_base,
141 &GC_debug_register_finalizer_ignore_self,
142 &debug_general_register_disappearing_link,
143 &GC_unregister_disappearing_link,
144 &GC_get_heap_size,
145 &GC_get_free_bytes,
146 &GC_gcollect,
147 &GC_enable,
148 &GC_disable,
149 &GC_debug_free
150};
151
152Ops disabled_ops = {
153 &dummy_do_init,
154 &std::malloc,
155 &std::malloc,
156 &std::malloc,
157 &std::malloc,
158 &dummy_base,
159 &dummy_register_finalizer,
160 &dummy_general_register_disappearing_link,
161 &dummy_unregister_disappearing_link,
162 &dummy_get_heap_size,
163 &dummy_get_free_bytes,
164 &dummy_gcollect,
165 &dummy_enable,
166 &dummy_disable,
167 &std::free
168};
169
170class InvalidGCModeError : public std::runtime_error {
171public:
172 InvalidGCModeError(const char *mode)
173 : runtime_error(std::string("Unknown GC mode \"") + mode + "\"")
174 {}
175};
176
177Ops const &get_ops() {
178 char *mode_string=std::getenv("_INKSCAPE_GC");
179 if (mode_string) {
180 if (!std::strcmp(mode_string, "enable")) {
181 return enabled_ops;
182 } else if (!std::strcmp(mode_string, "debug")) {
183 return debug_ops;
184 } else if (!std::strcmp(mode_string, "disable")) {
185 return disabled_ops;
186 } else {
187 throw InvalidGCModeError(mode_string);
188 }
189 } else {
190 return enabled_ops;
191 }
192}
193
194void die_because_not_initialized() {
195 g_error("Attempt to use GC allocator before call to Inkscape::GC::init()");
196}
197
198void *stub_malloc(std::size_t) {
199 die_because_not_initialized();
200 return nullptr;
201}
202
203void *stub_base(void *) {
204 die_because_not_initialized();
205 return nullptr;
206}
207
208void stub_register_finalizer_ignore_self(void *, CleanupFunc, void *,
209 CleanupFunc *, void **)
210{
211 die_because_not_initialized();
212}
213
214int stub_general_register_disappearing_link(void **, void const *) {
215 die_because_not_initialized();
216 return 0;
217}
218
219int stub_unregister_disappearing_link(void **) {
220 die_because_not_initialized();
221 return 0;
222}
223
224std::size_t stub_get_heap_size() {
225 die_because_not_initialized();
226 return 0;
227}
228
229std::size_t stub_get_free_bytes() {
230 die_because_not_initialized();
231 return 0;
232}
233
234void stub_gcollect() {
235 die_because_not_initialized();
236}
237
238void stub_enable() {
239 die_because_not_initialized();
240}
241
242void stub_disable() {
243 die_because_not_initialized();
244}
245
246void stub_free(void *) {
247 die_because_not_initialized();
248}
249
250}
251
252Ops Core::_ops = {
253 nullptr,
254 &stub_malloc,
255 &stub_malloc,
256 &stub_malloc,
257 &stub_malloc,
258 &stub_base,
259 &stub_register_finalizer_ignore_self,
260 &stub_general_register_disappearing_link,
261 &stub_unregister_disappearing_link,
262 &stub_get_heap_size,
263 &stub_get_free_bytes,
264 &stub_gcollect,
265 &stub_enable,
266 &stub_disable,
267 &stub_free
268};
269
271 try {
272 _ops = get_ops();
273 } catch (InvalidGCModeError &e) {
274 g_warning("%s; enabling normal collection", e.what());
275 _ops = enabled_ops;
276 }
277
278 _ops.do_init();
279}
280
281
282namespace {
283
284bool collection_requested=false;
285bool collection_task() {
288 collection_requested=false;
289 return false;
290}
291
292}
293
295 if (!collection_requested) {
296 collection_requested=true;
297 Glib::signal_idle().connect(sigc::ptr_fun(&collection_task));
298 }
299}
300
301}
302}
303
304/*
305 Local Variables:
306 mode:c++
307 c-file-style:"stroustrup"
308 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
309 indent-tabs-mode:nil
310 fill-column:99
311 End:
312*/
313// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
Glib::ustring msg
Wrapper for Boehm GC.
void(* CleanupFunc)(void *mem, void *data)
Definition gc-core.h:38
void request_early_collection()
Definition gc.cpp:294
Helper class to stream background task notifications as a series of messages.
STL namespace.
int mode
static void gcollect()
Definition gc-core.h:103
static Ops _ops
Definition gc-core.h:116
static void init()
Definition gc.cpp:270
void(* do_init)()
Definition gc-core.h:41