gsocket: add G_IO_ERROR_CONNECTION_CLOSED
[platform/upstream/glib.git] / gio / tests / task.c
index 7c7606f..1a1dd15 100644 (file)
@@ -651,6 +651,21 @@ test_return_if_cancelled (void)
 
 /* test_run_in_thread */
 
+static GMutex run_in_thread_mutex;
+static GCond run_in_thread_cond;
+
+static void
+task_weak_notify (gpointer  user_data,
+                  GObject  *ex_task)
+{
+  gboolean *weak_notify_ran = user_data;
+
+  g_mutex_lock (&run_in_thread_mutex);
+  *weak_notify_ran = TRUE;
+  g_cond_signal (&run_in_thread_cond);
+  g_mutex_unlock (&run_in_thread_mutex);
+}
+
 static void
 run_in_thread_callback (GObject      *object,
                         GAsyncResult *result,
@@ -689,7 +704,11 @@ run_in_thread_thread (GTask        *task,
 
   g_assert (g_thread_self () != main_thread);
 
+  g_mutex_lock (&run_in_thread_mutex);
   *thread_ran = TRUE;
+  g_cond_signal (&run_in_thread_cond);
+  g_mutex_unlock (&run_in_thread_mutex);
+
   g_task_return_int (task, magic);
 }
 
@@ -698,25 +717,32 @@ test_run_in_thread (void)
 {
   GTask *task;
   volatile gboolean thread_ran = FALSE;
+  volatile gboolean weak_notify_ran = FALSE;
   gboolean done = FALSE;
 
   task = g_task_new (NULL, NULL, run_in_thread_callback, &done);
-  g_object_add_weak_pointer (G_OBJECT (task), (gpointer *)&task);
+  g_object_weak_ref (G_OBJECT (task), task_weak_notify, (gpointer)&weak_notify_ran);
 
   g_task_set_task_data (task, (gpointer)&thread_ran, NULL);
   g_task_run_in_thread (task, run_in_thread_thread);
   g_object_unref (task);
 
+  g_mutex_lock (&run_in_thread_mutex);
   while (!thread_ran)
-    g_usleep (100);
+    g_cond_wait (&run_in_thread_cond, &run_in_thread_mutex);
+  g_mutex_unlock (&run_in_thread_mutex);
 
   g_assert (done == FALSE);
-  g_assert (task != NULL);
+  g_assert (weak_notify_ran == FALSE);
 
   g_main_loop_run (loop);
 
   g_assert (done == TRUE);
-  g_assert (task == NULL);
+
+  g_mutex_lock (&run_in_thread_mutex);
+  while (!weak_notify_ran)
+    g_cond_wait (&run_in_thread_cond, &run_in_thread_mutex);
+  g_mutex_unlock (&run_in_thread_mutex);
 }
 
 /* test_run_in_thread_sync */
@@ -825,28 +851,36 @@ fake_task_thread (GTask        *task,
 }
 
 #define G_TASK_THREAD_POOL_SIZE 10
+static int fake_tasks_running;
 
 static void
-test_run_in_thread_priority (void)
+fake_task_callback (GObject      *source,
+                    GAsyncResult *result,
+                    gpointer      user_data)
+{
+  if (--fake_tasks_running == 0)
+    g_main_loop_quit (loop);
+}
+
+static void
+clog_up_thread_pool (void)
 {
   GTask *task;
-  GCancellable *cancellable;
-  int seq_a, seq_b, seq_c, seq_d;
   int i;
 
-  /* Flush the thread pool, then clog it up with junk tasks */
   g_thread_pool_stop_unused_threads ();
 
   g_mutex_lock (&fake_task_mutex);
   for (i = 0; i < G_TASK_THREAD_POOL_SIZE - 1; i++)
     {
-      task = g_task_new (NULL, NULL, NULL, NULL);
+      task = g_task_new (NULL, NULL, fake_task_callback, NULL);
       g_task_set_task_data (task, &fake_task_mutex, NULL);
       g_assert_cmpint (g_task_get_priority (task), ==, G_PRIORITY_DEFAULT);
       g_task_set_priority (task, G_PRIORITY_HIGH * 2);
       g_assert_cmpint (g_task_get_priority (task), ==, G_PRIORITY_HIGH * 2);
       g_task_run_in_thread (task, fake_task_thread);
       g_object_unref (task);
+      fake_tasks_running++;
     }
 
   g_mutex_lock (&last_fake_task_mutex);
@@ -855,6 +889,23 @@ test_run_in_thread_priority (void)
   g_task_set_priority (task, G_PRIORITY_HIGH * 2);
   g_task_run_in_thread (task, fake_task_thread);
   g_object_unref (task);
+}
+
+static void
+unclog_thread_pool (void)
+{
+  g_mutex_unlock (&fake_task_mutex);
+  g_main_loop_run (loop);
+}
+
+static void
+test_run_in_thread_priority (void)
+{
+  GTask *task;
+  GCancellable *cancellable;
+  int seq_a, seq_b, seq_c, seq_d;
+
+  clog_up_thread_pool ();
 
   /* Queue three more tasks that we'll arrange to have run serially */
   task = g_task_new (NULL, NULL, NULL, NULL);
@@ -894,7 +945,50 @@ test_run_in_thread_priority (void)
   g_assert_cmpint (seq_a, ==, 3);
   g_assert_cmpint (seq_b, ==, 4);
 
-  g_mutex_unlock (&fake_task_mutex);
+  unclog_thread_pool ();
+}
+
+/* test_run_in_thread_nested: task threads that block waiting on
+ * other task threads will not cause the thread pool to starve.
+ */
+
+static void
+run_nested_task_thread (GTask        *task,
+                        gpointer      source_object,
+                        gpointer      task_data,
+                        GCancellable *cancellable)
+{
+  GTask *nested;
+  int *nested_tasks_left = task_data;
+
+  if ((*nested_tasks_left)--)
+    {
+      nested = g_task_new (NULL, NULL, NULL, NULL);
+      g_task_set_task_data (nested, nested_tasks_left, NULL);
+      g_task_run_in_thread_sync (nested, run_nested_task_thread);
+      g_object_unref (nested);
+    }
+
+  g_task_return_boolean (task, TRUE);
+}
+
+static void
+test_run_in_thread_nested (void)
+{
+  GTask *task;
+  int nested_tasks_left = 2;
+
+  clog_up_thread_pool ();
+
+  task = g_task_new (NULL, NULL, quit_main_loop_callback, NULL);
+  g_task_set_task_data (task, &nested_tasks_left, NULL);
+  g_task_run_in_thread (task, run_nested_task_thread);
+  g_object_unref (task);
+
+  g_mutex_unlock (&last_fake_task_mutex);
+  g_main_loop_run (loop);
+
+  unclog_thread_pool ();
 }
 
 /* test_return_on_cancel */
@@ -974,6 +1068,7 @@ test_return_on_cancel (void)
   GTask *task;
   GCancellable *cancellable;
   volatile ThreadState thread_state;
+  volatile gboolean weak_notify_ran = FALSE;
   gboolean callback_ran;
 
   cancellable = g_cancellable_new ();
@@ -1011,6 +1106,7 @@ test_return_on_cancel (void)
   callback_ran = FALSE;
   thread_state = THREAD_STARTING;
   task = g_task_new (NULL, cancellable, return_on_cancel_callback, &callback_ran);
+  g_object_weak_ref (G_OBJECT (task), task_weak_notify, (gpointer)&weak_notify_ran);
   g_task_set_return_on_cancel (task, TRUE);
 
   g_task_set_task_data (task, (gpointer)&thread_state, NULL);
@@ -1031,14 +1127,17 @@ test_return_on_cancel (void)
   g_assert (thread_state == THREAD_RUNNING);
   g_assert (callback_ran == TRUE);
 
+  g_assert (weak_notify_ran == FALSE);
+
   while (thread_state == THREAD_RUNNING)
     g_cond_wait (&roc_finish_cond, &roc_finish_mutex);
   g_mutex_unlock (&roc_finish_mutex);
 
   g_assert (thread_state == THREAD_CANCELLED);
-  /* We can't g_assert (task == NULL) here because it won't become NULL
-   * until a little bit after roc_finish_cond is signaled.
-   */
+  g_mutex_lock (&run_in_thread_mutex);
+  while (!weak_notify_ran)
+    g_cond_wait (&run_in_thread_cond, &run_in_thread_mutex);
+  g_mutex_unlock (&run_in_thread_mutex);
 
   g_cancellable_reset (cancellable);
 
@@ -1566,7 +1665,7 @@ legacy_error_return (gpointer user_data)
     }
   else
     {
-      GSimpleAsyncResult *simple = user_data;
+      GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
 
       G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
       g_simple_async_result_set_error (simple,
@@ -1632,7 +1731,6 @@ main (int argc, char **argv)
 {
   int ret;
 
-  g_type_init ();
   g_test_init (&argc, &argv, NULL);
 
   loop = g_main_loop_new (NULL, FALSE);
@@ -1653,6 +1751,7 @@ main (int argc, char **argv)
   g_test_add_func ("/gtask/run-in-thread", test_run_in_thread);
   g_test_add_func ("/gtask/run-in-thread-sync", test_run_in_thread_sync);
   g_test_add_func ("/gtask/run-in-thread-priority", test_run_in_thread_priority);
+  g_test_add_func ("/gtask/run-in-thread-nested", test_run_in_thread_nested);
   g_test_add_func ("/gtask/return-on-cancel", test_return_on_cancel);
   g_test_add_func ("/gtask/return-on-cancel-sync", test_return_on_cancel_sync);
   g_test_add_func ("/gtask/return-on-cancel-atomic", test_return_on_cancel_atomic);