[glib] GIOStream: support for unemulated async close()
- From: Ryan Lortie <desrt src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] GIOStream: support for unemulated async close()
- Date: Tue, 17 Feb 2015 21:32:00 +0000 (UTC)
commit c2c0a6ae5c8a0e924cb4b3a25b6adadcad7bd87e
Author: Ryan Lortie <desrt desrt ca>
Date: Tue Jan 20 08:11:02 2015 -0500
GIOStream: support for unemulated async close()
Add an implementation of non-thread-emulated async close of a GIOStream
if either of the underlying stream objects support it.
This prevents us from calling close() functions from another thread on
an object that may not be expecting that. It also allows us to skip the
thread entirely in case our objects support a pure async close.
https://bugzilla.gnome.org/show_bug.cgi?id=741630
gio/giostream.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 78 insertions(+), 3 deletions(-)
---
diff --git a/gio/giostream.c b/gio/giostream.c
index cd177ac..185062f 100644
--- a/gio/giostream.c
+++ b/gio/giostream.c
@@ -26,6 +26,7 @@
#include "giostream.h"
#include "gasyncresult.h"
+#include "gioprivate.h"
#include "gtask.h"
/**
@@ -542,6 +543,53 @@ close_async_thread (GTask *task,
g_task_return_boolean (task, TRUE);
}
+typedef struct
+{
+ GError *error;
+ gint pending;
+} CloseAsyncData;
+
+static void
+stream_close_complete (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GTask *task = user_data;
+ CloseAsyncData *data;
+
+ data = g_task_get_task_data (task);
+ data->pending--;
+
+ if (G_IS_OUTPUT_STREAM (source))
+ {
+ GError *error = NULL;
+
+ /* Match behaviour with the sync route and give precedent to the
+ * error returned from closing the output stream.
+ */
+ g_output_stream_close_finish (G_OUTPUT_STREAM (source), result, &error);
+ if (error)
+ {
+ if (data->error)
+ g_error_free (data->error);
+ data->error = error;
+ }
+ }
+ else
+ g_input_stream_close_finish (G_INPUT_STREAM (source), result, data->error ? NULL : &data->error);
+
+ if (data->pending == 0)
+ {
+ if (data->error)
+ g_task_return_error (task, data->error);
+ else
+ g_task_return_boolean (task, TRUE);
+
+ g_slice_free (CloseAsyncData, data);
+ g_object_unref (task);
+ }
+}
+
static void
g_io_stream_real_close_async (GIOStream *stream,
int io_priority,
@@ -549,14 +597,41 @@ g_io_stream_real_close_async (GIOStream *stream,
GAsyncReadyCallback callback,
gpointer user_data)
{
+ GInputStream *input;
+ GOutputStream *output;
GTask *task;
task = g_task_new (stream, cancellable, callback, user_data);
g_task_set_check_cancellable (task, FALSE);
g_task_set_priority (task, io_priority);
-
- g_task_run_in_thread (task, close_async_thread);
- g_object_unref (task);
+
+ input = g_io_stream_get_input_stream (stream);
+ output = g_io_stream_get_output_stream (stream);
+
+ if (g_input_stream_async_close_is_via_threads (input) && g_output_stream_async_close_is_via_threads
(output))
+ {
+ /* No sense in dispatching to the thread twice -- just do it all
+ * in one go.
+ */
+ g_task_run_in_thread (task, close_async_thread);
+ g_object_unref (task);
+ }
+ else
+ {
+ CloseAsyncData *data;
+
+ /* We should avoid dispatching to another thread in case either
+ * object that would not do it for itself because it may not be
+ * threadsafe.
+ */
+ data = g_slice_new (CloseAsyncData);
+ data->error = NULL;
+ data->pending = 2;
+
+ g_task_set_task_data (task, data, NULL);
+ g_input_stream_close_async (input, io_priority, cancellable, stream_close_complete, task);
+ g_output_stream_close_async (output, io_priority, cancellable, stream_close_complete, task);
+ }
}
static gboolean
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]