1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/ossrv/glib/tsrc/BC/tests/threadpool-test.c Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,486 @@
1.4 +/* Portion Copyright © 2008-09 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.*/
1.5 +#undef G_DISABLE_ASSERT
1.6 +#undef G_LOG_DOMAIN
1.7 +
1.8 +#include <config.h>
1.9 +
1.10 +#include <glib.h>
1.11 +#include <stdio.h>
1.12 +
1.13 +#ifdef SYMBIAN
1.14 +#include <glib_global.h>
1.15 +#include "mrt2_glib2_test.h"
1.16 +#endif /*SYMBIAN*/
1.17 +
1.18 +#define DEBUG_MSG(x)
1.19 +/* #define DEBUG_MSG(args) g_printerr args ; g_printerr ("\n"); */
1.20 +
1.21 +#define WAIT 5 /* seconds */
1.22 +#define MAX_THREADS 10
1.23 +
1.24 +/* if > 0 the test will run continously (since the test ends when
1.25 + * thread count is 0), if -1 it means no limit to unused threads
1.26 + * if 0 then no unused threads are possible */
1.27 +#define MAX_UNUSED_THREADS -1
1.28 +
1.29 +G_LOCK_DEFINE_STATIC (thread_counter_pools);
1.30 +
1.31 +static gulong abs_thread_counter = 0;
1.32 +static gulong running_thread_counter = 0;
1.33 +static gulong leftover_task_counter = 0;
1.34 +
1.35 +G_LOCK_DEFINE_STATIC (last_thread);
1.36 +
1.37 +static guint last_thread_id = 0;
1.38 +
1.39 +G_LOCK_DEFINE_STATIC (thread_counter_sort);
1.40 +
1.41 +static gulong sort_thread_counter = 0;
1.42 +
1.43 +static GThreadPool *idle_pool = NULL;
1.44 +
1.45 +static GMainLoop *main_loop = NULL;
1.46 +
1.47 +static void
1.48 +test_thread_functions (void)
1.49 +{
1.50 + gint max_unused_threads;
1.51 + guint max_idle_time;
1.52 +
1.53 +
1.54 +
1.55 + /* This function attempts to call functions which don't need a
1.56 + * threadpool to operate to make sure no uninitialised pointers
1.57 + * accessed and no errors occur.
1.58 + */
1.59 +
1.60 + max_unused_threads = 3;
1.61 +
1.62 + DEBUG_MSG (("[funcs] Setting max unused threads to %d",
1.63 + max_unused_threads));
1.64 + g_thread_pool_set_max_unused_threads (max_unused_threads);
1.65 +
1.66 + DEBUG_MSG (("[funcs] Getting max unused threads = %d",
1.67 + g_thread_pool_get_max_unused_threads ()));
1.68 + g_assert (g_thread_pool_get_max_unused_threads() == max_unused_threads);
1.69 +
1.70 + DEBUG_MSG (("[funcs] Getting num unused threads = %d",
1.71 + g_thread_pool_get_num_unused_threads ()));
1.72 + g_assert (g_thread_pool_get_num_unused_threads () == 0);
1.73 +
1.74 + DEBUG_MSG (("[funcs] Stopping unused threads"));
1.75 + g_thread_pool_stop_unused_threads ();
1.76 +
1.77 + max_idle_time = 10 * G_USEC_PER_SEC;
1.78 +
1.79 + DEBUG_MSG (("[funcs] Setting max idle time to %d",
1.80 + max_idle_time));
1.81 + g_thread_pool_set_max_idle_time (max_idle_time);
1.82 +
1.83 + DEBUG_MSG (("[funcs] Getting max idle time = %d",
1.84 + g_thread_pool_get_max_idle_time ()));
1.85 + g_assert (g_thread_pool_get_max_idle_time () == max_idle_time);
1.86 +
1.87 + DEBUG_MSG (("[funcs] Setting max idle time to 0"));
1.88 + g_thread_pool_set_max_idle_time (0);
1.89 +
1.90 + DEBUG_MSG (("[funcs] Getting max idle time = %d",
1.91 + g_thread_pool_get_max_idle_time ()));
1.92 + g_assert (g_thread_pool_get_max_idle_time () == 0);
1.93 +}
1.94 +
1.95 +static void
1.96 +test_count_threads_foreach (GThread *thread,
1.97 + guint *count)
1.98 +{
1.99 + ++*count;
1.100 +}
1.101 +
1.102 +static guint
1.103 +test_count_threads (void)
1.104 +{
1.105 + guint count = 0;
1.106 +
1.107 + g_thread_foreach ((GFunc) test_count_threads_foreach, &count);
1.108 +
1.109 + /* Exclude main thread */
1.110 + return count - 1;
1.111 +}
1.112 +
1.113 +static void
1.114 +test_thread_stop_unused (void)
1.115 +{
1.116 + GThreadPool *pool;
1.117 + guint i;
1.118 + guint limit = 100;
1.119 +
1.120 + /* Spawn a few threads. */
1.121 + g_thread_pool_set_max_unused_threads (-1);
1.122 + pool = g_thread_pool_new ((GFunc) g_usleep, NULL, -1, FALSE, NULL);
1.123 +
1.124 + for (i = 0; i < limit; i++)
1.125 + g_thread_pool_push (pool, GUINT_TO_POINTER (1000), NULL);
1.126 +
1.127 + DEBUG_MSG (("[unused] ===> pushed %d threads onto the idle pool",
1.128 + limit));
1.129 +
1.130 + /* Wait for the threads to migrate. */
1.131 + g_usleep (G_USEC_PER_SEC);
1.132 +
1.133 + DEBUG_MSG (("[unused] current threads %d",
1.134 + test_count_threads()));
1.135 +
1.136 + DEBUG_MSG (("[unused] stopping unused threads"));
1.137 + g_thread_pool_stop_unused_threads ();
1.138 +
1.139 + DEBUG_MSG (("[unused] waiting ONE second for threads to die"));
1.140 +
1.141 + /* Some time for threads to die. */
1.142 + g_usleep (G_USEC_PER_SEC);
1.143 +
1.144 + DEBUG_MSG (("[unused] stopped idle threads, %d remain, %d threads still exist",
1.145 + g_thread_pool_get_num_unused_threads (),
1.146 + test_count_threads ()));
1.147 +
1.148 + g_assert (g_thread_pool_get_num_unused_threads () == test_count_threads ());
1.149 + g_assert (g_thread_pool_get_num_unused_threads () == 0);
1.150 +
1.151 + g_thread_pool_set_max_unused_threads (MAX_THREADS);
1.152 +
1.153 + DEBUG_MSG (("[unused] cleaning up thread pool"));
1.154 + g_thread_pool_free (pool, FALSE, TRUE);
1.155 +}
1.156 +
1.157 +static void
1.158 +test_thread_pools_entry_func (gpointer data, gpointer user_data)
1.159 +{
1.160 + guint id = 0;
1.161 +
1.162 + id = GPOINTER_TO_UINT (data);
1.163 +
1.164 + DEBUG_MSG (("[pool] ---> [%3.3d] entered thread.", id));
1.165 +
1.166 + G_LOCK (thread_counter_pools);
1.167 + abs_thread_counter++;
1.168 + running_thread_counter++;
1.169 + G_UNLOCK (thread_counter_pools);
1.170 +
1.171 + g_usleep (g_random_int_range (0, 4000));
1.172 +
1.173 + G_LOCK (thread_counter_pools);
1.174 + running_thread_counter--;
1.175 + leftover_task_counter--;
1.176 +
1.177 + DEBUG_MSG (("[pool] ---> [%3.3d] exiting thread (abs count:%ld, "
1.178 + "running count:%ld, left over:%ld)",
1.179 + id, abs_thread_counter,
1.180 + running_thread_counter, leftover_task_counter));
1.181 + G_UNLOCK (thread_counter_pools);
1.182 +}
1.183 +
1.184 +static void
1.185 +test_thread_pools (void)
1.186 +{
1.187 + GThreadPool *pool1, *pool2, *pool3;
1.188 + guint runs;
1.189 + guint i;
1.190 +
1.191 + pool1 = g_thread_pool_new ((GFunc)test_thread_pools_entry_func, NULL, 3, FALSE, NULL);
1.192 + pool2 = g_thread_pool_new ((GFunc)test_thread_pools_entry_func, NULL, 5, TRUE, NULL);
1.193 + pool3 = g_thread_pool_new ((GFunc)test_thread_pools_entry_func, NULL, 7, TRUE, NULL);
1.194 +
1.195 + runs = 300;
1.196 + for (i = 0; i < runs; i++)
1.197 + {
1.198 + g_thread_pool_push (pool1, GUINT_TO_POINTER (i + 1), NULL);
1.199 + g_thread_pool_push (pool2, GUINT_TO_POINTER (i + 1), NULL);
1.200 + g_thread_pool_push (pool3, GUINT_TO_POINTER (i + 1), NULL);
1.201 + leftover_task_counter += 3;
1.202 + }
1.203 +
1.204 + g_thread_pool_free (pool1, TRUE, TRUE);
1.205 + g_thread_pool_free (pool2, FALSE, TRUE);
1.206 + g_thread_pool_free (pool3, FALSE, TRUE);
1.207 +
1.208 + g_assert (runs * 3 == abs_thread_counter + leftover_task_counter);
1.209 + g_assert (running_thread_counter == 0);
1.210 +}
1.211 +
1.212 +static gint
1.213 +test_thread_sort_compare_func (gconstpointer a, gconstpointer b, gpointer user_data)
1.214 +{
1.215 + guint32 id1, id2;
1.216 +
1.217 + id1 = GPOINTER_TO_UINT (a);
1.218 + id2 = GPOINTER_TO_UINT (b);
1.219 +
1.220 + return (id1 > id2 ? +1 : id1 == id2 ? 0 : -1);
1.221 +}
1.222 +
1.223 +static void
1.224 +test_thread_sort_entry_func (gpointer data, gpointer user_data)
1.225 +{
1.226 + guint thread_id;
1.227 + gboolean is_sorted;
1.228 +
1.229 + G_LOCK (last_thread);
1.230 +
1.231 + thread_id = GPOINTER_TO_UINT (data);
1.232 + is_sorted = GPOINTER_TO_INT (user_data);
1.233 +
1.234 + DEBUG_MSG (("%s ---> entered thread:%2.2d, last thread:%2.2d",
1.235 + is_sorted ? "[ sorted]" : "[unsorted]",
1.236 + thread_id, last_thread_id));
1.237 +
1.238 + if (is_sorted) {
1.239 + static gboolean last_failed = FALSE;
1.240 +
1.241 + if (last_thread_id > thread_id) {
1.242 + if (last_failed) {
1.243 + g_assert (last_thread_id <= thread_id);
1.244 + }
1.245 +
1.246 + /* Here we remember one fail and if it concurrently fails, it
1.247 + * can not be sorted. the last thread id might be < this thread
1.248 + * id if something is added to the queue since threads were
1.249 + * created
1.250 + */
1.251 + last_failed = TRUE;
1.252 + } else {
1.253 + last_failed = FALSE;
1.254 + }
1.255 +
1.256 + last_thread_id = thread_id;
1.257 + }
1.258 +
1.259 + G_UNLOCK (last_thread);
1.260 +
1.261 + g_usleep (WAIT * 1000);
1.262 +}
1.263 +
1.264 +static void
1.265 +test_thread_sort (gboolean sort)
1.266 +{
1.267 + GThreadPool *pool;
1.268 + guint limit;
1.269 + guint max_threads;
1.270 + gint i;
1.271 +
1.272 + limit = MAX_THREADS * 10;
1.273 +
1.274 + if (sort) {
1.275 + max_threads = 1;
1.276 + } else {
1.277 + max_threads = MAX_THREADS;
1.278 + }
1.279 +
1.280 + /* It is important that we only have a maximum of 1 thread for this
1.281 + * test since the results can not be guranteed to be sorted if > 1.
1.282 + *
1.283 + * Threads are scheduled by the operating system and are executed at
1.284 + * random. It cannot be assumed that threads are executed in the
1.285 + * order they are created. This was discussed in bug #334943.
1.286 + */
1.287 +
1.288 + pool = g_thread_pool_new (test_thread_sort_entry_func,
1.289 + GINT_TO_POINTER (sort),
1.290 + max_threads,
1.291 + FALSE,
1.292 + NULL);
1.293 +
1.294 + g_thread_pool_set_max_unused_threads (MAX_UNUSED_THREADS);
1.295 +
1.296 + if (sort) {
1.297 + g_thread_pool_set_sort_function (pool,
1.298 + test_thread_sort_compare_func,
1.299 + GUINT_TO_POINTER (69));
1.300 + }
1.301 +
1.302 + for (i = 0; i < limit; i++) {
1.303 + guint id;
1.304 +
1.305 + id = g_random_int_range (1, limit) + 1;
1.306 + g_thread_pool_push (pool, GUINT_TO_POINTER (id), NULL);
1.307 + DEBUG_MSG (("%s ===> pushed new thread with id:%d, number "
1.308 + "of threads:%d, unprocessed:%d",
1.309 + sort ? "[ sorted]" : "[unsorted]",
1.310 + id,
1.311 + g_thread_pool_get_num_threads (pool),
1.312 + g_thread_pool_unprocessed (pool)));
1.313 + }
1.314 +
1.315 + g_assert (g_thread_pool_get_max_threads (pool) == max_threads);
1.316 + g_assert (g_thread_pool_get_num_threads (pool) == g_thread_pool_get_max_threads (pool));
1.317 +}
1.318 +
1.319 +static void
1.320 +test_thread_idle_time_entry_func (gpointer data, gpointer user_data)
1.321 +{
1.322 + guint thread_id;
1.323 +
1.324 + thread_id = GPOINTER_TO_UINT (data);
1.325 +
1.326 + DEBUG_MSG (("[idle] ---> entered thread:%2.2d", thread_id));
1.327 +
1.328 + g_usleep (WAIT * 1000);
1.329 +
1.330 + DEBUG_MSG (("[idle] <--- exiting thread:%2.2d", thread_id));
1.331 +}
1.332 +
1.333 +static gboolean
1.334 +test_thread_idle_timeout (gpointer data)
1.335 +{
1.336 + guint interval;
1.337 + gint i;
1.338 +
1.339 + interval = GPOINTER_TO_UINT (data);
1.340 +
1.341 + for (i = 0; i < 2; i++) {
1.342 + g_thread_pool_push (idle_pool, GUINT_TO_POINTER (100 + i), NULL);
1.343 + DEBUG_MSG (("[idle] ===> pushed new thread with id:%d, number "
1.344 + "of threads:%d, unprocessed:%d",
1.345 + 100 + i,
1.346 + g_thread_pool_get_num_threads (idle_pool),
1.347 + g_thread_pool_unprocessed (idle_pool)));
1.348 + }
1.349 +
1.350 +
1.351 + return FALSE;
1.352 +}
1.353 +
1.354 +static void
1.355 +test_thread_idle_time ()
1.356 +{
1.357 + guint limit = 50;
1.358 + guint interval = 10000;
1.359 + gint i;
1.360 +
1.361 + idle_pool = g_thread_pool_new (test_thread_idle_time_entry_func,
1.362 + NULL,
1.363 + MAX_THREADS,
1.364 + FALSE,
1.365 + NULL);
1.366 +
1.367 + g_thread_pool_set_max_unused_threads (MAX_UNUSED_THREADS);
1.368 + g_thread_pool_set_max_idle_time (interval);
1.369 +
1.370 + g_assert (g_thread_pool_get_max_unused_threads () == MAX_UNUSED_THREADS);
1.371 + g_assert (g_thread_pool_get_max_idle_time () == interval);
1.372 +
1.373 + for (i = 0; i < limit; i++) {
1.374 + g_thread_pool_push (idle_pool, GUINT_TO_POINTER (i + 1), NULL);
1.375 + DEBUG_MSG (("[idle] ===> pushed new thread with id:%d, "
1.376 + "number of threads:%d, unprocessed:%d",
1.377 + i,
1.378 + g_thread_pool_get_num_threads (idle_pool),
1.379 + g_thread_pool_unprocessed (idle_pool)));
1.380 + }
1.381 +
1.382 + g_timeout_add ((interval - 1000),
1.383 + test_thread_idle_timeout,
1.384 + GUINT_TO_POINTER (interval));
1.385 +}
1.386 +
1.387 +static gboolean
1.388 +test_check_start_and_stop (gpointer user_data)
1.389 +{
1.390 + static guint test_number = 0;
1.391 + static gboolean run_next = FALSE;
1.392 + gboolean continue_timeout = TRUE;
1.393 + gboolean quit = TRUE;
1.394 +
1.395 + if (test_number == 0) {
1.396 + run_next = TRUE;
1.397 + DEBUG_MSG (("***** RUNNING TEST %2.2d *****", test_number));
1.398 + }
1.399 +
1.400 + if (run_next) {
1.401 + test_number++;
1.402 +
1.403 + switch (test_number) {
1.404 + case 1:
1.405 + test_thread_functions ();
1.406 + break;
1.407 + case 2:
1.408 + test_thread_stop_unused ();
1.409 + break;
1.410 + case 3:
1.411 + test_thread_pools ();
1.412 + break;
1.413 + case 4:
1.414 + test_thread_sort (FALSE);
1.415 + break;
1.416 + case 5:
1.417 + test_thread_sort (TRUE);
1.418 + break;
1.419 + case 6:
1.420 + test_thread_idle_time ();
1.421 + break;
1.422 + default:
1.423 + DEBUG_MSG (("***** END OF TESTS *****"));
1.424 + g_main_loop_quit (main_loop);
1.425 + continue_timeout = FALSE;
1.426 + break;
1.427 + }
1.428 +
1.429 + run_next = FALSE;
1.430 + return TRUE;
1.431 + }
1.432 +
1.433 + if (test_number == 3) {
1.434 + G_LOCK (thread_counter_pools);
1.435 + quit &= running_thread_counter <= 0;
1.436 + DEBUG_MSG (("***** POOL RUNNING THREAD COUNT:%ld",
1.437 + running_thread_counter));
1.438 + G_UNLOCK (thread_counter_pools);
1.439 + }
1.440 +
1.441 + if (test_number == 4 || test_number == 5) {
1.442 + G_LOCK (thread_counter_sort);
1.443 + quit &= sort_thread_counter <= 0;
1.444 + DEBUG_MSG (("***** POOL SORT THREAD COUNT:%ld",
1.445 + sort_thread_counter));
1.446 + G_UNLOCK (thread_counter_sort);
1.447 + }
1.448 +
1.449 + if (test_number == 6) {
1.450 + guint idle;
1.451 +
1.452 + idle = g_thread_pool_get_num_unused_threads ();
1.453 + quit &= idle < 1;
1.454 + DEBUG_MSG (("***** POOL IDLE THREAD COUNT:%d, UNPROCESSED JOBS:%d",
1.455 + idle, g_thread_pool_unprocessed (idle_pool)));
1.456 + }
1.457 +
1.458 + if (quit) {
1.459 + run_next = TRUE;
1.460 + }
1.461 +
1.462 + return continue_timeout;
1.463 +}
1.464 +
1.465 +int
1.466 +main (int argc, char *argv[])
1.467 +{
1.468 + /* Only run the test, if threads are enabled and a default thread
1.469 + implementation is available */
1.470 + #ifdef SYMBIAN
1.471 + guint g_thread_pool_unprocessed_op = -1;
1.472 + guint res;
1.473 + #endif //SYMBIAN
1.474 +
1.475 +#if defined(G_THREADS_ENABLED) && ! defined(G_THREADS_IMPL_NONE)
1.476 + g_thread_init (NULL);
1.477 +
1.478 + DEBUG_MSG (("Starting... (in one second)"));
1.479 + g_timeout_add (1000, test_check_start_and_stop, NULL);
1.480 +
1.481 + main_loop = g_main_loop_new (NULL, FALSE);
1.482 + g_main_loop_run (main_loop);
1.483 +#endif
1.484 +#ifdef SYMBIAN
1.485 + testResultXml("threadpool-test");
1.486 +#endif /* EMULATOR */
1.487 +
1.488 + return 0;
1.489 +}