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