diff options
author | Kjell Ahlstedt <kjell.ahlstedt@bredband.net> | 2012-03-22 19:06:33 +0100 |
---|---|---|
committer | Murray Cumming <murrayc@murrayc.com> | 2012-04-03 11:12:27 +0200 |
commit | 08c585e5f327bde1ddc25002fc4f97db03600f73 (patch) | |
tree | cb72cbcaab39b69b9415faf7226c6010208482fc | |
parent | 4bfc313d475b63650ef2ac68d6010edef3b94465 (diff) | |
download | glibmm-08c585e5f327bde1ddc25002fc4f97db03600f73.tar.gz |
Make SignalTimeout,SignalIdle::connect_once() more thread safe.
* glib/glibmm/main.cc: Don't create a sigc::connection in the connect_once()
methods. Bug #396963.
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | glib/glibmm/main.cc | 58 |
2 files changed, 59 insertions, 6 deletions
@@ -1,3 +1,10 @@ +2012-03-22 Kjell Ahlstedt <kjell.ahlstedt@bredband.net> + + Make SignalTimeout,SignalIdle::connect_once() more thread safe. + + * glib/glibmm/main.cc: Don't create a sigc::connection in the connect_once() + methods. Bug #396963. + 2012-03-30 Murray Cumming <murrayc@murrayc.com> Regenerate .defs files. diff --git a/glib/glibmm/main.cc b/glib/glibmm/main.cc index 91da7849..cf1b7c60 100644 --- a/glib/glibmm/main.cc +++ b/glib/glibmm/main.cc @@ -84,7 +84,7 @@ void* SourceConnectionNode::notify(void* data) g_source_destroy(s); // Destroying the object triggers execution of destroy_notify_handler(), - // eiter immediately or later, so we leave that to do the deletion. + // either immediately or later, so we leave that to do the deletion. } return 0; @@ -214,6 +214,26 @@ static gboolean glibmm_source_callback(void* data) return 0; } +/* Only used by SignalTimeout::connect_once() and SignalIdle::connect_once(). + * These don't use Glib::Source, to avoid the unnecessary overhead + * of a completely unused wrapper object. + */ +static gboolean glibmm_source_callback_once(void* data) +{ + SourceConnectionNode* const conn_data = static_cast<SourceConnectionNode*>(data); + + try + { + // Recreate the specific slot from the generic slot node. + (*static_cast<sigc::slot<void>*>(conn_data->get_slot()))(); + } + catch(...) + { + Glib::exception_handlers_invoke(); + } + return 0; // Destroy the event source after one call +} + static gboolean glibmm_iosource_callback(GIOChannel*, GIOCondition condition, void* data) { SourceCallbackData *const callback_data = static_cast<SourceCallbackData*>(data); @@ -251,6 +271,29 @@ static gboolean glibmm_child_watch_callback(GPid pid, gint child_status, void* d return 0; } +static void glibmm_signal_connect_once(const sigc::slot<void>& slot, int priority, + GSource* source, GMainContext* context) +{ + SourceConnectionNode* const conn_node = new SourceConnectionNode(slot); + + if (priority != G_PRIORITY_DEFAULT) + g_source_set_priority(source, priority); + + g_source_set_callback( + source, &glibmm_source_callback_once, conn_node, + &SourceConnectionNode::destroy_notify_callback); + + g_source_attach(source, context); + // GMainContext holds a reference to source until the source is dispatched and + // glibmm_source_callback_once() returns 0. Even if that has happened now + // (in another thread), conn_node and source still exist. + // SourceConnectionNode::destroy_notify_callback() has not been called, + // because the initial reference to source remains until the following call + // to g_source_unref(). + conn_node->install(source); + g_source_unref(source); +} + } // anonymous namespace @@ -315,7 +358,8 @@ sigc::connection SignalTimeout::connect(const sigc::slot<bool>& slot, void SignalTimeout::connect_once(const sigc::slot<void>& slot, unsigned int interval, int priority) { - connect(sigc::bind_return(slot, false), interval, priority); + GSource* const source = g_timeout_source_new(interval); + glibmm_signal_connect_once(slot, priority, source, context_); } /* Note that this is our equivalent of g_timeout_add_seconds(). */ @@ -344,7 +388,8 @@ sigc::connection SignalTimeout::connect_seconds(const sigc::slot<bool>& slot, void SignalTimeout::connect_seconds_once(const sigc::slot<void>& slot, unsigned int interval, int priority) { - connect_seconds(sigc::bind_return(slot, false), interval, priority); + GSource* const source = g_timeout_source_new_seconds(interval); + glibmm_signal_connect_once(slot, priority, source, context_); } SignalTimeout signal_timeout() @@ -384,7 +429,8 @@ sigc::connection SignalIdle::connect(const sigc::slot<bool>& slot, int priority) void SignalIdle::connect_once(const sigc::slot<void>& slot, int priority) { - connect(sigc::bind_return(slot, false), priority); + GSource* const source = g_idle_source_new(); + glibmm_signal_connect_once(slot, priority, source, context_); } SignalIdle signal_idle() @@ -795,7 +841,7 @@ Source::Source() { g_source_set_callback( gobject_, &glibmm_dummy_source_callback, - new SourceCallbackData(this), // our persistant callback data object + new SourceCallbackData(this), // our persistent callback data object &SourceCallbackData::destroy_notify_callback); } @@ -805,7 +851,7 @@ Source::Source(GSource* cast_item, GSourceFunc callback_func) { g_source_set_callback( gobject_, callback_func, - new SourceCallbackData(this), // our persistant callback data object + new SourceCallbackData(this), // our persistent callback data object &SourceCallbackData::destroy_notify_callback); } |