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