From b7ad9b86d70003c065606c563578cc66dcd2ce0a Mon Sep 17 00:00:00 2001 From: Kjell Ahlstedt Date: Mon, 27 Mar 2023 15:20:04 +0200 Subject: Gio: Use callback functions with C linkage * gio/giomm/socketsource.cc: Add extern "C". * gio/src/application.[ccg|hg]: Call Application_Class::open_callback() via a local function with C linkage. * gio/src/asyncinitable.[ccg|hg]: Call AsyncInitable_Class::init_async_vfunc_callback() and init_finish_vfunc_callback() via local functions with C linkage. * gio/src/dbusobjectmanagerclient.ccg: Use a local function with C linkage instead of Glib::destroy_notify_delete. * gio/src/file.ccg: Add extern "C". * gio/src/liststore.ccg: Add a TODO comment. * gio/src/memoryinputstream.ccg: Add extern "C". * gio/src/settings.ccg: Add extern "C". * gio/src/socketcontrolmessage.[ccg|hg]: Call SocketControlMessage_Class::deserialize_async_vfunc_callback() via a local function with C linkage. Code that mixes up C linkage and C++ linkage has undefined behavior. Most compilers make no difference between C and C++ linkage, so it has not been an issue so far. Part of issue #1 --- gio/giomm/socketsource.cc | 11 ++++++----- gio/src/application.ccg | 27 +++++++++++++++++++++++---- gio/src/application.hg | 3 ++- gio/src/asyncinitable.ccg | 29 +++++++++++++++++++++++++++++ gio/src/asyncinitable.hg | 8 +++++--- gio/src/dbusobjectmanagerclient.ccg | 13 ++++++++++--- gio/src/file.ccg | 4 +++- gio/src/liststore.ccg | 6 +++++- gio/src/memoryinputstream.ccg | 8 ++++++-- gio/src/settings.ccg | 12 ++++++++---- gio/src/socketcontrolmessage.ccg | 17 +++++++++++++++++ gio/src/socketcontrolmessage.hg | 3 ++- 12 files changed, 116 insertions(+), 25 deletions(-) diff --git a/gio/giomm/socketsource.cc b/gio/giomm/socketsource.cc index e46af5dd..e95f6946 100644 --- a/gio/giomm/socketsource.cc +++ b/gio/giomm/socketsource.cc @@ -22,8 +22,9 @@ namespace { - -gboolean +extern "C" +{ +static gboolean giomm_generic_socket_callback(sigc::slot_base* slot, GIOCondition condition) { g_return_val_if_fail(slot != nullptr, FALSE); @@ -40,20 +41,20 @@ giomm_generic_socket_callback(sigc::slot_base* slot, GIOCondition condition) return 0; } -gboolean +static gboolean giomm_signalsocket_callback(GSocket*, GIOCondition condition, void* user_data) { sigc::slot_base* const slot = Glib::Source::get_slot_from_connection_node(user_data); return giomm_generic_socket_callback(slot, condition); } -gboolean +static gboolean giomm_socketsource_callback(GSocket*, GIOCondition condition, void* user_data) { sigc::slot_base* const slot = Glib::Source::get_slot_from_callback_data(user_data); return giomm_generic_socket_callback(slot, condition); } - +} // extern "C" } // anonymous namespace namespace Gio diff --git a/gio/src/application.ccg b/gio/src/application.ccg index d85ae8d7..e1a9f3f5 100644 --- a/gio/src/application.ccg +++ b/gio/src/application.ccg @@ -27,9 +27,25 @@ using Flags = Gio::Application::Flags; namespace // anonymous { +// The function pointer, Application_signal_open_funcptr, is set in +// Application_Class::class_init_function() (generated by gmmproc), making it +// possible to indirectly call an Application_Class member function from +// a function with C linkage. +using Application_signal_open_functype = void (*) (GApplication* self, GFile** files, gint n_files, const gchar* hint); +Application_signal_open_functype Application_signal_open_funcptr; + +extern "C" +{ +// Shall be static. Non-static functions with C linkage get external linkage, +// even if they are defined in an anonymous namespace. +static void +Application_signal_open_default_callback(GApplication* self, GFile** files, gint n_files, const gchar* hint) +{ + Application_signal_open_funcptr(self, files, n_files, hint); +} static void -Application_signal_open_callback( +Application_signal_open_connect_callback( GApplication* self, GFile** files, gint n_files, const gchar* hint, void* data) { using SlotType = sigc::slot; @@ -96,9 +112,10 @@ Application_signal_open_notify_callback( return; } +} // extern "C" static const Glib::SignalProxyInfo Application_signal_open_info = { "open", - (GCallback)&Application_signal_open_callback, + (GCallback)&Application_signal_open_connect_callback, (GCallback)&Application_signal_open_notify_callback }; // The add_main_option_entry*() methods that take a slot parameter are handled @@ -190,7 +207,9 @@ OptionArgCallbackDataMap option_arg_callback_data; // Accesses to option_arg_callback_data must be thread-safe. std::mutex option_arg_callback_data_mutex; -gboolean +extern "C" +{ +static gboolean Application_option_arg_callback( const gchar* option_name, const gchar* value, gpointer /* data */, GError** error) { @@ -256,7 +275,7 @@ Application_option_arg_callback( } return false; } - +} // extern "C" } // anonymous namespace namespace Gio diff --git a/gio/src/application.hg b/gio/src/application.hg index cf59206e..7de44ee1 100644 --- a/gio/src/application.hg +++ b/gio/src/application.hg @@ -428,7 +428,8 @@ protected: #m4begin _PUSH(SECTION_PCC_CLASS_INIT_DEFAULT_SIGNAL_HANDLERS) - klass->open = &open_callback; + klass->open = &Application_signal_open_default_callback; + Application_signal_open_funcptr = &open_callback; _SECTION(SECTION_PH_DEFAULT_SIGNAL_HANDLERS) static void open_callback(GApplication* self, GFile** files, gint n_files, const gchar* hint); _POP() diff --git a/gio/src/asyncinitable.ccg b/gio/src/asyncinitable.ccg index 314c5b3f..38b5dd1c 100644 --- a/gio/src/asyncinitable.ccg +++ b/gio/src/asyncinitable.ccg @@ -20,6 +20,35 @@ #include #include +namespace // anonymous +{ +using AsyncInitable_init_async_vfunc_functype = void (*) (GAsyncInitable* self, + int io_priority, GCancellable* cancellable, GAsyncReadyCallback callback, + gpointer user_data); +using AsyncInitable_init_finish_vfunc_functype = gboolean (*) (GAsyncInitable* self, + GAsyncResult* res, GError** error); + +AsyncInitable_init_async_vfunc_functype AsyncInitable_init_async_vfunc_funcptr; +AsyncInitable_init_finish_vfunc_functype AsyncInitable_init_finish_vfunc_funcptr; + +extern "C" +{ +static void +AsyncInitable_init_async_vfunc_c_callback(GAsyncInitable* self, int io_priority, + GCancellable* cancellable, GAsyncReadyCallback callback, gpointer user_data) +{ + AsyncInitable_init_async_vfunc_funcptr(self, io_priority, cancellable, callback, user_data); +} + +static gboolean +AsyncInitable_init_finish_vfunc_c_callback(GAsyncInitable* self, + GAsyncResult* res, GError** error) +{ + return AsyncInitable_init_finish_vfunc_funcptr(self, res, error); +} +} // extern "C" +} // anonymous namespace + namespace Gio { diff --git a/gio/src/asyncinitable.hg b/gio/src/asyncinitable.hg index 842ec45d..e833e83b 100644 --- a/gio/src/asyncinitable.hg +++ b/gio/src/asyncinitable.hg @@ -105,13 +105,15 @@ protected: /** @throw Glib::Errror. */ - virtual bool init_finish_vfunc(const Glib::RefPtr& res); + virtual bool init_finish_vfunc(const Glib::RefPtr& res); protected: #m4begin _PUSH(SECTION_PCC_CLASS_INIT_VFUNCS) - klass->init_async = &init_async_vfunc_callback; - klass->init_finish = &init_finish_vfunc_callback; + klass->init_async = &AsyncInitable_init_async_vfunc_c_callback; + klass->init_finish = &AsyncInitable_init_finish_vfunc_c_callback; + AsyncInitable_init_async_vfunc_funcptr = &init_async_vfunc_callback; + AsyncInitable_init_finish_vfunc_funcptr = &init_finish_vfunc_callback; _SECTION(SECTION_PH_VFUNCS) static void init_async_vfunc_callback(GAsyncInitable* self, int io_priority, GCancellable* cancellable, GAsyncReadyCallback callback, diff --git a/gio/src/dbusobjectmanagerclient.ccg b/gio/src/dbusobjectmanagerclient.ccg index 76cc808e..5450ac09 100644 --- a/gio/src/dbusobjectmanagerclient.ccg +++ b/gio/src/dbusobjectmanagerclient.ccg @@ -18,7 +18,9 @@ namespace { -GType get_proxy_type_callback(GDBusObjectManagerClient* manager, +extern "C" +{ +static GType get_proxy_type_callback(GDBusObjectManagerClient* manager, const gchar* object_path, const gchar* interface_name, gpointer user_data) { auto slot_proxy_type = static_cast(user_data); @@ -35,6 +37,11 @@ GType get_proxy_type_callback(GDBusObjectManagerClient* manager, return 0; } +static void proxy_type_callback_delete(void* data) +{ + delete static_cast(data); +} +} // extern "C" } // anonymous namespace namespace Gio @@ -56,7 +63,7 @@ ObjectManagerClient::ObjectManagerClient(const Glib::RefPtr& connect "object-path", Glib::c_str_or_nullptr(object_path), "get-proxy-type-func", slot_proxy_type ? get_proxy_type_callback : nullptr, "get-proxy-type-user-data", slot_proxy_type ? new SlotProxyType(slot_proxy_type) : nullptr, - "get-proxy-type-destroy-notify", slot_proxy_type ? Glib::destroy_notify_delete : nullptr + "get-proxy-type-destroy-notify", slot_proxy_type ? proxy_type_callback_delete : nullptr ) { if (slot_async_ready) @@ -88,7 +95,7 @@ ObjectManagerClient::ObjectManagerClient(BusType bus_type, "object-path", Glib::c_str_or_nullptr(object_path), "get-proxy-type-func", slot_proxy_type ? get_proxy_type_callback : nullptr, "get-proxy-type-user-data", slot_proxy_type ? new SlotProxyType(slot_proxy_type) : nullptr, - "get-proxy-type-destroy-notify", slot_proxy_type ? Glib::destroy_notify_delete : nullptr + "get-proxy-type-destroy-notify", slot_proxy_type ? proxy_type_callback_delete : nullptr ) { if (slot_async_ready) diff --git a/gio/src/file.ccg b/gio/src/file.ccg index 8e8204a9..484bad52 100644 --- a/gio/src/file.ccg +++ b/gio/src/file.ccg @@ -28,6 +28,8 @@ using CopySlots = std::pair; using MeasureSlots = std::pair; using LoadPartialSlots = std::pair; +extern "C" +{ static void SignalProxy_file_progress_callback( goffset current_num_bytes, goffset total_num_bytes, gpointer data) @@ -162,7 +164,7 @@ SignalProxy_file_measure_progress_callback( Glib::exception_handlers_invoke(); } } - +} // extern "C" } // anonymous namespace namespace Gio diff --git a/gio/src/liststore.ccg b/gio/src/liststore.ccg index 9c95e7ef..dd5580f3 100644 --- a/gio/src/liststore.ccg +++ b/gio/src/liststore.ccg @@ -21,6 +21,9 @@ namespace { extern "C" { +// Non-static functions with C linkage get external linkage, even if they are +// defined in an anonymous namespace. +//TODO: Declare 'static' when we can break ABI. int ListStoreBase_CompareDataFunc(gconstpointer a, gconstpointer b, gpointer user_data) { auto slot = static_cast(user_data); @@ -33,6 +36,7 @@ int ListStoreBase_CompareDataFunc(gconstpointer a, gconstpointer b, gpointer use return (*slot)(item_a, item_b); } +//TODO: Declare 'static' when we can break ABI. // gboolean is int gboolean ListStoreBase_EqualFuncFull(gconstpointer a, gconstpointer b, gpointer user_data) { @@ -45,7 +49,7 @@ gboolean ListStoreBase_EqualFuncFull(gconstpointer a, gconstpointer b, gpointer return (*slot)(item_a, item_b); } -} +} // extern "C" } // anonymous namespace namespace Gio diff --git a/gio/src/memoryinputstream.ccg b/gio/src/memoryinputstream.ccg index 920e6166..ce620f41 100644 --- a/gio/src/memoryinputstream.ccg +++ b/gio/src/memoryinputstream.ccg @@ -39,7 +39,11 @@ private: void* m_data; }; -void +extern "C" +{ +// Shall be static. Non-static functions with C linkage get external linkage, +// even if they are defined in an anonymous namespace. +static void destroy_data_callback(void* user_data) { auto slot_with_data = static_cast(user_data); @@ -56,7 +60,7 @@ destroy_data_callback(void* user_data) delete slot_with_data; } - +} // extern "C" } // anonymous namespace namespace Gio diff --git a/gio/src/settings.ccg b/gio/src/settings.ccg index 7343bb64..1651c0d5 100644 --- a/gio/src/settings.ccg +++ b/gio/src/settings.ccg @@ -33,7 +33,11 @@ struct SettingsMapSlots Gio::Settings::SlotSetMapping from_property_to_setting; }; -gboolean +extern "C" +{ +// Shall be static. Non-static functions with C linkage get external linkage, +// even if they are defined in an anonymous namespace. +static gboolean Settings_get_mapping_callback( GValue* to_value, GVariant* from_variant, gpointer user_data) { @@ -52,7 +56,7 @@ Settings_get_mapping_callback( return result; } -GVariant* +static GVariant* Settings_set_mapping_callback( const GValue* from_value, const GVariantType* expected_type, gpointer user_data) { @@ -71,12 +75,12 @@ Settings_set_mapping_callback( return result; } -void +static void Settings_map_callback_destroy(gpointer user_data) { delete static_cast(user_data); } - +} // extern "C" } // anonymous namespace namespace Gio diff --git a/gio/src/socketcontrolmessage.ccg b/gio/src/socketcontrolmessage.ccg index ff98610c..ba0924e3 100644 --- a/gio/src/socketcontrolmessage.ccg +++ b/gio/src/socketcontrolmessage.ccg @@ -17,6 +17,23 @@ #include #include +namespace // anonymous +{ +using SocketControlMessage_deserialize_vfunc_functype = GSocketControlMessage* (*) + (int level, int type, gsize size, gpointer data); + +SocketControlMessage_deserialize_vfunc_functype SocketControlMessage_deserialize_vfunc_funcptr; + +extern "C" +{ +static GSocketControlMessage* +SocketControlMessage_deserialize_vfunc_c_callback(int level, int type, gsize size, gpointer data) +{ + return SocketControlMessage_deserialize_vfunc_funcptr(level, type, size, data); +} +} // extern "C" +} // anonymous namespace + namespace Gio { // static diff --git a/gio/src/socketcontrolmessage.hg b/gio/src/socketcontrolmessage.hg index 3048d8d7..0a7005bf 100644 --- a/gio/src/socketcontrolmessage.hg +++ b/gio/src/socketcontrolmessage.hg @@ -73,7 +73,8 @@ protected: // https://gitlab.gnome.org/GNOME/glibmm/issues/52 #m4begin _PUSH(SECTION_PCC_CLASS_INIT_VFUNCS) - klass->deserialize = &deserialize_vfunc_callback; + klass->deserialize = &SocketControlMessage_deserialize_vfunc_c_callback; + SocketControlMessage_deserialize_vfunc_funcptr = &deserialize_vfunc_callback; _SECTION(SECTION_PH_VFUNCS) static GSocketControlMessage* deserialize_vfunc_callback( int level, int type, gsize size, gpointer data); -- cgit v1.2.1