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 <davidz@redhat.com>
This commit is contained in:
David Zeuthen 2010-07-14 12:37:32 -04:00
parent 14e37ef796
commit 914b046226
5 changed files with 158 additions and 19 deletions

View File

@ -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

View File

@ -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 <link
* linkend="g-main-context-push-thread-default">thread-default main
* loop</link> 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 <link
* linkend="g-main-context-push-thread-default">thread-default main
* loop</link> 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;
}
/* ---------------------------------------------------------------------------------------------------- */

View File

@ -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,

View File

@ -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

View File

@ -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);
/*