Update to version 2.33.1
[profile/ivi/glib2.git] / gio / goutputstream.c
index f40af9c..e238d8b 100644 (file)
 #include "ginputstream.h"
 #include "gioerror.h"
 #include "glibintl.h"
-
+#include "gpollableoutputstream.h"
 
 /**
  * SECTION:goutputstream
  * @short_description: Base class for implementing streaming output
  * @include: gio/gio.h
  *
- * GOutputStream has functions to write to a stream (g_output_stream_write()),
+ * #GOutputStream has functions to write to a stream (g_output_stream_write()),
  * to close a stream (g_output_stream_close()) and to flush pending writes
  * (g_output_stream_flush()). 
  *
@@ -169,7 +169,7 @@ g_output_stream_init (GOutputStream *stream)
  * is written or an error occurs; 0 is never returned (unless
  * @count is 0).
  * 
- * If @cancellable is not NULL, then the operation can be cancelled by
+ * If @cancellable is not %NULL, then the operation can be cancelled by
  * triggering the cancellable object from another thread. If the operation
  * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned. If an
  * operation was partially finished when the operation was cancelled the
@@ -248,7 +248,7 @@ g_output_stream_write (GOutputStream  *stream,
  * On a successful write of @count bytes, %TRUE is returned, and @bytes_written
  * is set to @count.
  * 
- * If there is an error during the operation FALSE is returned and @error
+ * If there is an error during the operation %FALSE is returned and @error
  * is set to indicate the error status, @bytes_written is updated to contain
  * the number of bytes written into the stream before the error occurred.
  *
@@ -551,7 +551,7 @@ _g_output_stream_close_internal (GOutputStream  *stream,
  * is important to check and report the error to the user, otherwise
  * there might be a loss of data as all data might not be written.
  * 
- * If @cancellable is not NULL, then the operation can be cancelled by
+ * If @cancellable is not %NULL, then the operation can be cancelled by
  * triggering the cancellable object from another thread. If the operation
  * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
  * Cancelling a close will still leave the stream closed, but there some streams
@@ -1266,9 +1266,21 @@ typedef struct {
   const void         *buffer;
   gsize               count_requested;
   gssize              count_written;
+
+  GCancellable       *cancellable;
+  gint                io_priority;
+  gboolean            need_idle;
 } WriteData;
 
 static void
+free_write_data (WriteData *op)
+{
+  if (op->cancellable)
+    g_object_unref (op->cancellable);
+  g_slice_free (WriteData, op);
+}
+
+static void
 write_async_thread (GSimpleAsyncResult *res,
                     GObject            *object,
                     GCancellable       *cancellable)
@@ -1285,6 +1297,60 @@ write_async_thread (GSimpleAsyncResult *res,
     g_simple_async_result_take_error (res, error);
 }
 
+static void write_async_pollable (GPollableOutputStream *stream,
+                                 GSimpleAsyncResult    *result);
+
+static gboolean
+write_async_pollable_ready (GPollableOutputStream *stream,
+                           gpointer               user_data)
+{
+  GSimpleAsyncResult *result = user_data;
+
+  write_async_pollable (stream, result);
+  return FALSE;
+}
+
+static void
+write_async_pollable (GPollableOutputStream *stream,
+                     GSimpleAsyncResult    *result)
+{
+  GError *error = NULL;
+  WriteData *op = g_simple_async_result_get_op_res_gpointer (result);
+
+  if (g_cancellable_set_error_if_cancelled (op->cancellable, &error))
+    op->count_written = -1;
+  else
+    {
+      op->count_written = G_POLLABLE_OUTPUT_STREAM_GET_INTERFACE (stream)->
+       write_nonblocking (stream, op->buffer, op->count_requested, &error);
+    }
+
+  if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
+    {
+      GSource *source;
+
+      g_error_free (error);
+      op->need_idle = FALSE;
+
+      source = g_pollable_output_stream_create_source (stream, op->cancellable);
+      g_source_set_callback (source,
+                            (GSourceFunc) write_async_pollable_ready,
+                            g_object_ref (result), g_object_unref);
+      g_source_set_priority (source, op->io_priority);
+      g_source_attach (source, g_main_context_get_thread_default ());
+      g_source_unref (source);
+      return;
+    }
+
+  if (op->count_written == -1)
+    g_simple_async_result_take_error (result, error);
+
+  if (op->need_idle)
+    g_simple_async_result_complete_in_idle (result);
+  else
+    g_simple_async_result_complete (result);
+}
+
 static void
 g_output_stream_real_write_async (GOutputStream       *stream,
                                   const void          *buffer,
@@ -1297,13 +1363,20 @@ g_output_stream_real_write_async (GOutputStream       *stream,
   GSimpleAsyncResult *res;
   WriteData *op;
 
-  op = g_new0 (WriteData, 1);
+  op = g_slice_new0 (WriteData);
   res = g_simple_async_result_new (G_OBJECT (stream), callback, user_data, g_output_stream_real_write_async);
-  g_simple_async_result_set_op_res_gpointer (res, op, g_free);
+  g_simple_async_result_set_op_res_gpointer (res, op, (GDestroyNotify) free_write_data);
   op->buffer = buffer;
   op->count_requested = count;
+  op->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+  op->io_priority = io_priority;
+  op->need_idle = TRUE;
   
-  g_simple_async_result_run_in_thread (res, write_async_thread, io_priority, cancellable);
+  if (G_IS_POLLABLE_OUTPUT_STREAM (stream) &&
+      g_pollable_output_stream_can_poll (G_POLLABLE_OUTPUT_STREAM (stream)))
+    write_async_pollable (G_POLLABLE_OUTPUT_STREAM (stream), res);
+  else
+    g_simple_async_result_run_in_thread (res, write_async_thread, io_priority, cancellable);
   g_object_unref (res);
 }