📄 thread.c
字号:
/* $Id: thread.c 974 2007-02-19 01:13:53Z bennylp $ *//* * Copyright (C)2003-2007 Benny Prijono <benny@prijono.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include "test.h"/** * \page page_pjlib_thread_test Test: Thread Test * * This file contains \a thread_test() definition. * * \section thread_test_scope_sec Scope of Test * This tests: * - whether PJ_THREAD_SUSPENDED flag works. * - whether multithreading works. * - whether thread timeslicing works, and threads have equal * time-slice proportion. * * APIs tested: * - pj_thread_create() * - pj_thread_register() * - pj_thread_this() * - pj_thread_get_name() * - pj_thread_destroy() * - pj_thread_resume() * - pj_thread_sleep() * - pj_thread_join() * - pj_thread_destroy() * * * This file is <b>pjlib-test/thread.c</b> * * \include pjlib-test/thread.c */#if INCLUDE_THREAD_TEST#include <pjlib.h>#define THIS_FILE "thread_test"static volatile int quit_flag=0;#if 0# define TRACE__(args) PJ_LOG(3,args)#else# define TRACE__(args)#endif/* * The thread's entry point. * * Each of the thread mainly will just execute the loop which * increments a variable. */static void* thread_proc(pj_uint32_t *pcounter){ /* Test that pj_thread_register() works. */ pj_thread_desc desc; pj_thread_t *this_thread; unsigned id; pj_status_t rc; id = *pcounter; TRACE__((THIS_FILE, " thread %d running..", id)); pj_bzero(desc, sizeof(desc)); rc = pj_thread_register("thread", desc, &this_thread); if (rc != PJ_SUCCESS) { app_perror("...error in pj_thread_register", rc); return NULL; } /* Test that pj_thread_this() works */ this_thread = pj_thread_this(); if (this_thread == NULL) { PJ_LOG(3,(THIS_FILE, "...error: pj_thread_this() returns NULL!")); return NULL; } /* Test that pj_thread_get_name() works */ if (pj_thread_get_name(this_thread) == NULL) { PJ_LOG(3,(THIS_FILE, "...error: pj_thread_get_name() returns NULL!")); return NULL; } /* Main loop */ for (;!quit_flag;) { (*pcounter)++; //Must sleep if platform doesn't do time-slicing. //pj_thread_sleep(0); } TRACE__((THIS_FILE, " thread %d quitting..", id)); return NULL;}/* * simple_thread() */static int simple_thread(const char *title, unsigned flags){ pj_pool_t *pool; pj_thread_t *thread; pj_status_t rc; pj_uint32_t counter = 0; PJ_LOG(3,(THIS_FILE, "..%s", title)); pool = pj_pool_create(mem, NULL, 4000, 4000, NULL); if (!pool) return -1000; quit_flag = 0; TRACE__((THIS_FILE, " Creating thread 0..")); rc = pj_thread_create(pool, "thread", (pj_thread_proc*)&thread_proc, &counter, PJ_THREAD_DEFAULT_STACK_SIZE, flags, &thread); if (rc != PJ_SUCCESS) { app_perror("...error: unable to create thread", rc); return -1010; } TRACE__((THIS_FILE, " Main thread waiting..")); pj_thread_sleep(1500); TRACE__((THIS_FILE, " Main thread resuming..")); if (flags & PJ_THREAD_SUSPENDED) { /* Check that counter is still zero */ if (counter != 0) { PJ_LOG(3,(THIS_FILE, "...error: thread is not suspended")); return -1015; } rc = pj_thread_resume(thread); if (rc != PJ_SUCCESS) { app_perror("...error: resume thread error", rc); return -1020; } } PJ_LOG(3,(THIS_FILE, "..waiting for thread to quit..")); pj_thread_sleep(1500); quit_flag = 1; pj_thread_join(thread); pj_pool_release(pool); if (counter == 0) { PJ_LOG(3,(THIS_FILE, "...error: thread is not running")); return -1025; } PJ_LOG(3,(THIS_FILE, "...%s success", title)); return PJ_SUCCESS;}/* * timeslice_test() */static int timeslice_test(void){ enum { NUM_THREADS = 4 }; pj_pool_t *pool; pj_uint32_t counter[NUM_THREADS], lowest, highest, diff; pj_thread_t *thread[NUM_THREADS]; unsigned i; pj_status_t rc; quit_flag = 0; pool = pj_pool_create(mem, NULL, 4000, 4000, NULL); if (!pool) return -10; PJ_LOG(3,(THIS_FILE, "..timeslice testing with %d threads", NUM_THREADS)); /* Create all threads in suspended mode. */ for (i=0; i<NUM_THREADS; ++i) { counter[i] = i; rc = pj_thread_create(pool, "thread", (pj_thread_proc*)&thread_proc, &counter[i], PJ_THREAD_DEFAULT_STACK_SIZE, PJ_THREAD_SUSPENDED, &thread[i]); if (rc!=PJ_SUCCESS) { app_perror("...ERROR in pj_thread_create()", rc); return -20; } } /* Sleep for 1 second. * The purpose of this is to test whether all threads are suspended. */ TRACE__((THIS_FILE, " Main thread waiting..")); pj_thread_sleep(1000); TRACE__((THIS_FILE, " Main thread resuming..")); /* Check that all counters are still zero. */ for (i=0; i<NUM_THREADS; ++i) { if (counter[i] > i) { PJ_LOG(3,(THIS_FILE, "....ERROR! Thread %d-th is not suspended!", i)); return -30; } } /* Now resume all threads. */ for (i=0; i<NUM_THREADS; ++i) { TRACE__((THIS_FILE, " Resuming thread %d [%p]..", i, thread[i])); rc = pj_thread_resume(thread[i]); if (rc != PJ_SUCCESS) { app_perror("...ERROR in pj_thread_resume()", rc); return -40; } } /* Main thread sleeps for some time to allow threads to run. * The longer we sleep, the more accurate the calculation will be, * but it'll make user waits for longer for the test to finish. */ TRACE__((THIS_FILE, " Main thread waiting (5s)..")); pj_thread_sleep(5000); TRACE__((THIS_FILE, " Main thread resuming..")); /* Signal all threads to quit. */ quit_flag = 1; /* Wait until all threads quit, then destroy. */ for (i=0; i<NUM_THREADS; ++i) { TRACE__((THIS_FILE, " Main thread joining thread %d [%p]..", i, thread[i])); rc = pj_thread_join(thread[i]); if (rc != PJ_SUCCESS) { app_perror("...ERROR in pj_thread_join()", rc); return -50; } TRACE__((THIS_FILE, " Destroying thread %d [%p]..", i, thread[i])); rc = pj_thread_destroy(thread[i]); if (rc != PJ_SUCCESS) { app_perror("...ERROR in pj_thread_destroy()", rc); return -60; } } TRACE__((THIS_FILE, " Main thread calculating time slices..")); /* Now examine the value of the counters. * Check that all threads had equal proportion of processing. */ lowest = 0xFFFFFFFF; highest = 0; for (i=0; i<NUM_THREADS; ++i) { if (counter[i] < lowest) lowest = counter[i]; if (counter[i] > highest) highest = counter[i]; } /* Check that all threads are running. */ if (lowest < 2) { PJ_LOG(3,(THIS_FILE, "...ERROR: not all threads were running!")); return -70; } /* The difference between lowest and higest should be lower than 50%. */ diff = (highest-lowest)*100 / ((highest+lowest)/2); if ( diff >= 50) { PJ_LOG(3,(THIS_FILE, "...ERROR: thread didn't have equal timeslice!")); PJ_LOG(3,(THIS_FILE, ".....lowest counter=%u, highest counter=%u, diff=%u%%", lowest, highest, diff)); return -80; } else { PJ_LOG(3,(THIS_FILE, "...info: timeslice diff between lowest & highest=%u%%", diff)); } pj_pool_release(pool); return 0;}int thread_test(void){ int rc; rc = simple_thread("simple thread test", 0); if (rc != PJ_SUCCESS) return rc; rc = simple_thread("suspended thread test", PJ_THREAD_SUSPENDED); if (rc != PJ_SUCCESS) return rc; rc = timeslice_test(); if (rc != PJ_SUCCESS) return rc; return rc;}#else/* To prevent warning about "translation unit is empty" * when this test is disabled. */int dummy_thread_test;#endif /* INCLUDE_THREAD_TEST */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -