From: Alexander Larsson Date: Tue, 12 May 2009 14:30:15 +0000 (+0200) Subject: Import GIOStream from gnio X-Git-Tag: 2.21.1~91 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=05f544c59191ea7eab076fbb77a2e3648d52e167;p=platform%2Fupstream%2Fglib.git Import GIOStream from gnio Based on gnio rev 84516a5f544d8d5f3da368a83844e84eca8ef771 --- diff --git a/gio/Makefile.am b/gio/Makefile.am index 9a87508..78c2c3f 100644 --- a/gio/Makefile.am +++ b/gio/Makefile.am @@ -210,6 +210,7 @@ libgio_2_0_la_SOURCES = \ giomodule.c \ giomodule-priv.h \ gioscheduler.c \ + giostream.c \ gloadableicon.c \ gmount.c \ gmemoryinputstream.c \ @@ -326,6 +327,7 @@ gio_headers = \ gioerror.h \ giomodule.h \ gioscheduler.h \ + giostream.h \ gloadableicon.h \ gmount.h \ gmemoryinputstream.h \ diff --git a/gio/gio.h b/gio/gio.h index 9539a60..63d0b79 100644 --- a/gio/gio.h +++ b/gio/gio.h @@ -57,6 +57,7 @@ #include #include #include +#include #include #include #include diff --git a/gio/gio.symbols b/gio/gio.symbols index b3bedd1..9ebc37c 100644 --- a/gio/gio.symbols +++ b/gio/gio.symbols @@ -506,6 +506,21 @@ g_input_stream_clear_pending #endif #endif +#if IN_HEADER(__G_IO_STREAM_H__) +#if IN_FILE(__G_IO_STREAM_C__) +g_io_stream_get_type G_GNUC_CONST +g_io_stream_get_input_stream +g_io_stream_get_output_stream +g_io_stream_close +g_io_stream_close_async +g_io_stream_close_finish +g_io_stream_is_closed +g_io_stream_has_pending +g_io_stream_set_pending +g_io_stream_clear_pending +#endif +#endif + #if IN_HEADER(__G_IO_ERROR_H__) #if IN_FILE(__G_IO_ERROR_C__) g_io_error_quark diff --git a/gio/giostream.c b/gio/giostream.c new file mode 100644 index 0000000..3d22bd7 --- /dev/null +++ b/gio/giostream.c @@ -0,0 +1,607 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright © 2008 codethink + * Copyright © 2009 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Ryan Lortie + * Alexander Larsson + */ + +#include "config.h" +#include +#include "glibintl.h" + +#include "giostream.h" +#include +#include + +#include "gioalias.h" + +G_DEFINE_TYPE (GIOStream, g_io_stream, G_TYPE_OBJECT); + +/** + * SECTION:ginputstream + * @short_description: Base class for implementing readwrite streams + * @include: gio/gio.h + * + * GIOStream represents an object that has both read and write streams. + * Generally the two streams acts as separate input and output streams, + * but they share some common resources and state. For instance, for + * seekable streams they may use the same position in both streams. + * + * To do the actual reading and writing you need to get the substreams + * with g_io_stream_get_input_stream() and g_io_stream_get_output_stream(). + * + * To close a stream use g_io_stream_close() which will close the common + * stream object and also the individual substreams. You can also close + * the substreams themselves. In most cases this only marks the + * substream as closed, so further I/O on it fails. However, some streams + * may support "half-closed" states where one direction of the stream + * is actually shut down. + * + * Since: 2.22 + **/ + +enum +{ + PROP_0, + PROP_INPUT_STREAM, + PROP_OUTPUT_STREAM, + PROP_CLOSED +}; + +struct _GIOStreamPrivate { + guint closed : 1; + guint pending : 1; + GAsyncReadyCallback outstanding_callback; +}; + +static gboolean g_io_stream_real_close (GIOStream *stream, + GCancellable *cancellable, + GError **error); +static void g_io_stream_real_close_async (GIOStream *stream, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +static gboolean g_io_stream_real_close_finish (GIOStream *stream, + GAsyncResult *result, + GError **error); + +static void +g_io_stream_finalize (GObject *object) +{ + GIOStream *stream; + + stream = G_IO_STREAM (object); + + if (!stream->priv->closed) + g_io_stream_close (stream, NULL, NULL); + + G_OBJECT_CLASS (g_io_stream_parent_class)->finalize (object); +} + +static void +g_io_stream_dispose (GObject *object) +{ + GIOStream *stream; + + stream = G_IO_STREAM (object); + + if (!stream->priv->closed) + g_io_stream_close (stream, NULL, NULL); + + G_OBJECT_CLASS (g_io_stream_parent_class)->dispose (object); +} + +static void +g_io_stream_init (GIOStream *stream) +{ + stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream, + G_TYPE_IO_STREAM, + GIOStreamPrivate); +} + +static void +g_io_stream_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GIOStream *stream = G_IO_STREAM (object); + + switch (prop_id) + { + case PROP_CLOSED: + g_value_set_boolean (value, stream->priv->closed); + break; + + case PROP_INPUT_STREAM: + g_value_set_object (value, g_io_stream_get_input_stream (stream)); + break; + + case PROP_OUTPUT_STREAM: + g_value_set_object (value, g_io_stream_get_output_stream (stream)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +g_io_stream_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +g_io_stream_class_init (GIOStreamClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (GIOStreamPrivate)); + + gobject_class->finalize = g_io_stream_finalize; + gobject_class->dispose = g_io_stream_dispose; + gobject_class->set_property = g_io_stream_set_property; + gobject_class->get_property = g_io_stream_get_property; + + klass->close_fn = g_io_stream_real_close; + klass->close_async = g_io_stream_real_close_async; + klass->close_finish = g_io_stream_real_close_finish; + + g_object_class_install_property (gobject_class, PROP_CLOSED, + g_param_spec_boolean ("closed", + P_("Closed"), + P_("Is the stream closed"), + FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_INPUT_STREAM, + g_param_spec_object ("input-stream", + P_("Input stream"), + P_("The GInputStream to read from"), + G_TYPE_INPUT_STREAM, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_OUTPUT_STREAM, + g_param_spec_object ("output-stream", + P_("Output stream"), + P_("The GOutputStream to write to"), + G_TYPE_OUTPUT_STREAM, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); +} + +/** + * g_io_stream_is_closed: + * @stream: a #GIOStream. + * + * Checks if a stream is closed. + * + * Returns: %TRUE if the stream is closed. + * + * Since: 2.22 + **/ +gboolean +g_io_stream_is_closed (GIOStream *stream) +{ + g_return_val_if_fail (G_IS_IO_STREAM (stream), TRUE); + + return stream->priv->closed; +} + +/** + * g_io_stream_get_input_stream: + * @stream: input #GIOStream. + * + * Gets the input stream for this object. This is used + * for reading. + * + * Returns: a #GInputStream, owned by the #GIOStream do not free. + * + * Since: 2.22 + **/ +GInputStream * +g_io_stream_get_input_stream (GIOStream *io_stream) +{ + GIOStreamClass *klass; + + klass = G_IO_STREAM_GET_CLASS (io_stream); + + g_assert (klass->get_input_stream != NULL); + + return klass->get_input_stream (io_stream); +} + +/** + * g_io_stream_get_output_stream: + * @stream: input #GIOStream. + * + * Gets the output stream for this object. This is used for + * writing. + * + * Returns: a #GOutputStream, owned by the #GIOStream do not free. + * + * Since: 2.22 + **/ +GOutputStream * +g_io_stream_get_output_stream (GIOStream *io_stream) +{ + GIOStreamClass *klass; + + klass = G_IO_STREAM_GET_CLASS (io_stream); + + g_assert (klass->get_output_stream != NULL); + return klass->get_output_stream (io_stream); +} + +/** + * g_io_stream_has_pending: + * @stream: a #GIOStream. + * + * Checks if a stream has pending actions. + * + * Returns: %TRUE if @stream has pending actions. + * + * Since: 2.22 + **/ +gboolean +g_io_stream_has_pending (GIOStream *stream) +{ + g_return_val_if_fail (G_IS_IO_STREAM (stream), FALSE); + + return stream->priv->pending; +} + +/** + * g_io_stream_set_pending: + * @stream: a #GIOStream. + * @error: a #GError location to store the error occuring, or %NULL to + * ignore. + * + * Sets @stream to have actions pending. If the pending flag is + * already set or @stream is closed, it will return %FALSE and set + * @error. + * + * Return value: %TRUE if pending was previously unset and is now set. + * + * Since: 2.22 + **/ +gboolean +g_io_stream_set_pending (GIOStream *stream, + GError **error) +{ + g_return_val_if_fail (G_IS_IO_STREAM (stream), FALSE); + + if (stream->priv->closed) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED, + _("Stream is already closed")); + return FALSE; + } + + if (stream->priv->pending) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PENDING, + /* Translators: This is an error you get if there is + * already an operation running against this stream when + * you try to start one */ + _("Stream has outstanding operation")); + return FALSE; + } + + stream->priv->pending = TRUE; + return TRUE; +} + +/** + * g_io_stream_clear_pending: + * @stream: output stream + * + * Clears the pending flag on @stream. + * + * Since: 2.22 + **/ +void +g_io_stream_clear_pending (GIOStream *stream) +{ + g_return_if_fail (G_IS_IO_STREAM (stream)); + + stream->priv->pending = FALSE; +} + +static gboolean +g_io_stream_real_close (GIOStream *stream, + GCancellable *cancellable, + GError **error) +{ + gboolean res; + + res = g_output_stream_close (g_io_stream_get_output_stream (stream), + cancellable, error); + + /* If this errored out, unset error so that we don't report + further errors, but still do the following ops */ + if (error != NULL && *error != NULL) + error = NULL; + + res &= g_input_stream_close (g_io_stream_get_input_stream (stream), + cancellable, error); + + return res; +} + +/** + * g_io_stream_close: + * @stream: A #GIOStream. + * @cancellable: optional #GCancellable object, %NULL to ignore. + * @error: location to store the error occuring, or %NULL to ignore + * + * Closes the stream, releasing resources related to it. This will also + * closes the individual input and output streams, if they are not already + * closed. + * + * Once the stream is closed, all other operations will return %G_IO_ERROR_CLOSED. + * Closing a stream multiple times will not return an error. + * + * Closing a stream will automatically flush any outstanding buffers in the + * stream. + * + * Streams will be automatically closed when the last reference + * is dropped, but you might want to call this function to make sure + * resources are released as early as possible. + * + * Some streams might keep the backing store of the stream (e.g. a file descriptor) + * open after the stream is closed. See the documentation for the individual + * stream for details. + * + * On failure the first error that happened will be reported, but the close + * operation will finish as much as possible. A stream that failed to + * close will still return %G_IO_ERROR_CLOSED for all operations. Still, it + * 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 + * 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 some streams + * can use a faster close that doesn't block to e.g. check errors. + * + * The default implementation of this method just calls close on the + * individual input/output streams. + * + * Return value: %TRUE on success, %FALSE on failure + * + * Since: 2.22 + **/ +gboolean +g_io_stream_close (GIOStream *stream, + GCancellable *cancellable, + GError **error) +{ + GIOStreamClass *class; + gboolean res; + + g_return_val_if_fail (G_IS_IO_STREAM (stream), FALSE); + + class = G_IO_STREAM_GET_CLASS (stream); + + if (stream->priv->closed) + return TRUE; + + if (!g_io_stream_set_pending (stream, error)) + return FALSE; + + if (cancellable) + g_cancellable_push_current (cancellable); + + res = TRUE; + if (class->close_fn) + res = class->close_fn (stream, cancellable, error); + + if (cancellable) + g_cancellable_pop_current (cancellable); + + stream->priv->closed = TRUE; + g_io_stream_clear_pending (stream); + + return res; +} + +static void +async_ready_close_callback_wrapper (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GIOStream *stream = G_IO_STREAM (source_object); + + stream->priv->closed = TRUE; + g_io_stream_clear_pending (stream); + if (stream->priv->outstanding_callback) + (*stream->priv->outstanding_callback) (source_object, res, user_data); + g_object_unref (stream); +} + +/** + * g_io_stream_close_async: + * @stream: A #GIOStream. + * @io_priority: the io priority of the request. + * @callback: callback to call when the request is satisfied + * @user_data: the data to pass to callback function + * @cancellable: optional cancellable object + * + * Requests an asynchronous close of the stream, releasing resources + * related to it. When the operation is finished @callback will be + * called. You can then call g_io_stream_close_finish() to get + * the result of the operation. + * + * For behaviour details see g_io_stream_close(). + * + * The asyncronous methods have a default fallback that uses threads + * to implement asynchronicity, so they are optional for inheriting + * classes. However, if you override one you must override all. + * + * Since: 2.22 + **/ +void +g_io_stream_close_async (GIOStream *stream, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GIOStreamClass *class; + GSimpleAsyncResult *simple; + GError *error = NULL; + + g_return_if_fail (G_IS_IO_STREAM (stream)); + + if (stream->priv->closed) + { + simple = g_simple_async_result_new (G_OBJECT (stream), + callback, + user_data, + g_io_stream_close_async); + g_simple_async_result_complete_in_idle (simple); + g_object_unref (simple); + return; + } + + if (!g_io_stream_set_pending (stream, &error)) + { + g_simple_async_report_gerror_in_idle (G_OBJECT (stream), + callback, + user_data, + error); + g_error_free (error); + return; + } + + class = G_IO_STREAM_GET_CLASS (stream); + stream->priv->outstanding_callback = callback; + g_object_ref (stream); + class->close_async (stream, io_priority, cancellable, + async_ready_close_callback_wrapper, user_data); +} + +/** + * g_io_stream_close_finish: + * @stream: a #GIOStream. + * @result: a #GAsyncResult. + * @error: a #GError location to store the error occuring, or %NULL to + * ignore. + * + * Closes a stream. + * + * Returns: %TRUE if stream was successfully closed, %FALSE otherwise. + * + * Since: 2.22 + **/ +gboolean +g_io_stream_close_finish (GIOStream *stream, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + GIOStreamClass *class; + + g_return_val_if_fail (G_IS_IO_STREAM (stream), FALSE); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); + + if (G_IS_SIMPLE_ASYNC_RESULT (result)) + { + simple = G_SIMPLE_ASYNC_RESULT (result); + if (g_simple_async_result_propagate_error (simple, error)) + return FALSE; + + /* Special case already closed */ + if (g_simple_async_result_get_source_tag (simple) == g_io_stream_close_async) + return TRUE; + } + + class = G_IO_STREAM_GET_CLASS (stream); + return class->close_finish (stream, result, error); +} + + +static void +close_async_thread (GSimpleAsyncResult *res, + GObject *object, + GCancellable *cancellable) +{ + GIOStreamClass *class; + GError *error = NULL; + gboolean result; + + /* Auto handling of cancelation disabled, and ignore + cancellation, since we want to close things anyway, although + possibly in a quick-n-dirty way. At least we never want to leak + open handles */ + + class = G_IO_STREAM_GET_CLASS (object); + result = class->close_fn (G_IO_STREAM (object), cancellable, &error); + if (!result) + { + g_simple_async_result_set_from_error (res, error); + g_error_free (error); + } +} + +static void +g_io_stream_real_close_async (GIOStream *stream, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *res; + + res = g_simple_async_result_new (G_OBJECT (stream), + callback, + user_data, + g_io_stream_real_close_async); + + g_simple_async_result_set_handle_cancellation (res, FALSE); + + g_simple_async_result_run_in_thread (res, + close_async_thread, + io_priority, + cancellable); + g_object_unref (res); +} + +static gboolean +g_io_stream_real_close_finish (GIOStream *stream, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); + g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == + g_io_stream_real_close_async); + return TRUE; +} + +#define __G_IO_STREAM_C__ +#include "gioaliasdef.c" diff --git a/gio/giostream.h b/gio/giostream.h new file mode 100644 index 0000000..048fd4f --- /dev/null +++ b/gio/giostream.h @@ -0,0 +1,112 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright © 2008, 2009 Codethink Limited + * Copyright © 2009 Red Hat, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the licence or (at + * your option) any later version. + * + * See the included COPYING file for more information. + * + * Authors: Ryan Lortie + * Alexander Larsson + */ + +#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __G_IO_STREAM_H__ +#define __G_IO_STREAM_H__ + +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define G_TYPE_IO_STREAM (g_io_stream_get_type ()) +#define G_IO_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_IO_STREAM, GIOStream)) +#define G_IO_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_IO_STREAM, GIOStreamClass)) +#define G_IS_IO_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_IO_STREAM)) +#define G_IS_IO_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_IO_STREAM)) +#define G_IO_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_IO_STREAM, GIOStreamClass)) + +typedef struct _GIOStreamPrivate GIOStreamPrivate; +typedef struct _GIOStreamClass GIOStreamClass; + +/** + * GIOStream: + * + * Base class for read-write streams. + **/ +struct _GIOStream +{ + GObject parent_instance; + + /*< private >*/ + GIOStreamPrivate *priv; +}; + +struct _GIOStreamClass +{ + GObjectClass parent_class; + + GInputStream * (*get_input_stream) (GIOStream *stream); + GOutputStream * (*get_output_stream) (GIOStream *stream); + + gboolean (* close_fn) (GIOStream *stream, + GCancellable *cancellable, + GError **error); + void (* close_async) (GIOStream *stream, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (* close_finish) (GIOStream *stream, + GAsyncResult *result, + GError **error); + /*< private >*/ + /* Padding for future expansion */ + void (*_g_reserved1) (void); + void (*_g_reserved2) (void); + void (*_g_reserved3) (void); + void (*_g_reserved4) (void); + void (*_g_reserved5) (void); + void (*_g_reserved6) (void); + void (*_g_reserved7) (void); + void (*_g_reserved8) (void); + void (*_g_reserved9) (void); + void (*_g_reserved10) (void); +}; + +GType g_io_stream_get_type (void) G_GNUC_CONST; + +GInputStream * g_io_stream_get_input_stream (GIOStream *stream); +GOutputStream *g_io_stream_get_output_stream (GIOStream *stream); + +gboolean g_io_stream_close (GIOStream *stream, + GCancellable *cancellable, + GError **error); + +void g_io_stream_close_async (GIOStream *stream, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean g_io_stream_close_finish (GIOStream *stream, + GAsyncResult *result, + GError **error); + +gboolean g_io_stream_is_closed (GIOStream *stream); +gboolean g_io_stream_has_pending (GIOStream *stream); +gboolean g_io_stream_set_pending (GIOStream *stream, + GError **error); +void g_io_stream_clear_pending (GIOStream *stream); + +G_END_DECLS + +#endif /* __G_IO_STREAM_H__ */ diff --git a/gio/giotypes.h b/gio/giotypes.h index 41da274..9af8651 100644 --- a/gio/giotypes.h +++ b/gio/giotypes.h @@ -102,6 +102,7 @@ typedef struct _GMountOperation GMountOperation; typedef struct _GNetworkAddress GNetworkAddress; typedef struct _GNetworkService GNetworkService; typedef struct _GOutputStream GOutputStream; +typedef struct _GIOStream GIOStream; typedef struct _GResolver GResolver; typedef struct _GSeekable GSeekable; typedef struct _GSimpleAsyncResult GSimpleAsyncResult;