Merge branch 'wip/carlosg/cancelled-splice' into 'master'

Fix splice behavior on cancellation

See merge request GNOME/glib!1631
This commit is contained in:
Sebastian Dröge 2020-08-28 10:04:47 +00:00
commit e5c119ea41
2 changed files with 33 additions and 3 deletions

View File

@ -2643,6 +2643,8 @@ g_output_stream_real_writev_finish (GOutputStream *stream,
typedef struct { typedef struct {
GInputStream *source; GInputStream *source;
GOutputStreamSpliceFlags flags; GOutputStreamSpliceFlags flags;
guint istream_closed : 1;
guint ostream_closed : 1;
gssize n_read; gssize n_read;
gssize n_written; gssize n_written;
gsize bytes_copied; gsize bytes_copied;
@ -2665,11 +2667,11 @@ real_splice_async_complete_cb (GTask *task)
SpliceData *op = g_task_get_task_data (task); SpliceData *op = g_task_get_task_data (task);
if (op->flags & G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE && if (op->flags & G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE &&
!g_input_stream_is_closed (op->source)) !op->istream_closed)
return; return;
if (op->flags & G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET && if (op->flags & G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET &&
!g_output_stream_is_closed (g_task_get_source_object (task))) !op->ostream_closed)
return; return;
if (op->error != NULL) if (op->error != NULL)
@ -2691,8 +2693,10 @@ real_splice_async_close_input_cb (GObject *source,
gpointer user_data) gpointer user_data)
{ {
GTask *task = user_data; GTask *task = user_data;
SpliceData *op = g_task_get_task_data (task);
g_input_stream_close_finish (G_INPUT_STREAM (source), res, NULL); g_input_stream_close_finish (G_INPUT_STREAM (source), res, NULL);
op->istream_closed = TRUE;
real_splice_async_complete_cb (task); real_splice_async_complete_cb (task);
} }
@ -2707,6 +2711,7 @@ real_splice_async_close_output_cb (GObject *source,
GError **error = (op->error == NULL) ? &op->error : NULL; GError **error = (op->error == NULL) ? &op->error : NULL;
g_output_stream_internal_close_finish (G_OUTPUT_STREAM (source), res, error); g_output_stream_internal_close_finish (G_OUTPUT_STREAM (source), res, error);
op->ostream_closed = TRUE;
real_splice_async_complete_cb (task); real_splice_async_complete_cb (task);
} }

View File

@ -32,6 +32,7 @@ typedef enum
TEST_THREADED_NONE = 0, TEST_THREADED_NONE = 0,
TEST_THREADED_ISTREAM = 1, TEST_THREADED_ISTREAM = 1,
TEST_THREADED_OSTREAM = 2, TEST_THREADED_OSTREAM = 2,
TEST_CANCEL = 4,
TEST_THREADED_BOTH = TEST_THREADED_ISTREAM | TEST_THREADED_OSTREAM, TEST_THREADED_BOTH = TEST_THREADED_ISTREAM | TEST_THREADED_OSTREAM,
} TestThreadedFlags; } TestThreadedFlags;
@ -58,6 +59,14 @@ test_copy_chunks_splice_cb (GObject *source,
bytes_spliced = g_output_stream_splice_finish (G_OUTPUT_STREAM (source), bytes_spliced = g_output_stream_splice_finish (G_OUTPUT_STREAM (source),
res, &error); res, &error);
if (data->flags & TEST_CANCEL)
{
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
g_main_loop_quit (data->main_loop);
return;
}
g_assert_no_error (error); g_assert_no_error (error);
g_assert_cmpint (bytes_spliced, ==, strlen (data->data)); g_assert_cmpint (bytes_spliced, ==, strlen (data->data));
@ -100,11 +109,18 @@ test_copy_chunks_start (TestThreadedFlags flags)
{ {
TestCopyChunksData data; TestCopyChunksData data;
GError *error = NULL; GError *error = NULL;
GCancellable *cancellable = NULL;
data.main_loop = g_main_loop_new (NULL, FALSE); data.main_loop = g_main_loop_new (NULL, FALSE);
data.data = "abcdefghijklmnopqrstuvwxyz"; data.data = "abcdefghijklmnopqrstuvwxyz";
data.flags = flags; data.flags = flags;
if (data.flags & TEST_CANCEL)
{
cancellable = g_cancellable_new ();
g_cancellable_cancel (cancellable);
}
if (data.flags & TEST_THREADED_ISTREAM) if (data.flags & TEST_THREADED_ISTREAM)
{ {
GFile *file; GFile *file;
@ -150,7 +166,7 @@ test_copy_chunks_start (TestThreadedFlags flags)
g_output_stream_splice_async (data.ostream, data.istream, g_output_stream_splice_async (data.ostream, data.istream,
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
G_PRIORITY_DEFAULT, NULL, G_PRIORITY_DEFAULT, cancellable,
test_copy_chunks_splice_cb, &data); test_copy_chunks_splice_cb, &data);
/* We do not hold a ref in data struct, this is to make sure the operation /* We do not hold a ref in data struct, this is to make sure the operation
@ -158,6 +174,7 @@ test_copy_chunks_start (TestThreadedFlags flags)
*/ */
g_object_unref (data.istream); g_object_unref (data.istream);
g_object_unref (data.ostream); g_object_unref (data.ostream);
g_clear_object (&cancellable);
g_main_loop_run (data.main_loop); g_main_loop_run (data.main_loop);
g_main_loop_unref (data.main_loop); g_main_loop_unref (data.main_loop);
@ -187,6 +204,12 @@ test_copy_chunks_threaded (void)
test_copy_chunks_start (TEST_THREADED_BOTH); test_copy_chunks_start (TEST_THREADED_BOTH);
} }
static void
test_cancelled (void)
{
test_copy_chunks_start (TEST_THREADED_NONE | TEST_CANCEL);
}
int int
main (int argc, main (int argc,
char *argv[]) char *argv[])
@ -200,6 +223,8 @@ main (int argc,
test_copy_chunks_threaded_output); test_copy_chunks_threaded_output);
g_test_add_func ("/async-splice/copy-chunks-threaded", g_test_add_func ("/async-splice/copy-chunks-threaded",
test_copy_chunks_threaded); test_copy_chunks_threaded);
g_test_add_func ("/async-splice/cancelled",
test_cancelled);
return g_test_run(); return g_test_run();
} }