From 914b046226c762bae578e17f7ed9a0fdf058045a Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Wed, 14 Jul 2010 12:37:32 -0400 Subject: [PATCH] GDBusConnection: Fix up g_dbus_connection_close() ... so it is async, cancelable and returns an error. Also provide a synchronous version. This is an API/ABI break but it is expected that only very few applications use this API. Signed-off-by: David Zeuthen --- docs/reference/gio/gio-sections.txt | 2 + gio/gdbusconnection.c | 151 ++++++++++++++++++++++++---- gio/gdbusconnection.h | 14 ++- gio/gio.symbols | 2 + gio/tests/gdbus-connection.c | 8 +- 5 files changed, 158 insertions(+), 19 deletions(-) diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt index efbaf9011..e0d5b8cc9 100644 --- a/docs/reference/gio/gio-sections.txt +++ b/docs/reference/gio/gio-sections.txt @@ -2360,6 +2360,8 @@ g_dbus_connection_new_for_address_finish g_dbus_connection_new_for_address_sync g_dbus_connection_start_message_processing g_dbus_connection_close +g_dbus_connection_close_finish +g_dbus_connection_close_sync g_dbus_connection_is_closed g_dbus_connection_flush g_dbus_connection_flush_finish diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c index 80f1fe4d7..7290e2005 100644 --- a/gio/gdbusconnection.c +++ b/gio/gdbusconnection.c @@ -1036,6 +1036,7 @@ g_dbus_connection_flush_sync (GDBusConnection *connection, gboolean ret; g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); ret = FALSE; @@ -1122,46 +1123,162 @@ set_closed_unlocked (GDBusConnection *connection, /* ---------------------------------------------------------------------------------------------------- */ +static void +close_in_thread_func (GSimpleAsyncResult *res, + GObject *object, + GCancellable *cancellable) +{ + GError *error; + + error = NULL; + if (!g_dbus_connection_close_sync (G_DBUS_CONNECTION (object), + cancellable, + &error)) + { + g_simple_async_result_set_from_error (res, error); + g_error_free (error); + } +} + /** * g_dbus_connection_close: * @connection: A #GDBusConnection. + * @cancellable: A #GCancellable or %NULL. + * @callback: A #GAsyncReadyCallback to call when the request is satisfied or %NULL if you don't + * care about the result. + * @user_data: The data to pass to @callback. * * Closes @connection. Note that this never causes the process to * exit (this might only happen if the other end of a shared message * bus connection disconnects, see #GDBusConnection:exit-on-close). * - * Once the stream is closed, all operations will return + * Once the connection is closed, operations such as sending a message + * will return with the error %G_IO_ERROR_CLOSED. Closing a connection + * will not automatically flush the connection so queued messages may + * be lost. Use g_dbus_connection_flush() if you need such guarantees. + * + * If @connection is already closed, this method fails with * %G_IO_ERROR_CLOSED. * - * Note that closing a connection will not automatically flush the - * connection so queued messages may be lost. Use - * g_dbus_connection_flush() if you need such guarantees. + * When @connection has been closed, the #GDBusConnection::closed + * signal is emitted in the thread-default main + * loop of the thread that @connection was constructed in. * - * If @connection is already closed, this method does nothing. + * This is an asynchronous method. When the operation is finished, + * @callback will be invoked in the thread-default main + * loop of the thread you are calling this method from. You can + * then call g_dbus_connection_close_finish() to get the result of the + * operation. See g_dbus_connection_close_sync() for the synchronous + * version. * * Since: 2.26 */ void -g_dbus_connection_close (GDBusConnection *connection) +g_dbus_connection_close (GDBusConnection *connection, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { + GSimpleAsyncResult *simple; + g_return_if_fail (G_IS_DBUS_CONNECTION (connection)); + simple = g_simple_async_result_new (NULL, + callback, + user_data, + g_dbus_connection_close); + g_simple_async_result_run_in_thread (simple, + close_in_thread_func, + G_PRIORITY_DEFAULT, + cancellable); + g_object_unref (simple); +} + +/** + * g_dbus_connection_close_finish: + * @connection: A #GDBusConnection. + * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_connection_close(). + * @error: Return location for error or %NULL. + * + * Finishes an operation started with g_dbus_connection_close(). + * + * Returns: %TRUE if the operation succeeded, %FALSE if @error is set. + * + * Since: 2.26 + */ +gboolean +g_dbus_connection_close_finish (GDBusConnection *connection, + GAsyncResult *res, + GError **error) +{ + GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res); + gboolean ret; + + ret = FALSE; + + g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE); + g_return_val_if_fail (G_IS_ASYNC_RESULT (res), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_dbus_connection_close); + + if (g_simple_async_result_propagate_error (simple, error)) + goto out; + + ret = TRUE; + + out: + return ret; +} + +/** + * g_dbus_connection_close_sync: + * @connection: A #GDBusConnection. + * @cancellable: A #GCancellable or %NULL. + * @error: Return location for error or %NULL. + * + * Synchronously closees @connection. The calling thread is blocked + * until this is done. See g_dbus_connection_close() for the + * asynchronous version of this method and more details about what it + * does. + * + * Returns: %TRUE if the operation succeeded, %FALSE if @error is set. + * + * Since: 2.26 + */ +gboolean +g_dbus_connection_close_sync (GDBusConnection *connection, + GCancellable *cancellable, + GError **error) +{ + gboolean ret; + + g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + ret = FALSE; + CONNECTION_LOCK (connection); if (!connection->closed) { - GError *error = NULL; - - /* TODO: do this async */ - //g_debug ("closing connection %p's stream %p", connection, connection->stream); - if (!g_io_stream_close (connection->stream, NULL, &error)) - { - g_warning ("Error closing stream: %s", error->message); - g_error_free (error); - } - - set_closed_unlocked (connection, FALSE, NULL); + ret = g_io_stream_close (connection->stream, + cancellable, + error); + if (ret) + set_closed_unlocked (connection, FALSE, NULL); + } + else + { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_CLOSED, + _("The connection is closed")); } CONNECTION_UNLOCK (connection); + + return ret; } /* ---------------------------------------------------------------------------------------------------- */ diff --git a/gio/gdbusconnection.h b/gio/gdbusconnection.h index b9f8dc1ea..6dfb6fbbd 100644 --- a/gio/gdbusconnection.h +++ b/gio/gdbusconnection.h @@ -85,7 +85,6 @@ GDBusConnection *g_dbus_connection_new_for_address_sync (const gchar void g_dbus_connection_start_message_processing (GDBusConnection *connection); gboolean g_dbus_connection_is_closed (GDBusConnection *connection); -void g_dbus_connection_close (GDBusConnection *connection); GIOStream *g_dbus_connection_get_stream (GDBusConnection *connection); const gchar *g_dbus_connection_get_guid (GDBusConnection *connection); const gchar *g_dbus_connection_get_unique_name (GDBusConnection *connection); @@ -97,6 +96,19 @@ GDBusCapabilityFlags g_dbus_connection_get_capabilities (GDBusConnection /* ---------------------------------------------------------------------------------------------------- */ +void g_dbus_connection_close (GDBusConnection *connection, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean g_dbus_connection_close_finish (GDBusConnection *connection, + GAsyncResult *res, + GError **error); +gboolean g_dbus_connection_close_sync (GDBusConnection *connection, + GCancellable *cancellable, + GError **error); + +/* ---------------------------------------------------------------------------------------------------- */ + void g_dbus_connection_flush (GDBusConnection *connection, GCancellable *cancellable, GAsyncReadyCallback callback, diff --git a/gio/gio.symbols b/gio/gio.symbols index 1163edfec..62c961d31 100644 --- a/gio/gio.symbols +++ b/gio/gio.symbols @@ -1539,6 +1539,8 @@ g_dbus_connection_get_unique_name g_dbus_connection_is_closed g_dbus_connection_set_exit_on_close g_dbus_connection_close +g_dbus_connection_close_finish +g_dbus_connection_close_sync g_dbus_connection_flush g_dbus_connection_flush_finish g_dbus_connection_flush_sync diff --git a/gio/tests/gdbus-connection.c b/gio/tests/gdbus-connection.c index cd6aa0d2b..417e66cdc 100644 --- a/gio/tests/gdbus-connection.c +++ b/gio/tests/gdbus-connection.c @@ -39,6 +39,7 @@ static GMainLoop *loop = NULL; static void test_connection_life_cycle (void) { + gboolean ret; GDBusConnection *c; GDBusConnection *c2; GError *error; @@ -88,9 +89,14 @@ test_connection_life_cycle (void) g_assert_no_error (error); g_assert (c2 != NULL); g_assert (!g_dbus_connection_is_closed (c2)); - g_dbus_connection_close (c2); + ret = g_dbus_connection_close_sync (c2, NULL, &error); + g_assert_no_error (error); + g_assert (ret); _g_assert_signal_received (c2, "closed"); g_assert (g_dbus_connection_is_closed (c2)); + ret = g_dbus_connection_close_sync (c2, NULL, &error); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED); + g_assert (!ret); g_object_unref (c2); /*