From: Mike Gorse Date: Sun, 15 Jan 2012 18:29:56 +0000 (-0600) Subject: Avoid making calls on processes thought to be hung X-Git-Tag: AT_SPI2_CORE_2_3_4~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2291c9e97f9fad6cd7de746e5521b90ddbb56233;p=platform%2Fupstream%2Fat-spi2-core.git Avoid making calls on processes thought to be hung If a method call times out, record the process as being hung, and send a ping. Consider the process to be no longer hung when a response to the ping is received. Hopefully this will prevent long delays if an AT makes consecutive calls on an application that is not responding. --- diff --git a/atspi/atspi-misc.c b/atspi/atspi-misc.c index e2ccf10..94b5f9e 100644 --- a/atspi/atspi-misc.c +++ b/atspi/atspi-misc.c @@ -398,7 +398,6 @@ get_reference_from_iter (DBusMessageIter *iter, const char **app_name, const cha static void add_accessible_from_iter (DBusMessageIter *iter) { - GList *new_list; DBusMessageIter iter_struct, iter_array; const char *app_name, *path; AtspiAccessible *accessible; @@ -434,8 +433,7 @@ add_accessible_from_iter (DBusMessageIter *iter) AtspiAccessible *child; get_reference_from_iter (&iter_array, &app_name, &path); child = ref_accessible (app_name, path); - new_list = g_list_append (accessible->children, child); - if (new_list) accessible->children = new_list; + accessible->children = g_list_append (accessible->children, child); } /* interfaces */ @@ -927,6 +925,77 @@ atspi_exit (void) return leaked; } +static GSList *hung_processes; + +static void +remove_hung_process (DBusPendingCall *pending, void *data) +{ + gchar *bus_name = data; + + hung_processes = g_slist_remove (hung_processes, data); + g_free (data); + dbus_pending_call_unref (pending); +} + +static void +check_for_hang (DBusMessage *message, DBusError *error, DBusConnection *bus, const char *bus_name) +{ + if (!message && error->name && + !strcmp (error->name, "org.freedesktop.DBus.Error.NoReply")) + { + GSList *l; + DBusMessage *message; + gchar *bus_name_dup; + DBusPendingCall *pending = NULL; + for (l = hung_processes; l; l = l->next) + if (!strcmp (l->data, bus_name)) + return; + message = dbus_message_new_method_call (bus_name, "/", + "org.freedesktop.DBus.Peer", + "Ping"); + if (!message) + return; + dbus_connection_send_with_reply (bus, message, &pending, -1); + dbus_message_unref (message); + if (!pending) + return; + bus_name_dup = g_strdup (bus_name); + hung_processes = g_slist_append (hung_processes, bus_name_dup); + dbus_pending_call_set_notify (pending, remove_hung_process, bus_name_dup, NULL); + } +} + +static gboolean +connection_is_hung (const char *bus_name) +{ + GSList *l; + + for (l = hung_processes; l; l = l->next) + if (!strcmp (l->data, bus_name)) + return TRUE; + return FALSE; +} + +static gboolean +check_app (AtspiApplication *app, GError **error) +{ + if (!app || !app->bus) + { + g_set_error_literal (error, ATSPI_ERROR, ATSPI_ERROR_APPLICATION_GONE, + _("The application no longer exists")); + return FALSE; + } + + if (atspi_main_loop && connection_is_hung (app->bus_name)) + { + g_set_error_literal (error, ATSPI_ERROR, ATSPI_ERROR_IPC, + "The process appears to be hung."); + return FALSE; + } + + return TRUE; +} + dbus_bool_t _atspi_dbus_call (gpointer obj, const char *interface, const char *method, GError **error, const char *type, ...) { @@ -935,12 +1004,8 @@ _atspi_dbus_call (gpointer obj, const char *interface, const char *method, GErro DBusError err; AtspiObject *aobj = ATSPI_OBJECT (obj); - if (!aobj->app || !aobj->app->bus) - { - g_set_error_literal (error, ATSPI_ERROR, ATSPI_ERROR_APPLICATION_GONE, - _("The application no longer exists")); + if (!check_app (aobj->app, error)) return FALSE; - } va_start (args, type); dbus_error_init (&err); @@ -948,6 +1013,7 @@ _atspi_dbus_call (gpointer obj, const char *interface, const char *method, GErro aobj->path, interface, method, &err, type, args); va_end (args); + check_for_hang (NULL, &err, aobj->app->bus, aobj->app->bus_name); _atspi_process_deferred_messages ((gpointer)TRUE); if (dbus_error_is_set (&err)) { @@ -970,6 +1036,7 @@ _atspi_dbus_call_partial (gpointer obj, return _atspi_dbus_call_partial_va (obj, interface, method, error, type, args); } + DBusMessage * _atspi_dbus_call_partial_va (gpointer obj, const char *interface, @@ -986,22 +1053,19 @@ _atspi_dbus_call_partial_va (gpointer obj, dbus_error_init (&err); - if (!aobj->app || !aobj->app->bus) - { - g_set_error_literal (error, ATSPI_ERROR, ATSPI_ERROR_APPLICATION_GONE, - _("The application no longer exists")); + if (!check_app (aobj->app, error)) goto out; - } - msg = dbus_message_new_method_call (aobj->app->bus_name, aobj->path, interface, method); - if (!msg) - goto out; + msg = dbus_message_new_method_call (aobj->app->bus_name, aobj->path, interface, method); + if (!msg) + goto out; - p = type; - dbus_message_iter_init_append (msg, &iter); - dbind_any_marshal_va (&iter, &p, args); + p = type; + dbus_message_iter_init_append (msg, &iter); + dbind_any_marshal_va (&iter, &p, args); - reply = dbind_send_and_allow_reentry (aobj->app->bus, msg, &err); + reply = dbind_send_and_allow_reentry (aobj->app->bus, msg, &err); + check_for_hang (reply, &err, aobj->app->bus, aobj->app->bus_name); out: va_end (args); if (msg) @@ -1028,12 +1092,8 @@ _atspi_dbus_get_property (gpointer obj, const char *interface, const char *name, if (!aobj) return FALSE; - if (!aobj->app || !aobj->app->bus) - { - g_set_error_literal (error, ATSPI_ERROR, ATSPI_ERROR_APPLICATION_GONE, - _("The application no longer exists")); + if (!check_app (aobj->app, error)) return FALSE; - } message = dbus_message_new_method_call (aobj->app->bus_name, aobj->path, @@ -1047,6 +1107,7 @@ _atspi_dbus_get_property (gpointer obj, const char *interface, const char *name, dbus_message_append_args (message, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID); dbus_error_init (&err); reply = dbind_send_and_allow_reentry (aobj->app->bus, message, &err); + check_for_hang (reply, &err, aobj->app->bus, aobj->app->bus_name); dbus_message_unref (message); _atspi_process_deferred_messages ((gpointer)TRUE); if (!reply) @@ -1320,7 +1381,7 @@ get_accessibility_bus_address_dbus (void) { g_warning ("Error retrieving accessibility bus address: %s: %s", error.name, error.message); - dbus_error_init (&error); + dbus_error_free (&error); return NULL; } diff --git a/dbind/dbind.c b/dbind/dbind.c index 167c3e8..3989bb6 100644 --- a/dbind/dbind.c +++ b/dbind/dbind.c @@ -87,12 +87,18 @@ dbind_send_and_allow_reentry (DBusConnection * bus, DBusMessage * message, DBusE dbus_pending_call_ref (pending); while (!closure->reply) { - if (!dbus_connection_read_write_dispatch (bus, dbind_timeout) || - time_elapsed (&tv) > dbind_timeout) + if (!dbus_connection_read_write_dispatch (bus, dbind_timeout)) { dbus_pending_call_unref (pending); return NULL; } + if (time_elapsed (&tv) > dbind_timeout) + { + dbus_pending_call_unref (pending); + dbus_set_error_const (error, "org.freedesktop.DBus.Error.NoReply", + "timeout from dbind"); + return NULL; + } } ret = closure->reply;