From 59f1f5465571bac403357b59cf7bfe2723356a37 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Wed, 5 Oct 2011 10:46:57 -0400 Subject: [PATCH] Add g_main_context_ref_thread_default() Add g_main_context_ref_thread_default(), which always returns a reffed GMainContext, rather than sometimes returning a (non-reffed) GMainContext, and sometimes returning NULL. This simplifies the bookkeeping in any code that needs to keep a reference to the thread-default context for a while. https://bugzilla.gnome.org/show_bug.cgi?id=660994 --- docs/reference/glib/glib-sections.txt | 1 + gio/gdbus-2.0/codegen/codegen.py | 7 ++---- gio/gdbusconnection.c | 46 +++++++++++++---------------------- gio/gdbusinterfaceskeleton.c | 7 ++---- gio/gdbusnameowning.c | 17 ++++++------- gio/gdbusnamewatching.c | 17 ++++++------- gio/gdbusserver.c | 9 +++---- gio/gfilemonitor.c | 5 ++-- gio/gioscheduler.c | 7 ++---- gio/gsettings.c | 7 +----- gio/gsimpleasyncresult.c | 9 ++----- gio/gtlsinteraction.c | 7 ++---- glib/glib.symbols | 1 + glib/gmain.c | 34 ++++++++++++++++++++++++-- glib/gmain.h | 1 + 15 files changed, 84 insertions(+), 91 deletions(-) diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt index 27eae3b..464d72a 100644 --- a/docs/reference/glib/glib-sections.txt +++ b/docs/reference/glib/glib-sections.txt @@ -485,6 +485,7 @@ g_main_context_invoke_full g_main_context_get_thread_default +g_main_context_ref_thread_default g_main_context_push_thread_default g_main_context_pop_thread_default diff --git a/gio/gdbus-2.0/codegen/codegen.py b/gio/gdbus-2.0/codegen/codegen.py index 22e7503..cb9d775 100644 --- a/gio/gdbus-2.0/codegen/codegen.py +++ b/gio/gdbus-2.0/codegen/codegen.py @@ -2342,8 +2342,7 @@ class CodeGenerator: self.c.write(' g_list_free (skeleton->priv->changed_properties);\n') self.c.write(' if (skeleton->priv->changed_properties_idle_source != NULL)\n') self.c.write(' g_source_destroy (skeleton->priv->changed_properties_idle_source);\n') - self.c.write(' if (skeleton->priv->context != NULL)\n') - self.c.write(' g_main_context_unref (skeleton->priv->context);\n') + self.c.write(' g_main_context_unref (skeleton->priv->context);\n') self.c.write(' g_mutex_clear (&skeleton->priv->lock);\n') self.c.write(' G_OBJECT_CLASS (%s_skeleton_parent_class)->finalize (object);\n' '}\n' @@ -2514,9 +2513,7 @@ class CodeGenerator: ' skeleton->priv = G_TYPE_INSTANCE_GET_PRIVATE (skeleton, %sTYPE_%s_SKELETON, %sSkeletonPrivate);\n' %(i.name_lower, i.camel_name, i.ns_upper, i.name_upper, i.camel_name)) self.c.write(' g_mutex_init (&skeleton->priv->lock);\n') - self.c.write(' skeleton->priv->context = g_main_context_get_thread_default ();\n') - self.c.write(' if (skeleton->priv->context != NULL)\n') - self.c.write(' g_main_context_ref (skeleton->priv->context);\n') + self.c.write(' skeleton->priv->context = g_main_context_ref_thread_default ();\n') if len(i.properties) > 0: self.c.write(' skeleton->priv->properties = g_value_array_new (%d);\n'%(len(i.properties))) n = 0 diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c index ea2822a..0572653 100644 --- a/gio/gdbusconnection.c +++ b/gio/gdbusconnection.c @@ -224,10 +224,14 @@ call_destroy_notify (GMainContext *context, GDestroyNotify callback, gpointer user_data) { + GMainContext *current_context; + if (callback == NULL) goto out; - if (context == g_main_context_get_thread_default ()) + current_context = g_main_context_get_thread_default (); + if ((context == current_context) || + (current_context == NULL && context == g_main_context_default ())) { callback (user_data); } @@ -357,7 +361,7 @@ struct _GDBusConnection /* If the connection could not be established during initable_init(), this GError will set */ GError *initialization_error; - /* The result of g_main_context_get_thread_default() when the object + /* The result of g_main_context_ref_thread_default() when the object * was created (the GObject _init() function) - this is used for delivery * of the :closed GObject signal. */ @@ -536,8 +540,7 @@ g_dbus_connection_finalize (GObject *object) g_hash_table_unref (connection->map_id_to_es); g_hash_table_unref (connection->map_object_path_to_es); - if (connection->main_context_at_construction != NULL) - g_main_context_unref (connection->main_context_at_construction); + g_main_context_unref (connection->main_context_at_construction); g_free (connection->machine_id); @@ -933,9 +936,7 @@ g_dbus_connection_init (GDBusConnection *connection) connection->map_id_to_es = g_hash_table_new (g_direct_hash, g_direct_equal); - connection->main_context_at_construction = g_main_context_get_thread_default (); - if (connection->main_context_at_construction != NULL) - g_main_context_ref (connection->main_context_at_construction); + connection->main_context_at_construction = g_main_context_ref_thread_default (); connection->filters = g_ptr_array_new (); } @@ -1570,8 +1571,7 @@ send_message_data_unref (SendMessageData *data) g_object_unref (data->connection); if (data->cancellable != NULL) g_object_unref (data->cancellable); - if (data->main_context != NULL) - g_main_context_unref (data->main_context); + g_main_context_unref (data->main_context); g_free (data); } } @@ -1763,9 +1763,7 @@ g_dbus_connection_send_message_with_reply_unlocked (GDBusConnection *connect data->connection = g_object_ref (connection); data->simple = simple; data->serial = *out_serial; - data->main_context = g_main_context_get_thread_default (); - if (data->main_context != NULL) - g_main_context_ref (data->main_context); + data->main_context = g_main_context_ref_thread_default (); if (cancellable != NULL) { @@ -3195,9 +3193,7 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection, subscriber.user_data = user_data; subscriber.user_data_free_func = user_data_free_func; subscriber.id = _global_subscriber_id++; /* TODO: overflow etc. */ - subscriber.context = g_main_context_get_thread_default (); - if (subscriber.context != NULL) - g_main_context_ref (subscriber.context); + subscriber.context = g_main_context_ref_thread_default (); /* see if we've already have this rule */ signal_data = g_hash_table_lookup (connection->map_rule_to_signal_data, rule); @@ -3359,8 +3355,7 @@ g_dbus_connection_signal_unsubscribe (GDBusConnection *connection, call_destroy_notify (subscriber->context, subscriber->user_data_free_func, subscriber->user_data); - if (subscriber->context != NULL) - g_main_context_unref (subscriber->context); + g_main_context_unref (subscriber->context); } g_array_free (subscribers, TRUE); @@ -3606,8 +3601,7 @@ purge_all_signal_subscriptions (GDBusConnection *connection) call_destroy_notify (subscriber->context, subscriber->user_data_free_func, subscriber->user_data); - if (subscriber->context != NULL) - g_main_context_unref (subscriber->context); + g_main_context_unref (subscriber->context); } g_array_free (subscribers, TRUE); @@ -3692,8 +3686,7 @@ exported_interface_free (ExportedInterface *ei) ei->user_data_free_func, ei->user_data); - if (ei->context != NULL) - g_main_context_unref (ei->context); + g_main_context_unref (ei->context); g_free (ei->interface_name); _g_dbus_interface_vtable_free (ei->vtable); @@ -4752,9 +4745,7 @@ g_dbus_connection_register_object (GDBusConnection *connection, ei->interface_info = g_dbus_interface_info_ref (interface_info); g_dbus_interface_info_cache_build (ei->interface_info); ei->interface_name = g_strdup (interface_info->name); - ei->context = g_main_context_get_thread_default (); - if (ei->context != NULL) - g_main_context_ref (ei->context); + ei->context = g_main_context_ref_thread_default (); g_hash_table_insert (eo->map_if_name_to_ei, (gpointer) ei->interface_name, @@ -5594,8 +5585,7 @@ exported_subtree_free (ExportedSubtree *es) es->user_data_free_func, es->user_data); - if (es->context != NULL) - g_main_context_unref (es->context); + g_main_context_unref (es->context); _g_dbus_subtree_vtable_free (es->vtable); g_free (es->object_path); @@ -6099,9 +6089,7 @@ g_dbus_connection_register_subtree (GDBusConnection *connection, es->id = _global_subtree_registration_id++; /* TODO: overflow etc. */ es->user_data = user_data; es->user_data_free_func = user_data_free_func; - es->context = g_main_context_get_thread_default (); - if (es->context != NULL) - g_main_context_ref (es->context); + es->context = g_main_context_ref_thread_default (); g_hash_table_insert (connection->map_object_path_to_es, es->object_path, es); g_hash_table_insert (connection->map_id_to_es, diff --git a/gio/gdbusinterfaceskeleton.c b/gio/gdbusinterfaceskeleton.c index 0a81811..0cd5d6f 100644 --- a/gio/gdbusinterfaceskeleton.c +++ b/gio/gdbusinterfaceskeleton.c @@ -425,8 +425,7 @@ dispatch_data_unref (DispatchData *data) { if (g_atomic_int_dec_and_test (&data->ref_count)) { - if (data->context != NULL) - g_main_context_unref (data->context); + g_main_context_unref (data->context); g_free (data); } } @@ -587,10 +586,8 @@ g_dbus_interface_method_dispatch_helper (GDBusInterfaceSkeleton *interface data->interface = interface; data->method_call_func = method_call_func; data->invocation = invocation; - data->context = g_main_context_get_thread_default (); + data->context = g_main_context_ref_thread_default (); data->ref_count = 1; - if (data->context != NULL) - g_main_context_ref (data->context); g_io_scheduler_push_job (dispatch_in_thread_func, data, (GDestroyNotify) dispatch_data_unref, diff --git a/gio/gdbusnameowning.c b/gio/gdbusnameowning.c index 74c181a..4b1c01a 100644 --- a/gio/gdbusnameowning.c +++ b/gio/gdbusnameowning.c @@ -105,8 +105,7 @@ client_unref (Client *client) g_dbus_connection_signal_unsubscribe (client->connection, client->name_lost_subscription_id); g_object_unref (client->connection); } - if (client->main_context != NULL) - g_main_context_unref (client->main_context); + g_main_context_unref (client->main_context); g_free (client->name); if (client->user_data_free_func != NULL) client->user_data_free_func (client->user_data); @@ -206,11 +205,15 @@ schedule_call_in_idle (Client *client, CallType call_type) static void do_call (Client *client, CallType call_type) { + GMainContext *current_context; + /* only schedule in idle if we're not in the right thread */ - if (g_main_context_get_thread_default () != client->main_context) + current_context = g_main_context_ref_thread_default (); + if (current_context != client->main_context) schedule_call_in_idle (client, call_type); else actually_do_call (client, client->connection, call_type); + g_main_context_unref (current_context); } static void @@ -492,9 +495,7 @@ g_bus_own_name_on_connection (GDBusConnection *connection, client->name_lost_handler = name_lost_handler; client->user_data = user_data; client->user_data_free_func = user_data_free_func; - client->main_context = g_main_context_get_thread_default (); - if (client->main_context != NULL) - g_main_context_ref (client->main_context); + client->main_context = g_main_context_ref_thread_default (); client->connection = g_object_ref (connection); @@ -606,9 +607,7 @@ g_bus_own_name (GBusType bus_type, client->name_lost_handler = name_lost_handler; client->user_data = user_data; client->user_data_free_func = user_data_free_func; - client->main_context = g_main_context_get_thread_default (); - if (client->main_context != NULL) - g_main_context_ref (client->main_context); + client->main_context = g_main_context_ref_thread_default (); if (map_id_to_client == NULL) { diff --git a/gio/gdbusnamewatching.c b/gio/gdbusnamewatching.c index 2fd0347..3f1f544 100644 --- a/gio/gdbusnamewatching.c +++ b/gio/gdbusnamewatching.c @@ -103,8 +103,7 @@ client_unref (Client *client) } g_free (client->name); g_free (client->name_owner); - if (client->main_context != NULL) - g_main_context_unref (client->main_context); + g_main_context_unref (client->main_context); if (client->user_data_free_func != NULL) client->user_data_free_func (client->user_data); g_free (client); @@ -207,11 +206,15 @@ schedule_call_in_idle (Client *client, CallType call_type) static void do_call (Client *client, CallType call_type) { + GMainContext *current_context; + /* only schedule in idle if we're not in the right thread */ - if (g_main_context_get_thread_default () != client->main_context) + current_context = g_main_context_ref_thread_default (); + if (current_context != client->main_context) schedule_call_in_idle (client, call_type); else actually_do_call (client, client->connection, client->name_owner, call_type); + g_main_context_unref (current_context); } static void @@ -566,9 +569,7 @@ g_bus_watch_name (GBusType bus_type, client->name_vanished_handler = name_vanished_handler; client->user_data = user_data; client->user_data_free_func = user_data_free_func; - client->main_context = g_main_context_get_thread_default (); - if (client->main_context != NULL) - g_main_context_ref (client->main_context); + client->main_context = g_main_context_ref_thread_default (); if (map_id_to_client == NULL) { @@ -630,9 +631,7 @@ guint g_bus_watch_name_on_connection (GDBusConnection *connection, client->name_vanished_handler = name_vanished_handler; client->user_data = user_data; client->user_data_free_func = user_data_free_func; - client->main_context = g_main_context_get_thread_default (); - if (client->main_context != NULL) - g_main_context_ref (client->main_context); + client->main_context = g_main_context_ref_thread_default (); if (map_id_to_client == NULL) map_id_to_client = g_hash_table_new (g_direct_hash, g_direct_equal); diff --git a/gio/gdbusserver.c b/gio/gdbusserver.c index c1a098e..3fd383f 100644 --- a/gio/gdbusserver.c +++ b/gio/gdbusserver.c @@ -99,7 +99,7 @@ struct _GDBusServer gboolean is_using_listener; gulong run_signal_handler_id; - /* The result of g_main_context_get_thread_default() when the object + /* The result of g_main_context_ref_thread_default() when the object * was created (the GObject _init() function) - this is used for delivery * of the :new-connection GObject signal. */ @@ -183,8 +183,7 @@ g_dbus_server_finalize (GObject *object) */ g_free (server->nonce_file); - if (server->main_context_at_construction != NULL) - g_main_context_unref (server->main_context_at_construction); + g_main_context_unref (server->main_context_at_construction); G_OBJECT_CLASS (g_dbus_server_parent_class)->finalize (object); } @@ -434,9 +433,7 @@ g_dbus_server_class_init (GDBusServerClass *klass) static void g_dbus_server_init (GDBusServer *server) { - server->main_context_at_construction = g_main_context_get_thread_default (); - if (server->main_context_at_construction != NULL) - g_main_context_ref (server->main_context_at_construction); + server->main_context_at_construction = g_main_context_ref_thread_default (); } static gboolean diff --git a/gio/gfilemonitor.c b/gio/gfilemonitor.c index 93fd23e..6bad280 100644 --- a/gio/gfilemonitor.c +++ b/gio/gfilemonitor.c @@ -175,8 +175,7 @@ g_file_monitor_finalize (GObject *object) g_hash_table_destroy (monitor->priv->rate_limiter); - if (monitor->priv->context) - g_main_context_unref (monitor->priv->context); + g_main_context_unref (monitor->priv->context); G_OBJECT_CLASS (g_file_monitor_parent_class)->finalize (object); } @@ -273,7 +272,7 @@ g_file_monitor_init (GFileMonitor *monitor) monitor->priv->rate_limit_msec = DEFAULT_RATE_LIMIT_MSECS; monitor->priv->rate_limiter = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, NULL, (GDestroyNotify) rate_limiter_free); - monitor->priv->context = g_main_context_get_thread_default (); + monitor->priv->context = g_main_context_ref_thread_default (); } /** diff --git a/gio/gioscheduler.c b/gio/gioscheduler.c index 6e669c7..36db5f2 100644 --- a/gio/gioscheduler.c +++ b/gio/gioscheduler.c @@ -69,8 +69,7 @@ g_io_job_free (GIOSchedulerJob *job) { if (job->cancellable) g_object_unref (job->cancellable); - if (job->context) - g_main_context_unref (job->context); + g_main_context_unref (job->context); g_free (job); } @@ -224,9 +223,7 @@ g_io_scheduler_push_job (GIOSchedulerJobFunc job_func, if (cancellable) job->cancellable = g_object_ref (cancellable); - job->context = g_main_context_get_thread_default (); - if (job->context) - g_main_context_ref (job->context); + job->context = g_main_context_ref_thread_default (); G_LOCK (active_jobs); active_jobs = g_slist_prepend (active_jobs, job); diff --git a/gio/gsettings.c b/gio/gsettings.c index 01d74af..cf1d23a 100644 --- a/gio/gsettings.c +++ b/gio/gsettings.c @@ -547,12 +547,7 @@ g_settings_init (GSettings *settings) G_TYPE_SETTINGS, GSettingsPrivate); - settings->priv->main_context = g_main_context_get_thread_default (); - - if (settings->priv->main_context == NULL) - settings->priv->main_context = g_main_context_default (); - - g_main_context_ref (settings->priv->main_context); + settings->priv->main_context = g_main_context_ref_thread_default (); } static void diff --git a/gio/gsimpleasyncresult.c b/gio/gsimpleasyncresult.c index 389d3c1..178721d 100644 --- a/gio/gsimpleasyncresult.c +++ b/gio/gsimpleasyncresult.c @@ -268,8 +268,7 @@ g_simple_async_result_finalize (GObject *object) if (simple->source_object) g_object_unref (simple->source_object); - if (simple->context) - g_main_context_unref (simple->context); + g_main_context_unref (simple->context); clear_op_res (simple); @@ -292,9 +291,7 @@ g_simple_async_result_init (GSimpleAsyncResult *simple) { simple->handle_cancellation = TRUE; - simple->context = g_main_context_get_thread_default (); - if (simple->context) - g_main_context_ref (simple->context); + simple->context = g_main_context_ref_thread_default (); } /** @@ -736,8 +733,6 @@ g_simple_async_result_complete (GSimpleAsyncResult *simple) if (current_source && !g_source_is_destroyed (current_source)) { current_context = g_source_get_context (current_source); - if (current_context == g_main_context_default ()) - current_context = NULL; if (simple->context != current_context) g_warning ("g_simple_async_result_complete() called from wrong context!"); } diff --git a/gio/gtlsinteraction.c b/gio/gtlsinteraction.c index 6ad4127..41574b7 100644 --- a/gio/gtlsinteraction.c +++ b/gio/gtlsinteraction.c @@ -187,9 +187,7 @@ g_tls_interaction_init (GTlsInteraction *interaction) { interaction->priv = G_TYPE_INSTANCE_GET_PRIVATE (interaction, G_TYPE_TLS_INTERACTION, GTlsInteractionPrivate); - interaction->priv->context = g_main_context_get_thread_default (); - if (interaction->priv->context) - g_main_context_ref (interaction->priv->context); + interaction->priv->context = g_main_context_ref_thread_default (); } static void @@ -197,8 +195,7 @@ g_tls_interaction_finalize (GObject *object) { GTlsInteraction *interaction = G_TLS_INTERACTION (object); - if (interaction->priv->context) - g_main_context_unref (interaction->priv->context); + g_main_context_unref (interaction->priv->context); G_OBJECT_CLASS (g_tls_interaction_parent_class)->finalize (object); } diff --git a/glib/glib.symbols b/glib/glib.symbols index 8f1992a..cd88f17 100644 --- a/glib/glib.symbols +++ b/glib/glib.symbols @@ -581,6 +581,7 @@ g_main_context_prepare g_main_context_push_thread_default g_main_context_query g_main_context_ref +g_main_context_ref_thread_default g_main_context_release g_main_context_remove_poll g_main_context_set_poll_func diff --git a/glib/gmain.c b/glib/gmain.c index fe63b40..9a38482 100644 --- a/glib/gmain.c +++ b/glib/gmain.c @@ -719,12 +719,16 @@ g_main_context_pop_thread_default (GMainContext *context) * * Gets the thread-default #GMainContext for this thread. Asynchronous * operations that want to be able to be run in contexts other than - * the default one should call this method to get a #GMainContext to - * add their #GSources to. (Note that even in single-threaded + * the default one should call this method or + * g_main_context_ref_thread_default() to get a #GMainContext to add + * their #GSources to. (Note that even in single-threaded * programs applications may sometimes want to temporarily push a * non-default context, so it is not safe to assume that this will * always return %NULL if you are running in the default thread.) * + * If you need to hold a reference on the context, use + * g_main_context_ref_thread_default() instead. + * * Returns: (transfer none): the thread-default #GMainContext, or * %NULL if the thread-default context is the global default context. * @@ -742,6 +746,32 @@ g_main_context_get_thread_default (void) return NULL; } +/** + * g_main_context_ref_thread_default: + * + * Gets the thread-default #GMainContext for this thread, as with + * g_main_context_get_thread_default(), but also adds a reference to + * it with g_main_context_ref(). In addition, unlike + * g_main_context_get_thread_default(), if the thread-default context + * is the global default context, this will return that #GMainContext + * (with a ref added to it) rather than returning %NULL. + * + * Returns: (transfer full): the thread-default #GMainContext. Unref + * with g_main_context_unref() when you are done with it. + * + * Since: 2.32 + */ +GMainContext * +g_main_context_ref_thread_default (void) +{ + GMainContext *context; + + context = g_main_context_get_thread_default (); + if (!context) + context = g_main_context_default (); + return g_main_context_ref (context); +} + /* Hooks for adding to the main loop */ /** diff --git a/glib/gmain.h b/glib/gmain.h index 80895e2..c8229a6 100644 --- a/glib/gmain.h +++ b/glib/gmain.h @@ -342,6 +342,7 @@ GSource *g_main_current_source (void); void g_main_context_push_thread_default (GMainContext *context); void g_main_context_pop_thread_default (GMainContext *context); GMainContext *g_main_context_get_thread_default (void); +GMainContext *g_main_context_ref_thread_default (void); /* GMainLoop: */ -- 2.7.4