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