glib/tests/threadpool-test.c
branchRCL_3
changeset 56 acd3cd4aaceb
equal deleted inserted replaced
54:4332f0f7be53 56:acd3cd4aaceb
       
     1 /* Portion Copyright © 2008-09 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.*/
       
     2 #undef G_DISABLE_ASSERT
       
     3 #undef G_LOG_DOMAIN
       
     4 
       
     5 #include "config.h"
       
     6 
       
     7 #include <glib.h>
       
     8 
       
     9 #ifdef __SYMBIAN32__
       
    10 #include <glib_global.h>
       
    11 #include "mrt2_glib2_test.h"
       
    12 #endif /*__SYMBIAN32__*/
       
    13 #define DEBUG_MSG(x)
       
    14 /* #define DEBUG_MSG(args) g_printerr args ; g_printerr ("\n");  */
       
    15 
       
    16 #define WAIT                5    /* seconds */
       
    17 #define MAX_THREADS         10
       
    18 
       
    19 /* if > 0 the test will run continously (since the test ends when
       
    20  * thread count is 0), if -1 it means no limit to unused threads
       
    21  * if 0 then no unused threads are possible */
       
    22 #define MAX_UNUSED_THREADS -1
       
    23 
       
    24 G_LOCK_DEFINE_STATIC (thread_counter_pools);
       
    25 
       
    26 static gulong abs_thread_counter = 0;
       
    27 static gulong running_thread_counter = 0;
       
    28 static gulong leftover_task_counter = 0;
       
    29 
       
    30 G_LOCK_DEFINE_STATIC (last_thread);
       
    31 
       
    32 static guint last_thread_id = 0;
       
    33 
       
    34 G_LOCK_DEFINE_STATIC (thread_counter_sort);
       
    35 
       
    36 static gulong sort_thread_counter = 0;
       
    37 
       
    38 static GThreadPool *idle_pool = NULL;
       
    39 
       
    40 static GMainLoop *main_loop = NULL;
       
    41 
       
    42 static void
       
    43 test_thread_functions (void)
       
    44 {
       
    45   gint max_unused_threads;
       
    46   guint max_idle_time;
       
    47 
       
    48   /* This function attempts to call functions which don't need a
       
    49    * threadpool to operate to make sure no uninitialised pointers
       
    50    * accessed and no errors occur.
       
    51    */
       
    52 
       
    53   max_unused_threads = 3;
       
    54 
       
    55   DEBUG_MSG (("[funcs] Setting max unused threads to %d",
       
    56 	      max_unused_threads));
       
    57   g_thread_pool_set_max_unused_threads (max_unused_threads);
       
    58 
       
    59   DEBUG_MSG (("[funcs] Getting max unused threads = %d",
       
    60 	     g_thread_pool_get_max_unused_threads ()));
       
    61   g_assert (g_thread_pool_get_max_unused_threads() == max_unused_threads);
       
    62 
       
    63   DEBUG_MSG (("[funcs] Getting num unused threads = %d",
       
    64 	     g_thread_pool_get_num_unused_threads ()));
       
    65   g_assert (g_thread_pool_get_num_unused_threads () == 0);
       
    66 
       
    67   DEBUG_MSG (("[funcs] Stopping unused threads"));
       
    68   g_thread_pool_stop_unused_threads ();
       
    69 
       
    70   max_idle_time = 10 * G_USEC_PER_SEC;
       
    71 
       
    72   DEBUG_MSG (("[funcs] Setting max idle time to %d",
       
    73 	      max_idle_time));
       
    74   g_thread_pool_set_max_idle_time (max_idle_time);
       
    75 
       
    76   DEBUG_MSG (("[funcs] Getting max idle time = %d",
       
    77 	     g_thread_pool_get_max_idle_time ()));
       
    78   g_assert (g_thread_pool_get_max_idle_time () == max_idle_time);
       
    79 
       
    80   DEBUG_MSG (("[funcs] Setting max idle time to 0"));
       
    81   g_thread_pool_set_max_idle_time (0);
       
    82 
       
    83   DEBUG_MSG (("[funcs] Getting max idle time = %d",
       
    84 	     g_thread_pool_get_max_idle_time ()));
       
    85   g_assert (g_thread_pool_get_max_idle_time () == 0);
       
    86 }
       
    87 
       
    88 static void
       
    89 test_count_threads_foreach (GThread *thread,
       
    90 			    guint   *count)
       
    91 {
       
    92    ++*count;
       
    93 }
       
    94 
       
    95 static guint
       
    96 test_count_threads (void)
       
    97 {
       
    98   guint count = 0;
       
    99 
       
   100   g_thread_foreach ((GFunc) test_count_threads_foreach, &count);
       
   101 
       
   102   /* Exclude main thread */
       
   103   return count - 1;
       
   104 }
       
   105 
       
   106 static void
       
   107 test_thread_stop_unused (void)
       
   108 {
       
   109    GThreadPool *pool;
       
   110    guint i;
       
   111    guint limit = 100;
       
   112 
       
   113    /* Spawn a few threads. */
       
   114    g_thread_pool_set_max_unused_threads (-1);
       
   115    pool = g_thread_pool_new ((GFunc) g_usleep, NULL, -1, FALSE, NULL);
       
   116 
       
   117    for (i = 0; i < limit; i++)
       
   118      g_thread_pool_push (pool, GUINT_TO_POINTER (1000), NULL);
       
   119 
       
   120    DEBUG_MSG (("[unused] ===> pushed %d threads onto the idle pool",
       
   121 	       limit));
       
   122 
       
   123    /* Wait for the threads to migrate. */
       
   124    g_usleep (G_USEC_PER_SEC);
       
   125 
       
   126    DEBUG_MSG (("[unused] current threads %d",
       
   127 	       test_count_threads()));
       
   128 
       
   129    DEBUG_MSG (("[unused] stopping unused threads"));
       
   130    g_thread_pool_stop_unused_threads ();
       
   131 
       
   132    DEBUG_MSG (("[unused] waiting ONE second for threads to die"));
       
   133 
       
   134    /* Some time for threads to die. */
       
   135    g_usleep (G_USEC_PER_SEC);
       
   136 
       
   137    DEBUG_MSG (("[unused] stopped idle threads, %d remain, %d threads still exist",
       
   138 	       g_thread_pool_get_num_unused_threads (),
       
   139 	       test_count_threads ()));
       
   140 
       
   141    g_assert (g_thread_pool_get_num_unused_threads () == test_count_threads ());
       
   142    g_assert (g_thread_pool_get_num_unused_threads () == 0);
       
   143 
       
   144    g_thread_pool_set_max_unused_threads (MAX_THREADS);
       
   145 
       
   146    DEBUG_MSG (("[unused] cleaning up thread pool"));
       
   147    g_thread_pool_free (pool, FALSE, TRUE);
       
   148 }
       
   149 
       
   150 static void
       
   151 test_thread_pools_entry_func (gpointer data, gpointer user_data)
       
   152 {
       
   153   guint id = 0;
       
   154 
       
   155   id = GPOINTER_TO_UINT (data);
       
   156 
       
   157   DEBUG_MSG (("[pool] ---> [%3.3d] entered thread.", id));
       
   158 
       
   159   G_LOCK (thread_counter_pools);
       
   160   abs_thread_counter++;
       
   161   running_thread_counter++;
       
   162   G_UNLOCK (thread_counter_pools);
       
   163 
       
   164   g_usleep (g_random_int_range (0, 4000));
       
   165 
       
   166   G_LOCK (thread_counter_pools);
       
   167   running_thread_counter--;
       
   168   leftover_task_counter--;
       
   169 
       
   170   DEBUG_MSG (("[pool] ---> [%3.3d] exiting thread (abs count:%ld, "
       
   171 	      "running count:%ld, left over:%ld)",
       
   172 	      id, abs_thread_counter,
       
   173 	      running_thread_counter, leftover_task_counter));
       
   174   G_UNLOCK (thread_counter_pools);
       
   175 }
       
   176 
       
   177 static void
       
   178 test_thread_pools (void)
       
   179 {
       
   180   GThreadPool *pool1, *pool2, *pool3;
       
   181   guint runs;
       
   182   guint i;
       
   183 
       
   184   pool1 = g_thread_pool_new ((GFunc)test_thread_pools_entry_func, NULL, 3, FALSE, NULL);
       
   185   pool2 = g_thread_pool_new ((GFunc)test_thread_pools_entry_func, NULL, 5, TRUE, NULL);
       
   186   pool3 = g_thread_pool_new ((GFunc)test_thread_pools_entry_func, NULL, 7, TRUE, NULL);
       
   187 
       
   188   runs = 300;
       
   189   for (i = 0; i < runs; i++)
       
   190     {
       
   191       g_thread_pool_push (pool1, GUINT_TO_POINTER (i + 1), NULL);
       
   192       g_thread_pool_push (pool2, GUINT_TO_POINTER (i + 1), NULL);
       
   193       g_thread_pool_push (pool3, GUINT_TO_POINTER (i + 1), NULL);
       
   194 
       
   195       G_LOCK (thread_counter_pools);
       
   196       leftover_task_counter += 3;
       
   197       G_UNLOCK (thread_counter_pools);
       
   198     }
       
   199 
       
   200   g_thread_pool_free (pool1, TRUE, TRUE);
       
   201   g_thread_pool_free (pool2, FALSE, TRUE);
       
   202   g_thread_pool_free (pool3, FALSE, TRUE);
       
   203 
       
   204   g_assert (runs * 3 == abs_thread_counter + leftover_task_counter);
       
   205   g_assert (running_thread_counter == 0);
       
   206 }
       
   207 
       
   208 static gint
       
   209 test_thread_sort_compare_func (gconstpointer a, gconstpointer b, gpointer user_data)
       
   210 {
       
   211   guint32 id1, id2;
       
   212 
       
   213   id1 = GPOINTER_TO_UINT (a);
       
   214   id2 = GPOINTER_TO_UINT (b);
       
   215 
       
   216   return (id1 > id2 ? +1 : id1 == id2 ? 0 : -1);
       
   217 }
       
   218 
       
   219 static void
       
   220 test_thread_sort_entry_func (gpointer data, gpointer user_data)
       
   221 {
       
   222   guint thread_id;
       
   223   gboolean is_sorted;
       
   224 
       
   225   G_LOCK (last_thread);
       
   226 
       
   227   thread_id = GPOINTER_TO_UINT (data);
       
   228   is_sorted = GPOINTER_TO_INT (user_data);
       
   229 
       
   230   DEBUG_MSG (("%s ---> entered thread:%2.2d, last thread:%2.2d",
       
   231 	      is_sorted ? "[  sorted]" : "[unsorted]",
       
   232 	      thread_id, last_thread_id));
       
   233 
       
   234   if (is_sorted) {
       
   235     static gboolean last_failed = FALSE;
       
   236 
       
   237     if (last_thread_id > thread_id) {
       
   238       if (last_failed) {
       
   239 	g_assert (last_thread_id <= thread_id);
       
   240       }
       
   241 
       
   242       /* Here we remember one fail and if it concurrently fails, it
       
   243        * can not be sorted. the last thread id might be < this thread
       
   244        * id if something is added to the queue since threads were
       
   245        * created
       
   246        */
       
   247       last_failed = TRUE;
       
   248     } else {
       
   249       last_failed = FALSE;
       
   250     }
       
   251 
       
   252     last_thread_id = thread_id;
       
   253   }
       
   254 
       
   255   G_UNLOCK (last_thread);
       
   256 
       
   257   g_usleep (WAIT * 1000);
       
   258 }
       
   259 
       
   260 static void
       
   261 test_thread_sort (gboolean sort)
       
   262 {
       
   263   GThreadPool *pool;
       
   264   guint limit;
       
   265   guint max_threads;
       
   266   gint i;
       
   267 
       
   268   limit = MAX_THREADS * 10;
       
   269 
       
   270   if (sort) {
       
   271     max_threads = 1;
       
   272   } else {
       
   273     max_threads = MAX_THREADS;
       
   274   }
       
   275 
       
   276   /* It is important that we only have a maximum of 1 thread for this
       
   277    * test since the results can not be guranteed to be sorted if > 1.
       
   278    *
       
   279    * Threads are scheduled by the operating system and are executed at
       
   280    * random. It cannot be assumed that threads are executed in the
       
   281    * order they are created. This was discussed in bug #334943.
       
   282    */
       
   283 
       
   284   pool = g_thread_pool_new (test_thread_sort_entry_func,
       
   285 			    GINT_TO_POINTER (sort),
       
   286 			    max_threads,
       
   287 			    FALSE,
       
   288 			    NULL);
       
   289 
       
   290   g_thread_pool_set_max_unused_threads (MAX_UNUSED_THREADS);
       
   291 
       
   292   if (sort) {
       
   293     g_thread_pool_set_sort_function (pool,
       
   294 				     test_thread_sort_compare_func,
       
   295 				     GUINT_TO_POINTER (69));
       
   296   }
       
   297 
       
   298   for (i = 0; i < limit; i++) {
       
   299     guint id;
       
   300 
       
   301     id = g_random_int_range (1, limit) + 1;
       
   302     g_thread_pool_push (pool, GUINT_TO_POINTER (id), NULL);
       
   303     DEBUG_MSG (("%s ===> pushed new thread with id:%d, number "
       
   304 		"of threads:%d, unprocessed:%d",
       
   305 		sort ? "[  sorted]" : "[unsorted]",
       
   306 		id,
       
   307 		g_thread_pool_get_num_threads (pool),
       
   308 		g_thread_pool_unprocessed (pool)));
       
   309   }
       
   310 
       
   311   g_assert (g_thread_pool_get_max_threads (pool) == max_threads);
       
   312   g_assert (g_thread_pool_get_num_threads (pool) == g_thread_pool_get_max_threads (pool));
       
   313 }
       
   314 
       
   315 static void
       
   316 test_thread_idle_time_entry_func (gpointer data, gpointer user_data)
       
   317 {
       
   318   guint thread_id;
       
   319 
       
   320   thread_id = GPOINTER_TO_UINT (data);
       
   321 
       
   322   DEBUG_MSG (("[idle] ---> entered thread:%2.2d", thread_id));
       
   323 
       
   324   g_usleep (WAIT * 1000);
       
   325 
       
   326   DEBUG_MSG (("[idle] <--- exiting thread:%2.2d", thread_id));
       
   327 }
       
   328 
       
   329 static gboolean
       
   330 test_thread_idle_timeout (gpointer data)
       
   331 {
       
   332   guint interval;
       
   333   gint i;
       
   334 
       
   335   interval = GPOINTER_TO_UINT (data);
       
   336 
       
   337   for (i = 0; i < 2; i++) {
       
   338     g_thread_pool_push (idle_pool, GUINT_TO_POINTER (100 + i), NULL);
       
   339     DEBUG_MSG (("[idle] ===> pushed new thread with id:%d, number "
       
   340 		"of threads:%d, unprocessed:%d",
       
   341 		100 + i,
       
   342 		g_thread_pool_get_num_threads (idle_pool),
       
   343 		g_thread_pool_unprocessed (idle_pool)));
       
   344   }
       
   345 
       
   346 
       
   347   return FALSE;
       
   348 }
       
   349 
       
   350 static void
       
   351 test_thread_idle_time ()
       
   352 {
       
   353   guint limit = 50;
       
   354   guint interval = 10000;
       
   355   gint i;
       
   356 
       
   357   idle_pool = g_thread_pool_new (test_thread_idle_time_entry_func,
       
   358 				 NULL,
       
   359 				 MAX_THREADS,
       
   360 				 FALSE,
       
   361 				 NULL);
       
   362 
       
   363   g_thread_pool_set_max_unused_threads (MAX_UNUSED_THREADS);
       
   364   g_thread_pool_set_max_idle_time (interval);
       
   365 
       
   366   g_assert (g_thread_pool_get_max_unused_threads () == MAX_UNUSED_THREADS);
       
   367   g_assert (g_thread_pool_get_max_idle_time () == interval);
       
   368 
       
   369   for (i = 0; i < limit; i++) {
       
   370     g_thread_pool_push (idle_pool, GUINT_TO_POINTER (i + 1), NULL);
       
   371     DEBUG_MSG (("[idle] ===> pushed new thread with id:%d, "
       
   372 		"number of threads:%d, unprocessed:%d",
       
   373 		i,
       
   374 		g_thread_pool_get_num_threads (idle_pool),
       
   375 		g_thread_pool_unprocessed (idle_pool)));
       
   376   }
       
   377 
       
   378   g_timeout_add ((interval - 1000),
       
   379 		 test_thread_idle_timeout,
       
   380 		 GUINT_TO_POINTER (interval));
       
   381 }
       
   382 
       
   383 static gboolean
       
   384 test_check_start_and_stop (gpointer user_data)
       
   385 {
       
   386   static guint test_number = 0;
       
   387   static gboolean run_next = FALSE;
       
   388   gboolean continue_timeout = TRUE;
       
   389   gboolean quit = TRUE;
       
   390 
       
   391   if (test_number == 0) {
       
   392     run_next = TRUE;
       
   393     DEBUG_MSG (("***** RUNNING TEST %2.2d *****", test_number));
       
   394   }
       
   395 
       
   396   if (run_next) {
       
   397     test_number++;
       
   398 
       
   399     switch (test_number) {
       
   400     case 1:
       
   401       test_thread_functions ();
       
   402       break;
       
   403     case 2:
       
   404       test_thread_stop_unused ();
       
   405       break;
       
   406     case 3:
       
   407       test_thread_pools ();
       
   408       break;
       
   409     case 4:
       
   410       test_thread_sort (FALSE);
       
   411       break;
       
   412     case 5:
       
   413       test_thread_sort (TRUE);
       
   414       break;
       
   415     case 6:
       
   416       test_thread_stop_unused ();
       
   417       break;
       
   418     case 7:
       
   419       test_thread_idle_time ();
       
   420       break;
       
   421     default:
       
   422       DEBUG_MSG (("***** END OF TESTS *****"));
       
   423       g_main_loop_quit (main_loop);
       
   424       continue_timeout = FALSE;
       
   425       break;
       
   426     }
       
   427 
       
   428     run_next = FALSE;
       
   429     return TRUE;
       
   430   }
       
   431 
       
   432   if (test_number == 3) {
       
   433     G_LOCK (thread_counter_pools);
       
   434     quit &= running_thread_counter <= 0;
       
   435     DEBUG_MSG (("***** POOL RUNNING THREAD COUNT:%ld",
       
   436 		running_thread_counter));
       
   437     G_UNLOCK (thread_counter_pools);
       
   438   }
       
   439 
       
   440   if (test_number == 4 || test_number == 5) {
       
   441     G_LOCK (thread_counter_sort);
       
   442     quit &= sort_thread_counter <= 0;
       
   443     DEBUG_MSG (("***** POOL SORT THREAD COUNT:%ld",
       
   444 		sort_thread_counter));
       
   445     G_UNLOCK (thread_counter_sort);
       
   446   }
       
   447 
       
   448   if (test_number == 7) {
       
   449     guint idle;
       
   450 
       
   451     idle = g_thread_pool_get_num_unused_threads ();
       
   452     quit &= idle < 1;
       
   453     DEBUG_MSG (("***** POOL IDLE THREAD COUNT:%d, UNPROCESSED JOBS:%d",
       
   454 		idle, g_thread_pool_unprocessed (idle_pool)));
       
   455   }
       
   456 
       
   457   if (quit) {
       
   458     run_next = TRUE;
       
   459   }
       
   460 
       
   461   return continue_timeout;
       
   462 }
       
   463 
       
   464 int
       
   465 main (int argc, char *argv[])
       
   466 {
       
   467   /* Only run the test, if threads are enabled and a default thread
       
   468      implementation is available */
       
   469   #ifdef __SYMBIAN32__
       
   470   guint g_thread_pool_unprocessed_op = -1;
       
   471   guint res;
       
   472   #endif //__SYMBIAN32__
       
   473 
       
   474 #if defined(G_THREADS_ENABLED) && ! defined(G_THREADS_IMPL_NONE)
       
   475   g_thread_init (NULL);
       
   476 
       
   477   DEBUG_MSG (("Starting... (in one second)"));
       
   478   g_timeout_add (1000, test_check_start_and_stop, NULL);
       
   479 
       
   480   main_loop = g_main_loop_new (NULL, FALSE);
       
   481   g_main_loop_run (main_loop);
       
   482 #endif
       
   483 #ifdef __SYMBIAN32__
       
   484   testResultXml("threadpool-test");
       
   485 #endif /* EMULATOR */
       
   486 
       
   487   return 0;
       
   488 }