| 
									
										
										
										
											2011-08-12 11:49:31 +02:00
										 |  |  | /* GIO - GLib Input, Output and Streaming Library
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2011 Collabora Ltd. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 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 | 
					
						
							| 
									
										
										
										
											2014-01-23 12:58:29 +01:00
										 |  |  |  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							| 
									
										
										
										
											2011-08-12 11:49:31 +02:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Author: Stef Walter <stefw@collabora.co.uk> | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <locale.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <gio/gio.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* How long to wait in ms for each iteration */ | 
					
						
							|  |  |  | #define WAIT_ITERATION (10)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static gint num_async_operations = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   guint iterations_requested; | 
					
						
							|  |  |  |   guint iterations_done; | 
					
						
							|  |  |  | } MockOperationData; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | mock_operation_free (gpointer user_data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   MockOperationData *data = user_data; | 
					
						
							|  |  |  |   g_free (data); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2012-08-02 15:45:24 -04:00
										 |  |  | mock_operation_thread (GTask        *task, | 
					
						
							|  |  |  |                        gpointer      source_object, | 
					
						
							|  |  |  |                        gpointer      task_data, | 
					
						
							|  |  |  |                        GCancellable *cancellable) | 
					
						
							| 
									
										
										
										
											2011-08-12 11:49:31 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-08-02 15:45:24 -04:00
										 |  |  |   MockOperationData *data = task_data; | 
					
						
							| 
									
										
										
										
											2011-08-12 11:49:31 +02:00
										 |  |  |   guint i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (i = 0; i < data->iterations_requested; i++) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2012-08-02 15:45:24 -04:00
										 |  |  |       if (g_cancellable_is_cancelled (cancellable)) | 
					
						
							| 
									
										
										
										
											2011-08-12 11:49:31 +02:00
										 |  |  |         break; | 
					
						
							|  |  |  |       if (g_test_verbose ()) | 
					
						
							|  |  |  |         g_printerr ("THRD: %u iteration %u\n", data->iterations_requested, i); | 
					
						
							|  |  |  |       g_usleep (WAIT_ITERATION * 1000); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (g_test_verbose ()) | 
					
						
							|  |  |  |     g_printerr ("THRD: %u stopped at %u\n", data->iterations_requested, i); | 
					
						
							|  |  |  |   data->iterations_done = i; | 
					
						
							| 
									
										
										
										
											2012-08-02 15:45:24 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   g_task_return_boolean (task, TRUE); | 
					
						
							| 
									
										
										
										
											2011-08-12 11:49:31 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static gboolean | 
					
						
							|  |  |  | mock_operation_timeout (gpointer user_data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-08-02 15:45:24 -04:00
										 |  |  |   GTask *task; | 
					
						
							| 
									
										
										
										
											2011-08-12 11:49:31 +02:00
										 |  |  |   MockOperationData *data; | 
					
						
							|  |  |  |   gboolean done = FALSE; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-02 15:45:24 -04:00
										 |  |  |   task = G_TASK (user_data); | 
					
						
							|  |  |  |   data = g_task_get_task_data (task); | 
					
						
							| 
									
										
										
										
											2011-08-12 11:49:31 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (data->iterations_done >= data->iterations_requested) | 
					
						
							|  |  |  |       done = TRUE; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-02 15:45:24 -04:00
										 |  |  |   if (g_cancellable_is_cancelled (g_task_get_cancellable (task))) | 
					
						
							| 
									
										
										
										
											2011-08-12 11:49:31 +02:00
										 |  |  |       done = TRUE; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-02 15:45:24 -04:00
										 |  |  |   if (done) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2011-08-12 11:49:31 +02:00
										 |  |  |       if (g_test_verbose ()) | 
					
						
							|  |  |  |         g_printerr ("LOOP: %u stopped at %u\n", data->iterations_requested,\ | 
					
						
							|  |  |  |                     data->iterations_done); | 
					
						
							| 
									
										
										
										
											2012-08-02 15:45:24 -04:00
										 |  |  |       g_task_return_boolean (task, TRUE); | 
					
						
							| 
									
										
										
										
											2011-08-12 11:49:31 +02:00
										 |  |  |       return FALSE; /* don't call timeout again */ | 
					
						
							| 
									
										
										
										
											2012-08-02 15:45:24 -04:00
										 |  |  |     } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2011-08-12 11:49:31 +02:00
										 |  |  |       data->iterations_done++; | 
					
						
							|  |  |  |       if (g_test_verbose ()) | 
					
						
							|  |  |  |         g_printerr ("LOOP: %u iteration %u\n", data->iterations_requested, | 
					
						
							|  |  |  |                     data->iterations_done); | 
					
						
							|  |  |  |       return TRUE; /* call timeout */ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | mock_operation_async (guint                wait_iterations, | 
					
						
							|  |  |  |                       gboolean             run_in_thread, | 
					
						
							|  |  |  |                       GCancellable        *cancellable, | 
					
						
							|  |  |  |                       GAsyncReadyCallback  callback, | 
					
						
							|  |  |  |                       gpointer             user_data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-08-02 15:45:24 -04:00
										 |  |  |   GTask *task; | 
					
						
							| 
									
										
										
										
											2011-08-12 11:49:31 +02:00
										 |  |  |   MockOperationData *data; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-02 15:45:24 -04:00
										 |  |  |   task = g_task_new (NULL, cancellable, callback, user_data); | 
					
						
							| 
									
										
										
										
											2011-08-12 11:49:31 +02:00
										 |  |  |   data = g_new0 (MockOperationData, 1); | 
					
						
							|  |  |  |   data->iterations_requested = wait_iterations; | 
					
						
							| 
									
										
										
										
											2012-08-02 15:45:24 -04:00
										 |  |  |   g_task_set_task_data (task, data, mock_operation_free); | 
					
						
							| 
									
										
										
										
											2011-08-12 11:49:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-02 15:45:24 -04:00
										 |  |  |   if (run_in_thread) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       g_task_run_in_thread (task, mock_operation_thread); | 
					
						
							| 
									
										
										
										
											2011-08-12 11:49:31 +02:00
										 |  |  |       if (g_test_verbose ()) | 
					
						
							|  |  |  |         g_printerr ("THRD: %d started\n", wait_iterations); | 
					
						
							| 
									
										
										
										
											2012-08-02 15:45:24 -04:00
										 |  |  |     } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2011-08-12 11:49:31 +02:00
										 |  |  |       g_timeout_add_full (G_PRIORITY_DEFAULT, WAIT_ITERATION, mock_operation_timeout, | 
					
						
							| 
									
										
										
										
											2012-08-02 15:45:24 -04:00
										 |  |  |                           g_object_ref (task), g_object_unref); | 
					
						
							| 
									
										
										
										
											2011-08-12 11:49:31 +02:00
										 |  |  |       if (g_test_verbose ()) | 
					
						
							|  |  |  |         g_printerr ("LOOP: %d started\n", wait_iterations); | 
					
						
							| 
									
										
										
										
											2012-08-02 15:45:24 -04:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-08-12 11:49:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-02 15:45:24 -04:00
										 |  |  |   g_object_unref (task); | 
					
						
							| 
									
										
										
										
											2011-08-12 11:49:31 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static guint | 
					
						
							|  |  |  | mock_operation_finish (GAsyncResult  *result, | 
					
						
							|  |  |  |                        GError       **error) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   MockOperationData *data; | 
					
						
							| 
									
										
										
										
											2012-08-02 15:45:24 -04:00
										 |  |  |   GTask *task; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   g_assert (g_task_is_valid (result, NULL)); | 
					
						
							| 
									
										
										
										
											2011-08-12 11:49:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-02 15:45:24 -04:00
										 |  |  |   /* This test expects the return value to be iterations_done even
 | 
					
						
							|  |  |  |    * when an error is set. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   task = G_TASK (result); | 
					
						
							|  |  |  |   data = g_task_get_task_data (task); | 
					
						
							| 
									
										
										
										
											2011-08-12 11:49:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-02 15:45:24 -04:00
										 |  |  |   g_task_propagate_boolean (task, error); | 
					
						
							| 
									
										
										
										
											2011-08-12 11:49:31 +02:00
										 |  |  |   return data->iterations_done; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-24 17:11:38 -04:00
										 |  |  | GMainLoop *loop; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-12 11:49:31 +02:00
										 |  |  | static void | 
					
						
							|  |  |  | on_mock_operation_ready (GObject      *source, | 
					
						
							|  |  |  |                          GAsyncResult *result, | 
					
						
							|  |  |  |                          gpointer      user_data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   guint iterations_requested; | 
					
						
							|  |  |  |   guint iterations_done; | 
					
						
							|  |  |  |   GError *error = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   iterations_requested = GPOINTER_TO_UINT (user_data); | 
					
						
							|  |  |  |   iterations_done = mock_operation_finish (result, &error); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); | 
					
						
							|  |  |  |   g_error_free (error); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   g_assert_cmpint (iterations_requested, >, iterations_done); | 
					
						
							|  |  |  |   num_async_operations--; | 
					
						
							| 
									
										
										
										
											2012-08-24 17:11:38 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (!num_async_operations) | 
					
						
							|  |  |  |     g_main_loop_quit (loop); | 
					
						
							| 
									
										
										
										
											2011-08-12 11:49:31 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static gboolean | 
					
						
							|  |  |  | on_main_loop_timeout_quit (gpointer user_data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GMainLoop *loop = user_data; | 
					
						
							|  |  |  |   g_main_loop_quit (loop); | 
					
						
							|  |  |  |   return FALSE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | test_cancel_multiple_concurrent (void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GCancellable *cancellable; | 
					
						
							|  |  |  |   guint i, iterations; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   cancellable = g_cancellable_new (); | 
					
						
							|  |  |  |   loop = g_main_loop_new (NULL, FALSE); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (i = 0; i < 45; i++) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       iterations = i + 10; | 
					
						
							|  |  |  |       mock_operation_async (iterations, g_random_boolean (), cancellable, | 
					
						
							|  |  |  |                             on_mock_operation_ready, GUINT_TO_POINTER (iterations)); | 
					
						
							|  |  |  |       num_async_operations++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Wait for two iterations, to give threads a chance to start up */ | 
					
						
							|  |  |  |   g_timeout_add (WAIT_ITERATION * 2, on_main_loop_timeout_quit, loop); | 
					
						
							|  |  |  |   g_main_loop_run (loop); | 
					
						
							|  |  |  |   g_assert_cmpint (num_async_operations, ==, 45); | 
					
						
							|  |  |  |   if (g_test_verbose ()) | 
					
						
							|  |  |  |     g_printerr ("CANCEL: %d operations\n", num_async_operations); | 
					
						
							|  |  |  |   g_cancellable_cancel (cancellable); | 
					
						
							|  |  |  |   g_assert (g_cancellable_is_cancelled (cancellable)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-24 17:11:38 -04:00
										 |  |  |   /* Wait for all operations to be cancelled */ | 
					
						
							| 
									
										
										
										
											2011-08-12 11:49:31 +02:00
										 |  |  |   g_main_loop_run (loop); | 
					
						
							|  |  |  |   g_assert_cmpint (num_async_operations, ==, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   g_object_unref (cancellable); | 
					
						
							|  |  |  |   g_main_loop_unref (loop); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | main (int argc, char *argv[]) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   g_test_init (&argc, &argv, NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   g_test_add_func ("/cancellable/multiple-concurrent", test_cancel_multiple_concurrent); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return g_test_run (); | 
					
						
							|  |  |  | } |