// SPDX-License-Identifier: GPL-2.0-or-later /** @file * Wrapper for Boehm GC. */ /* Authors: * MenTaLguY * * Copyright (C) 2004 MenTaLguY * * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ #include "inkgc/gc-core.h" #include #include #include #include #include #include #include namespace Inkscape { namespace GC { namespace { void display_warning(char *msg, GC_word arg) { g_warning(msg, arg); } void do_init() { GC_set_no_dls(1); GC_set_all_interior_pointers(1); GC_set_finalize_on_demand(0); GC_INIT(); GC_set_warn_proc(&display_warning); } void *debug_malloc(std::size_t size) { return GC_debug_malloc(size, GC_EXTRAS); } void *debug_malloc_atomic(std::size_t size) { return GC_debug_malloc_atomic(size, GC_EXTRAS); } void *debug_malloc_uncollectable(std::size_t size) { return GC_debug_malloc_uncollectable(size, GC_EXTRAS); } void *debug_malloc_atomic_uncollectable(std::size_t size) { return GC_debug_malloc_uncollectable(size, GC_EXTRAS); } std::ptrdiff_t compute_debug_base_fixup() { char *base=reinterpret_cast(GC_debug_malloc(1, GC_EXTRAS)); char *real_base=reinterpret_cast(GC_base(base)); GC_debug_free(base); return base - real_base; } inline std::ptrdiff_t const &debug_base_fixup() { static std::ptrdiff_t fixup=compute_debug_base_fixup(); return fixup; } void *debug_base(void *ptr) { char *base=reinterpret_cast(GC_base(ptr)); return base + debug_base_fixup(); } int debug_general_register_disappearing_link(void **p_ptr, void const *base) { char const *real_base = reinterpret_cast(base) - debug_base_fixup(); #if (GC_MAJOR_VERSION >= 7 && GC_MINOR_VERSION >= 4) return GC_general_register_disappearing_link(p_ptr, real_base); #else // compatibility with older Boehm GC versions return GC_general_register_disappearing_link(p_ptr, const_cast(real_base)); #endif } void dummy_do_init() {} void *dummy_base(void *) { return nullptr; } void dummy_register_finalizer(void *, CleanupFunc, void *, CleanupFunc *old_func, void **old_data) { if (old_func) { *old_func = nullptr; } if (old_data) { *old_data = nullptr; } } int dummy_general_register_disappearing_link(void **, void const *) { return false; } int dummy_unregister_disappearing_link(void **/*link*/) { return false; } std::size_t dummy_get_heap_size() { return 0; } std::size_t dummy_get_free_bytes() { return 0; } void dummy_gcollect() {} void dummy_enable() {} void dummy_disable() {} Ops enabled_ops = { &do_init, &GC_malloc, &GC_malloc_atomic, &GC_malloc_uncollectable, &GC_malloc_atomic_uncollectable, &GC_base, &GC_register_finalizer_ignore_self, #if (GC_MAJOR_VERSION >= 7 && GC_MINOR_VERSION >= 4) &GC_general_register_disappearing_link, #else // compatibility with older Boehm GC versions (int (*)(void**, const void*))(&GC_general_register_disappearing_link), #endif &GC_unregister_disappearing_link, &GC_get_heap_size, &GC_get_free_bytes, &GC_gcollect, &GC_enable, &GC_disable, &GC_free }; Ops debug_ops = { &do_init, &debug_malloc, &debug_malloc_atomic, &debug_malloc_uncollectable, &debug_malloc_atomic_uncollectable, &debug_base, &GC_debug_register_finalizer_ignore_self, &debug_general_register_disappearing_link, &GC_unregister_disappearing_link, &GC_get_heap_size, &GC_get_free_bytes, &GC_gcollect, &GC_enable, &GC_disable, &GC_debug_free }; Ops disabled_ops = { &dummy_do_init, &std::malloc, &std::malloc, &std::malloc, &std::malloc, &dummy_base, &dummy_register_finalizer, &dummy_general_register_disappearing_link, &dummy_unregister_disappearing_link, &dummy_get_heap_size, &dummy_get_free_bytes, &dummy_gcollect, &dummy_enable, &dummy_disable, &std::free }; class InvalidGCModeError : public std::runtime_error { public: InvalidGCModeError(const char *mode) : runtime_error(std::string("Unknown GC mode \"") + mode + "\"") {} }; Ops const &get_ops() { char *mode_string=std::getenv("_INKSCAPE_GC"); if (mode_string) { if (!std::strcmp(mode_string, "enable")) { return enabled_ops; } else if (!std::strcmp(mode_string, "debug")) { return debug_ops; } else if (!std::strcmp(mode_string, "disable")) { return disabled_ops; } else { throw InvalidGCModeError(mode_string); } } else { return enabled_ops; } } void die_because_not_initialized() { g_error("Attempt to use GC allocator before call to Inkscape::GC::init()"); } void *stub_malloc(std::size_t) { die_because_not_initialized(); return nullptr; } void *stub_base(void *) { die_because_not_initialized(); return nullptr; } void stub_register_finalizer_ignore_self(void *, CleanupFunc, void *, CleanupFunc *, void **) { die_because_not_initialized(); } int stub_general_register_disappearing_link(void **, void const *) { die_because_not_initialized(); return 0; } int stub_unregister_disappearing_link(void **) { die_because_not_initialized(); return 0; } std::size_t stub_get_heap_size() { die_because_not_initialized(); return 0; } std::size_t stub_get_free_bytes() { die_because_not_initialized(); return 0; } void stub_gcollect() { die_because_not_initialized(); } void stub_enable() { die_because_not_initialized(); } void stub_disable() { die_because_not_initialized(); } void stub_free(void *) { die_because_not_initialized(); } } Ops Core::_ops = { nullptr, &stub_malloc, &stub_malloc, &stub_malloc, &stub_malloc, &stub_base, &stub_register_finalizer_ignore_self, &stub_general_register_disappearing_link, &stub_unregister_disappearing_link, &stub_get_heap_size, &stub_get_free_bytes, &stub_gcollect, &stub_enable, &stub_disable, &stub_free }; void Core::init() { try { _ops = get_ops(); } catch (InvalidGCModeError &e) { g_warning("%s; enabling normal collection", e.what()); _ops = enabled_ops; } _ops.do_init(); } namespace { bool collection_requested=false; bool collection_task() { Core::gcollect(); Core::gcollect(); collection_requested=false; return false; } } void request_early_collection() { if (!collection_requested) { collection_requested=true; Glib::signal_idle().connect(sigc::ptr_fun(&collection_task)); } } } } /* Local Variables: mode:c++ c-file-style:"stroustrup" c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) indent-tabs-mode:nil fill-column:99 End: */ // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :