1
/* $Id: thread.c 3553 2011-05-05 06:14:19Z nanang $ */
3
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
* \page page_pjlib_thread_test Test: Thread Test
25
* This file contains \a thread_test() definition.
27
* \section thread_test_scope_sec Scope of Test
29
* - whether PJ_THREAD_SUSPENDED flag works.
30
* - whether multithreading works.
31
* - whether thread timeslicing works, and threads have equal
32
* time-slice proportion.
35
* - pj_thread_create()
36
* - pj_thread_register()
38
* - pj_thread_get_name()
39
* - pj_thread_destroy()
40
* - pj_thread_resume()
43
* - pj_thread_destroy()
46
* This file is <b>pjlib-test/thread.c</b>
48
* \include pjlib-test/thread.c
50
#if INCLUDE_THREAD_TEST
54
#define THIS_FILE "thread_test"
56
static volatile int quit_flag=0;
59
# define TRACE__(args) PJ_LOG(3,args)
61
# define TRACE__(args)
66
* The thread's entry point.
68
* Each of the thread mainly will just execute the loop which
69
* increments a variable.
71
static void* thread_proc(pj_uint32_t *pcounter)
73
/* Test that pj_thread_register() works. */
75
pj_thread_t *this_thread;
80
TRACE__((THIS_FILE, " thread %d running..", id));
82
pj_bzero(desc, sizeof(desc));
84
rc = pj_thread_register("thread", desc, &this_thread);
85
if (rc != PJ_SUCCESS) {
86
app_perror("...error in pj_thread_register", rc);
90
/* Test that pj_thread_this() works */
91
this_thread = pj_thread_this();
92
if (this_thread == NULL) {
93
PJ_LOG(3,(THIS_FILE, "...error: pj_thread_this() returns NULL!"));
97
/* Test that pj_thread_get_name() works */
98
if (pj_thread_get_name(this_thread) == NULL) {
99
PJ_LOG(3,(THIS_FILE, "...error: pj_thread_get_name() returns NULL!"));
106
//Must sleep if platform doesn't do time-slicing.
107
//pj_thread_sleep(0);
110
TRACE__((THIS_FILE, " thread %d quitting..", id));
117
static int simple_thread(const char *title, unsigned flags)
122
pj_uint32_t counter = 0;
124
PJ_LOG(3,(THIS_FILE, "..%s", title));
126
pool = pj_pool_create(mem, NULL, 4000, 4000, NULL);
132
TRACE__((THIS_FILE, " Creating thread 0.."));
133
rc = pj_thread_create(pool, "thread", (pj_thread_proc*)&thread_proc,
135
PJ_THREAD_DEFAULT_STACK_SIZE,
139
if (rc != PJ_SUCCESS) {
140
app_perror("...error: unable to create thread", rc);
144
TRACE__((THIS_FILE, " Main thread waiting.."));
145
pj_thread_sleep(1500);
146
TRACE__((THIS_FILE, " Main thread resuming.."));
148
if (flags & PJ_THREAD_SUSPENDED) {
150
/* Check that counter is still zero */
152
PJ_LOG(3,(THIS_FILE, "...error: thread is not suspended"));
156
rc = pj_thread_resume(thread);
157
if (rc != PJ_SUCCESS) {
158
app_perror("...error: resume thread error", rc);
163
PJ_LOG(3,(THIS_FILE, "..waiting for thread to quit.."));
165
pj_thread_sleep(1500);
168
pj_thread_join(thread);
170
pj_pool_release(pool);
173
PJ_LOG(3,(THIS_FILE, "...error: thread is not running"));
177
PJ_LOG(3,(THIS_FILE, "...%s success", title));
185
static int timeslice_test(void)
187
enum { NUM_THREADS = 4 };
189
pj_uint32_t counter[NUM_THREADS], lowest, highest, diff;
190
pj_thread_t *thread[NUM_THREADS];
196
pool = pj_pool_create(mem, NULL, 4000, 4000, NULL);
200
PJ_LOG(3,(THIS_FILE, "..timeslice testing with %d threads", NUM_THREADS));
202
/* Create all threads in suspended mode. */
203
for (i=0; i<NUM_THREADS; ++i) {
205
rc = pj_thread_create(pool, "thread", (pj_thread_proc*)&thread_proc,
207
PJ_THREAD_DEFAULT_STACK_SIZE,
210
if (rc!=PJ_SUCCESS) {
211
app_perror("...ERROR in pj_thread_create()", rc);
216
/* Sleep for 1 second.
217
* The purpose of this is to test whether all threads are suspended.
219
TRACE__((THIS_FILE, " Main thread waiting.."));
220
pj_thread_sleep(1000);
221
TRACE__((THIS_FILE, " Main thread resuming.."));
223
/* Check that all counters are still zero. */
224
for (i=0; i<NUM_THREADS; ++i) {
225
if (counter[i] > i) {
226
PJ_LOG(3,(THIS_FILE, "....ERROR! Thread %d-th is not suspended!",
232
/* Now resume all threads. */
233
for (i=0; i<NUM_THREADS; ++i) {
234
TRACE__((THIS_FILE, " Resuming thread %d [%p]..", i, thread[i]));
235
rc = pj_thread_resume(thread[i]);
236
if (rc != PJ_SUCCESS) {
237
app_perror("...ERROR in pj_thread_resume()", rc);
242
/* Main thread sleeps for some time to allow threads to run.
243
* The longer we sleep, the more accurate the calculation will be,
244
* but it'll make user waits for longer for the test to finish.
246
TRACE__((THIS_FILE, " Main thread waiting (5s).."));
247
pj_thread_sleep(5000);
248
TRACE__((THIS_FILE, " Main thread resuming.."));
250
/* Signal all threads to quit. */
253
/* Wait until all threads quit, then destroy. */
254
for (i=0; i<NUM_THREADS; ++i) {
255
TRACE__((THIS_FILE, " Main thread joining thread %d [%p]..",
257
rc = pj_thread_join(thread[i]);
258
if (rc != PJ_SUCCESS) {
259
app_perror("...ERROR in pj_thread_join()", rc);
262
TRACE__((THIS_FILE, " Destroying thread %d [%p]..", i, thread[i]));
263
rc = pj_thread_destroy(thread[i]);
264
if (rc != PJ_SUCCESS) {
265
app_perror("...ERROR in pj_thread_destroy()", rc);
270
TRACE__((THIS_FILE, " Main thread calculating time slices.."));
272
/* Now examine the value of the counters.
273
* Check that all threads had equal proportion of processing.
277
for (i=0; i<NUM_THREADS; ++i) {
278
if (counter[i] < lowest)
280
if (counter[i] > highest)
281
highest = counter[i];
284
/* Check that all threads are running. */
286
PJ_LOG(3,(THIS_FILE, "...ERROR: not all threads were running!"));
290
/* The difference between lowest and higest should be lower than 50%.
292
diff = (highest-lowest)*100 / ((highest+lowest)/2);
295
"...ERROR: thread didn't have equal timeslice!"));
297
".....lowest counter=%u, highest counter=%u, diff=%u%%",
298
lowest, highest, diff));
302
"...info: timeslice diff between lowest & highest=%u%%",
306
pj_pool_release(pool);
310
int thread_test(void)
314
rc = simple_thread("simple thread test", 0);
315
if (rc != PJ_SUCCESS)
318
rc = simple_thread("suspended thread test", PJ_THREAD_SUSPENDED);
319
if (rc != PJ_SUCCESS)
322
rc = timeslice_test();
323
if (rc != PJ_SUCCESS)
330
/* To prevent warning about "translation unit is empty"
331
* when this test is disabled.
333
int dummy_thread_test;
334
#endif /* INCLUDE_THREAD_TEST */