mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-07-30 13:53:30 +02:00
gio: use GPollable* to implement fallback read_async/write_async
If a GInputStream does not provide a read_async() implementation, but does implement GPollableInputStream, then instead of doing read-synchronously-in-a-thread, just use g_pollable_input_stream_read_nonblocking() and g_pollable_input_stream_create_source() to implement an async read in the same thread. Similarly for GOutputStream. Remove a bunch of existing read_async()/write_async() implementations that are basically equivalent to the new fallback method. https://bugzilla.gnome.org/show_bug.cgi?id=673997
This commit is contained in:
@@ -100,16 +100,6 @@ static gssize g_buffered_input_stream_read (GInputStream *s
|
||||
gsize count,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
static void g_buffered_input_stream_read_async (GInputStream *stream,
|
||||
void *buffer,
|
||||
gsize count,
|
||||
int io_priority,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
static gssize g_buffered_input_stream_read_finish (GInputStream *stream,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
static gssize g_buffered_input_stream_real_fill (GBufferedInputStream *stream,
|
||||
gssize count,
|
||||
GCancellable *cancellable,
|
||||
@@ -150,8 +140,6 @@ g_buffered_input_stream_class_init (GBufferedInputStreamClass *klass)
|
||||
istream_class->skip_async = g_buffered_input_stream_skip_async;
|
||||
istream_class->skip_finish = g_buffered_input_stream_skip_finish;
|
||||
istream_class->read_fn = g_buffered_input_stream_read;
|
||||
istream_class->read_async = g_buffered_input_stream_read_async;
|
||||
istream_class->read_finish = g_buffered_input_stream_read_finish;
|
||||
|
||||
bstream_class = G_BUFFERED_INPUT_STREAM_CLASS (klass);
|
||||
bstream_class->fill = g_buffered_input_stream_real_fill;
|
||||
@@ -1017,189 +1005,6 @@ g_buffered_input_stream_real_fill_finish (GBufferedInputStream *stream,
|
||||
return nread;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gssize bytes_read;
|
||||
gssize count;
|
||||
void *buffer;
|
||||
} ReadAsyncData;
|
||||
|
||||
static void
|
||||
free_read_async_data (gpointer _data)
|
||||
{
|
||||
ReadAsyncData *data = _data;
|
||||
g_slice_free (ReadAsyncData, data);
|
||||
}
|
||||
|
||||
static void
|
||||
large_read_callback (GObject *source_object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
|
||||
ReadAsyncData *data;
|
||||
GError *error;
|
||||
gssize nread;
|
||||
|
||||
data = g_simple_async_result_get_op_res_gpointer (simple);
|
||||
|
||||
error = NULL;
|
||||
nread = g_input_stream_read_finish (G_INPUT_STREAM (source_object),
|
||||
result, &error);
|
||||
|
||||
/* Only report the error if we've not already read some data */
|
||||
if (nread < 0 && data->bytes_read == 0)
|
||||
g_simple_async_result_take_error (simple, error);
|
||||
else if (error)
|
||||
g_error_free (error);
|
||||
|
||||
if (nread > 0)
|
||||
data->bytes_read += nread;
|
||||
|
||||
/* Complete immediately, not in idle, since we're already
|
||||
* in a mainloop callout
|
||||
*/
|
||||
g_simple_async_result_complete (simple);
|
||||
g_object_unref (simple);
|
||||
}
|
||||
|
||||
static void
|
||||
read_fill_buffer_callback (GObject *source_object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
|
||||
GBufferedInputStream *bstream;
|
||||
GBufferedInputStreamPrivate *priv;
|
||||
ReadAsyncData *data;
|
||||
GError *error;
|
||||
gssize nread;
|
||||
gsize available;
|
||||
|
||||
bstream = G_BUFFERED_INPUT_STREAM (source_object);
|
||||
priv = bstream->priv;
|
||||
|
||||
data = g_simple_async_result_get_op_res_gpointer (simple);
|
||||
|
||||
error = NULL;
|
||||
nread = g_buffered_input_stream_fill_finish (bstream,
|
||||
result, &error);
|
||||
|
||||
if (nread < 0 && data->bytes_read == 0)
|
||||
g_simple_async_result_take_error (simple, error);
|
||||
else if (error)
|
||||
g_error_free (error);
|
||||
|
||||
if (nread > 0)
|
||||
{
|
||||
available = priv->end - priv->pos;
|
||||
data->count = MIN (data->count, available);
|
||||
|
||||
memcpy ((char *)data->buffer + data->bytes_read, (char *)priv->buffer + priv->pos, data->count);
|
||||
data->bytes_read += data->count;
|
||||
priv->pos += data->count;
|
||||
}
|
||||
|
||||
/* Complete immediately, not in idle, since we're already
|
||||
* in a mainloop callout
|
||||
*/
|
||||
g_simple_async_result_complete (simple);
|
||||
g_object_unref (simple);
|
||||
}
|
||||
|
||||
static void
|
||||
g_buffered_input_stream_read_async (GInputStream *stream,
|
||||
void *buffer,
|
||||
gsize count,
|
||||
int io_priority,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GBufferedInputStream *bstream;
|
||||
GBufferedInputStreamPrivate *priv;
|
||||
GBufferedInputStreamClass *class;
|
||||
GInputStream *base_stream;
|
||||
gsize available;
|
||||
GSimpleAsyncResult *simple;
|
||||
ReadAsyncData *data;
|
||||
|
||||
bstream = G_BUFFERED_INPUT_STREAM (stream);
|
||||
priv = bstream->priv;
|
||||
|
||||
data = g_slice_new (ReadAsyncData);
|
||||
data->buffer = buffer;
|
||||
data->bytes_read = 0;
|
||||
simple = g_simple_async_result_new (G_OBJECT (stream),
|
||||
callback, user_data,
|
||||
g_buffered_input_stream_read_async);
|
||||
g_simple_async_result_set_op_res_gpointer (simple, data, free_read_async_data);
|
||||
|
||||
available = priv->end - priv->pos;
|
||||
|
||||
if (count <= available)
|
||||
{
|
||||
memcpy (buffer, priv->buffer + priv->pos, count);
|
||||
priv->pos += count;
|
||||
data->bytes_read = count;
|
||||
|
||||
g_simple_async_result_complete_in_idle (simple);
|
||||
g_object_unref (simple);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Full request not available, read all currently available
|
||||
* and request refill for more
|
||||
*/
|
||||
|
||||
memcpy (buffer, priv->buffer + priv->pos, available);
|
||||
priv->pos = 0;
|
||||
priv->end = 0;
|
||||
|
||||
count -= available;
|
||||
|
||||
data->bytes_read = available;
|
||||
data->count = count;
|
||||
|
||||
if (count > priv->len)
|
||||
{
|
||||
/* Large request, shortcut buffer */
|
||||
|
||||
base_stream = G_FILTER_INPUT_STREAM (stream)->base_stream;
|
||||
|
||||
g_input_stream_read_async (base_stream,
|
||||
(char *)buffer + data->bytes_read,
|
||||
count,
|
||||
io_priority, cancellable,
|
||||
large_read_callback,
|
||||
simple);
|
||||
}
|
||||
else
|
||||
{
|
||||
class = G_BUFFERED_INPUT_STREAM_GET_CLASS (stream);
|
||||
class->fill_async (bstream, priv->len, io_priority, cancellable,
|
||||
read_fill_buffer_callback, simple);
|
||||
}
|
||||
}
|
||||
|
||||
static gssize
|
||||
g_buffered_input_stream_read_finish (GInputStream *stream,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
GSimpleAsyncResult *simple;
|
||||
ReadAsyncData *data;
|
||||
|
||||
simple = G_SIMPLE_ASYNC_RESULT (result);
|
||||
|
||||
g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_buffered_input_stream_read_async);
|
||||
|
||||
data = g_simple_async_result_get_op_res_gpointer (simple);
|
||||
|
||||
return data->bytes_read;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gssize bytes_skipped;
|
||||
|
Reference in New Issue
Block a user