Blame gio/tests/cancellable.c

Packit ae235b
/* GIO - GLib Input, Output and Streaming Library
Packit ae235b
 *
Packit ae235b
 * Copyright (C) 2011 Collabora Ltd.
Packit ae235b
 *
Packit ae235b
 * This library is free software; you can redistribute it and/or
Packit ae235b
 * modify it under the terms of the GNU Lesser General Public
Packit ae235b
 * License as published by the Free Software Foundation; either
Packit ae235b
 * version 2.1 of the License, or (at your option) any later version.
Packit ae235b
 *
Packit ae235b
 * This library is distributed in the hope that it will be useful,
Packit ae235b
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit ae235b
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit ae235b
 * Lesser General Public License for more details.
Packit ae235b
 *
Packit ae235b
 * You should have received a copy of the GNU Lesser General
Packit ae235b
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit ae235b
 *
Packit ae235b
 * Author: Stef Walter <stefw@collabora.co.uk>
Packit ae235b
 */
Packit ae235b
Packit ae235b
#include <locale.h>
Packit ae235b
Packit ae235b
#include <gio/gio.h>
Packit ae235b
Packit ae235b
/* How long to wait in ms for each iteration */
Packit ae235b
#define WAIT_ITERATION (10)
Packit ae235b
Packit ae235b
static gint num_async_operations = 0;
Packit ae235b
Packit ae235b
typedef struct
Packit ae235b
{
Packit ae235b
  guint iterations_requested;
Packit ae235b
  guint iterations_done;
Packit ae235b
} MockOperationData;
Packit ae235b
Packit ae235b
static void
Packit ae235b
mock_operation_free (gpointer user_data)
Packit ae235b
{
Packit ae235b
  MockOperationData *data = user_data;
Packit ae235b
  g_free (data);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
mock_operation_thread (GTask        *task,
Packit ae235b
                       gpointer      source_object,
Packit ae235b
                       gpointer      task_data,
Packit ae235b
                       GCancellable *cancellable)
Packit ae235b
{
Packit ae235b
  MockOperationData *data = task_data;
Packit ae235b
  guint i;
Packit ae235b
Packit ae235b
  for (i = 0; i < data->iterations_requested; i++)
Packit ae235b
    {
Packit ae235b
      if (g_cancellable_is_cancelled (cancellable))
Packit ae235b
        break;
Packit ae235b
      if (g_test_verbose ())
Packit ae235b
        g_printerr ("THRD: %u iteration %u\n", data->iterations_requested, i);
Packit ae235b
      g_usleep (WAIT_ITERATION * 1000);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (g_test_verbose ())
Packit ae235b
    g_printerr ("THRD: %u stopped at %u\n", data->iterations_requested, i);
Packit ae235b
  data->iterations_done = i;
Packit ae235b
Packit ae235b
  g_task_return_boolean (task, TRUE);
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
mock_operation_timeout (gpointer user_data)
Packit ae235b
{
Packit ae235b
  GTask *task;
Packit ae235b
  MockOperationData *data;
Packit ae235b
  gboolean done = FALSE;
Packit ae235b
Packit ae235b
  task = G_TASK (user_data);
Packit ae235b
  data = g_task_get_task_data (task);
Packit ae235b
Packit ae235b
  if (data->iterations_done >= data->iterations_requested)
Packit ae235b
      done = TRUE;
Packit ae235b
Packit ae235b
  if (g_cancellable_is_cancelled (g_task_get_cancellable (task)))
Packit ae235b
      done = TRUE;
Packit ae235b
Packit ae235b
  if (done)
Packit ae235b
    {
Packit ae235b
      if (g_test_verbose ())
Packit ae235b
        g_printerr ("LOOP: %u stopped at %u\n", data->iterations_requested,\
Packit ae235b
                    data->iterations_done);
Packit ae235b
      g_task_return_boolean (task, TRUE);
Packit ae235b
      return FALSE; /* don't call timeout again */
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      data->iterations_done++;
Packit ae235b
      if (g_test_verbose ())
Packit ae235b
        g_printerr ("LOOP: %u iteration %u\n", data->iterations_requested,
Packit ae235b
                    data->iterations_done);
Packit ae235b
      return TRUE; /* call timeout */
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
mock_operation_async (guint                wait_iterations,
Packit ae235b
                      gboolean             run_in_thread,
Packit ae235b
                      GCancellable        *cancellable,
Packit ae235b
                      GAsyncReadyCallback  callback,
Packit ae235b
                      gpointer             user_data)
Packit ae235b
{
Packit ae235b
  GTask *task;
Packit ae235b
  MockOperationData *data;
Packit ae235b
Packit ae235b
  task = g_task_new (NULL, cancellable, callback, user_data);
Packit ae235b
  data = g_new0 (MockOperationData, 1);
Packit ae235b
  data->iterations_requested = wait_iterations;
Packit ae235b
  g_task_set_task_data (task, data, mock_operation_free);
Packit ae235b
Packit ae235b
  if (run_in_thread)
Packit ae235b
    {
Packit ae235b
      g_task_run_in_thread (task, mock_operation_thread);
Packit ae235b
      if (g_test_verbose ())
Packit ae235b
        g_printerr ("THRD: %d started\n", wait_iterations);
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      g_timeout_add_full (G_PRIORITY_DEFAULT, WAIT_ITERATION, mock_operation_timeout,
Packit ae235b
                          g_object_ref (task), g_object_unref);
Packit ae235b
      if (g_test_verbose ())
Packit ae235b
        g_printerr ("LOOP: %d started\n", wait_iterations);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_object_unref (task);
Packit ae235b
}
Packit ae235b
Packit ae235b
static guint
Packit ae235b
mock_operation_finish (GAsyncResult  *result,
Packit ae235b
                       GError       **error)
Packit ae235b
{
Packit ae235b
  MockOperationData *data;
Packit ae235b
  GTask *task;
Packit ae235b
Packit ae235b
  g_assert (g_task_is_valid (result, NULL));
Packit ae235b
Packit ae235b
  /* This test expects the return value to be iterations_done even
Packit ae235b
   * when an error is set.
Packit ae235b
   */
Packit ae235b
  task = G_TASK (result);
Packit ae235b
  data = g_task_get_task_data (task);
Packit ae235b
Packit ae235b
  g_task_propagate_boolean (task, error);
Packit ae235b
  return data->iterations_done;
Packit ae235b
}
Packit ae235b
Packit ae235b
GMainLoop *loop;
Packit ae235b
Packit ae235b
static void
Packit ae235b
on_mock_operation_ready (GObject      *source,
Packit ae235b
                         GAsyncResult *result,
Packit ae235b
                         gpointer      user_data)
Packit ae235b
{
Packit ae235b
  guint iterations_requested;
Packit ae235b
  guint iterations_done;
Packit ae235b
  GError *error = NULL;
Packit ae235b
Packit ae235b
  iterations_requested = GPOINTER_TO_UINT (user_data);
Packit ae235b
  iterations_done = mock_operation_finish (result, &error);
Packit ae235b
Packit ae235b
  g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
Packit ae235b
  g_error_free (error);
Packit ae235b
Packit ae235b
  g_assert_cmpint (iterations_requested, >, iterations_done);
Packit ae235b
  num_async_operations--;
Packit ae235b
Packit ae235b
  if (!num_async_operations)
Packit ae235b
    g_main_loop_quit (loop);
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
on_main_loop_timeout_quit (gpointer user_data)
Packit ae235b
{
Packit ae235b
  GMainLoop *loop = user_data;
Packit ae235b
  g_main_loop_quit (loop);
Packit ae235b
  return FALSE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
test_cancel_multiple_concurrent (void)
Packit ae235b
{
Packit ae235b
  GCancellable *cancellable;
Packit ae235b
  guint i, iterations;
Packit ae235b
Packit ae235b
  cancellable = g_cancellable_new ();
Packit ae235b
  loop = g_main_loop_new (NULL, FALSE);
Packit ae235b
Packit ae235b
  for (i = 0; i < 45; i++)
Packit ae235b
    {
Packit ae235b
      iterations = i + 10;
Packit ae235b
      mock_operation_async (iterations, g_random_boolean (), cancellable,
Packit ae235b
                            on_mock_operation_ready, GUINT_TO_POINTER (iterations));
Packit ae235b
      num_async_operations++;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  /* Wait for two iterations, to give threads a chance to start up */
Packit ae235b
  g_timeout_add (WAIT_ITERATION * 2, on_main_loop_timeout_quit, loop);
Packit ae235b
  g_main_loop_run (loop);
Packit ae235b
  g_assert_cmpint (num_async_operations, ==, 45);
Packit ae235b
  if (g_test_verbose ())
Packit ae235b
    g_printerr ("CANCEL: %d operations\n", num_async_operations);
Packit ae235b
  g_cancellable_cancel (cancellable);
Packit ae235b
  g_assert (g_cancellable_is_cancelled (cancellable));
Packit ae235b
Packit ae235b
  /* Wait for all operations to be cancelled */
Packit ae235b
  g_main_loop_run (loop);
Packit ae235b
  g_assert_cmpint (num_async_operations, ==, 0);
Packit ae235b
Packit ae235b
  g_object_unref (cancellable);
Packit ae235b
  g_main_loop_unref (loop);
Packit ae235b
}
Packit ae235b
Packit ae235b
int
Packit ae235b
main (int argc, char *argv[])
Packit ae235b
{
Packit ae235b
  g_test_init (&argc, &argv, NULL);
Packit ae235b
Packit ae235b
  g_test_add_func ("/cancellable/multiple-concurrent", test_cancel_multiple_concurrent);
Packit ae235b
Packit ae235b
  return g_test_run ();
Packit ae235b
}