|
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 } |