1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright (C) 2011 Collabora Ltd.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307, USA.
20 * Author: Stef Walter <stefw@collabora.co.uk>
27 /* How long to wait in ms for each iteration */
28 #define WAIT_ITERATION (10)
30 static gint num_async_operations = 0;
34 guint iterations_requested;
35 guint iterations_done;
36 GCancellable *cancellable;
40 mock_operation_free (gpointer user_data)
42 MockOperationData *data = user_data;
43 g_object_unref (data->cancellable);
48 mock_operation_thread (GSimpleAsyncResult *simple,
50 GCancellable *cancellable)
52 MockOperationData *data;
55 data = g_simple_async_result_get_op_res_gpointer (simple);
56 g_assert (data->cancellable == cancellable);
58 for (i = 0; i < data->iterations_requested; i++)
60 if (g_cancellable_is_cancelled (data->cancellable))
62 if (g_test_verbose ())
63 g_printerr ("THRD: %u iteration %u\n", data->iterations_requested, i);
64 g_usleep (WAIT_ITERATION * 1000);
67 if (g_test_verbose ())
68 g_printerr ("THRD: %u stopped at %u\n", data->iterations_requested, i);
69 data->iterations_done = i;
73 mock_operation_timeout (gpointer user_data)
75 GSimpleAsyncResult *simple;
76 MockOperationData *data;
78 gboolean done = FALSE;
80 simple = G_SIMPLE_ASYNC_RESULT (user_data);
81 data = g_simple_async_result_get_op_res_gpointer (simple);
83 if (data->iterations_done >= data->iterations_requested)
86 if (g_cancellable_set_error_if_cancelled (data->cancellable, &error)) {
87 g_simple_async_result_take_error (simple, error);
92 if (g_test_verbose ())
93 g_printerr ("LOOP: %u stopped at %u\n", data->iterations_requested,\
94 data->iterations_done);
95 g_simple_async_result_complete (simple);
96 return FALSE; /* don't call timeout again */
99 data->iterations_done++;
100 if (g_test_verbose ())
101 g_printerr ("LOOP: %u iteration %u\n", data->iterations_requested,
102 data->iterations_done);
103 return TRUE; /* call timeout */
108 mock_operation_async (guint wait_iterations,
109 gboolean run_in_thread,
110 GCancellable *cancellable,
111 GAsyncReadyCallback callback,
114 GSimpleAsyncResult *simple;
115 MockOperationData *data;
117 simple = g_simple_async_result_new (NULL, callback, user_data,
118 mock_operation_async);
119 data = g_new0 (MockOperationData, 1);
120 data->iterations_requested = wait_iterations;
121 data->cancellable = g_object_ref (cancellable);
122 g_simple_async_result_set_op_res_gpointer (simple, data, mock_operation_free);
125 g_simple_async_result_run_in_thread (simple, mock_operation_thread,
126 G_PRIORITY_DEFAULT, cancellable);
127 if (g_test_verbose ())
128 g_printerr ("THRD: %d started\n", wait_iterations);
130 g_timeout_add_full (G_PRIORITY_DEFAULT, WAIT_ITERATION, mock_operation_timeout,
131 g_object_ref (simple), g_object_unref);
132 if (g_test_verbose ())
133 g_printerr ("LOOP: %d started\n", wait_iterations);
136 g_object_unref (simple);
140 mock_operation_finish (GAsyncResult *result,
143 MockOperationData *data;
145 g_assert (g_simple_async_result_is_valid (result, NULL, mock_operation_async));
146 g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error);
148 data = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
149 return data->iterations_done;
153 on_mock_operation_ready (GObject *source,
154 GAsyncResult *result,
157 guint iterations_requested;
158 guint iterations_done;
159 GError *error = NULL;
161 iterations_requested = GPOINTER_TO_UINT (user_data);
162 iterations_done = mock_operation_finish (result, &error);
164 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
165 g_error_free (error);
167 g_assert_cmpint (iterations_requested, >, iterations_done);
168 num_async_operations--;
172 on_main_loop_timeout_quit (gpointer user_data)
174 GMainLoop *loop = user_data;
175 g_main_loop_quit (loop);
180 test_cancel_multiple_concurrent (void)
182 GCancellable *cancellable;
186 cancellable = g_cancellable_new ();
187 loop = g_main_loop_new (NULL, FALSE);
189 for (i = 0; i < 45; i++)
192 mock_operation_async (iterations, g_random_boolean (), cancellable,
193 on_mock_operation_ready, GUINT_TO_POINTER (iterations));
194 num_async_operations++;
197 /* Wait for two iterations, to give threads a chance to start up */
198 g_timeout_add (WAIT_ITERATION * 2, on_main_loop_timeout_quit, loop);
199 g_main_loop_run (loop);
200 g_assert_cmpint (num_async_operations, ==, 45);
201 if (g_test_verbose ())
202 g_printerr ("CANCEL: %d operations\n", num_async_operations);
203 g_cancellable_cancel (cancellable);
204 g_assert (g_cancellable_is_cancelled (cancellable));
206 /* Wait for two more iterations, and all threads should be cancelled */
207 g_timeout_add (WAIT_ITERATION * 2, on_main_loop_timeout_quit, loop);
208 g_main_loop_run (loop);
209 g_assert_cmpint (num_async_operations, ==, 0);
211 g_object_unref (cancellable);
212 g_main_loop_unref (loop);
216 main (int argc, char *argv[])
219 g_test_init (&argc, &argv, NULL);
221 g_test_add_func ("/cancellable/multiple-concurrent", test_cancel_multiple_concurrent);
223 return g_test_run ();