7c960c78fa5abc9210e14e7f3dabe61c32d27465
[platform/upstream/glib.git] / gio / tests / cancellable.c
1 /* GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright (C) 2011 Collabora Ltd.
4  *
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.
9  *
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.
14  *
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.
19  *
20  * Author: Stef Walter <stefw@collabora.co.uk>
21  */
22
23 #include <locale.h>
24
25 #include <gio/gio.h>
26
27 /* How long to wait in ms for each iteration */
28 #define WAIT_ITERATION (10)
29
30 static gint num_async_operations = 0;
31
32 typedef struct
33 {
34   guint iterations_requested;
35   guint iterations_done;
36   GCancellable *cancellable;
37 } MockOperationData;
38
39 static void
40 mock_operation_free (gpointer user_data)
41 {
42   MockOperationData *data = user_data;
43   g_object_unref (data->cancellable);
44   g_free (data);
45 }
46
47 static void
48 mock_operation_thread (GSimpleAsyncResult *simple,
49                        GObject            *object,
50                        GCancellable       *cancellable)
51 {
52   MockOperationData *data;
53   guint i;
54
55   data = g_simple_async_result_get_op_res_gpointer (simple);
56   g_assert (data->cancellable == cancellable);
57
58   for (i = 0; i < data->iterations_requested; i++)
59     {
60       if (g_cancellable_is_cancelled (data->cancellable))
61         break;
62       if (g_test_verbose ())
63         g_printerr ("THRD: %u iteration %u\n", data->iterations_requested, i);
64       g_usleep (WAIT_ITERATION * 1000);
65     }
66
67   if (g_test_verbose ())
68     g_printerr ("THRD: %u stopped at %u\n", data->iterations_requested, i);
69   data->iterations_done = i;
70 }
71
72 static gboolean
73 mock_operation_timeout (gpointer user_data)
74 {
75   GSimpleAsyncResult *simple;
76   MockOperationData *data;
77   GError *error = NULL;
78   gboolean done = FALSE;
79
80   simple = G_SIMPLE_ASYNC_RESULT (user_data);
81   data = g_simple_async_result_get_op_res_gpointer (simple);
82
83   if (data->iterations_done >= data->iterations_requested)
84       done = TRUE;
85
86   if (g_cancellable_set_error_if_cancelled (data->cancellable, &error)) {
87       g_simple_async_result_take_error (simple, error);
88       done = TRUE;
89   }
90
91   if (done) {
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 */
97
98   } else {
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 */
104     }
105 }
106
107 static void
108 mock_operation_async (guint                wait_iterations,
109                       gboolean             run_in_thread,
110                       GCancellable        *cancellable,
111                       GAsyncReadyCallback  callback,
112                       gpointer             user_data)
113 {
114   GSimpleAsyncResult *simple;
115   MockOperationData *data;
116
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);
123
124   if (run_in_thread) {
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);
129   } else {
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);
134   }
135
136   g_object_unref (simple);
137 }
138
139 static guint
140 mock_operation_finish (GAsyncResult  *result,
141                        GError       **error)
142 {
143   MockOperationData *data;
144
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);
147
148   data = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
149   return data->iterations_done;
150 }
151
152 GMainLoop *loop;
153
154 static void
155 on_mock_operation_ready (GObject      *source,
156                          GAsyncResult *result,
157                          gpointer      user_data)
158 {
159   guint iterations_requested;
160   guint iterations_done;
161   GError *error = NULL;
162
163   iterations_requested = GPOINTER_TO_UINT (user_data);
164   iterations_done = mock_operation_finish (result, &error);
165
166   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
167   g_error_free (error);
168
169   g_assert_cmpint (iterations_requested, >, iterations_done);
170   num_async_operations--;
171
172   if (!num_async_operations)
173     g_main_loop_quit (loop);
174 }
175
176 static gboolean
177 on_main_loop_timeout_quit (gpointer user_data)
178 {
179   GMainLoop *loop = user_data;
180   g_main_loop_quit (loop);
181   return FALSE;
182 }
183
184 static void
185 test_cancel_multiple_concurrent (void)
186 {
187   GCancellable *cancellable;
188   guint i, iterations;
189
190   cancellable = g_cancellable_new ();
191   loop = g_main_loop_new (NULL, FALSE);
192
193   for (i = 0; i < 45; i++)
194     {
195       iterations = i + 10;
196       mock_operation_async (iterations, g_random_boolean (), cancellable,
197                             on_mock_operation_ready, GUINT_TO_POINTER (iterations));
198       num_async_operations++;
199     }
200
201   /* Wait for two iterations, to give threads a chance to start up */
202   g_timeout_add (WAIT_ITERATION * 2, on_main_loop_timeout_quit, loop);
203   g_main_loop_run (loop);
204   g_assert_cmpint (num_async_operations, ==, 45);
205   if (g_test_verbose ())
206     g_printerr ("CANCEL: %d operations\n", num_async_operations);
207   g_cancellable_cancel (cancellable);
208   g_assert (g_cancellable_is_cancelled (cancellable));
209
210   /* Wait for all operations to be cancelled */
211   g_main_loop_run (loop);
212   g_assert_cmpint (num_async_operations, ==, 0);
213
214   g_object_unref (cancellable);
215   g_main_loop_unref (loop);
216 }
217
218 int
219 main (int argc, char *argv[])
220 {
221   g_type_init ();
222   g_test_init (&argc, &argv, NULL);
223
224   g_test_add_func ("/cancellable/multiple-concurrent", test_cancel_multiple_concurrent);
225
226   return g_test_run ();
227 }