📄 stress_threads.c
字号:
{
int delay;
system_clockH = cyg_real_time_clock();
cyg_clock_to_counter(system_clockH, &counterH);
for (;;) {
delay = (rand() % 20);
/* now send a request to the server */
cyg_mutex_lock(&client_request_lock); {
if (0 == clients_paused)
client_makes_request++;
} cyg_mutex_unlock(&client_request_lock);
cyg_thread_delay(10+delay);
}
}
/* listener_program() -- listens for a request and spawns a handler to
take care of the request */
void listener_program(cyg_addrword_t data)
{
for (;;) {
int make_request = 0;
cyg_mutex_lock(&client_request_lock); {
if (client_makes_request > 0) {
--client_makes_request;
make_request = 1;
}
} cyg_mutex_unlock(&client_request_lock);
if (make_request)
start_handler();
cyg_thread_delay(2 + (rand() % 10));
}
}
/* handler_program() -- is spawned to handle each incoming request */
void handler_program(cyg_addrword_t data)
{
/* here is where we perform specific stressful tasks */
perform_stressful_tasks();
cyg_thread_delay(4 + (int) (0.5*log(1.0 + fabs((rand() % 1000000)))));
{
// Loop until the handler id and priority can be communicated to
// the main_program.
int freed = 0;
do {
cyg_mutex_lock(&free_handler_lock); {
if (-1 == free_handler_id) {
free_handler_id = data;
free_handler_pri = P_BASE_HANDLER+(int) data;
freed = 1;
}
} cyg_mutex_unlock(&free_handler_lock);
if (!freed)
cyg_thread_delay(2);
} while (!freed);
}
// Then exit.
cyg_thread_exit();
}
/* start a new handler */
void start_handler(void)
{
int prio;
char* name;
int handler_slot = 0;
int found = 0;
while (!found) {
cyg_mutex_lock(&handler_slot_lock); {
for (handler_slot = 0; handler_slot < MAX_HANDLERS;++handler_slot){
if (!handler_thread_in_use[handler_slot]) {
found = 1;
handler_thread_in_use[handler_slot]++;
handler_thread_in_use_count++;
break;
}
}
} cyg_mutex_unlock(&handler_slot_lock);
if (!found)
cyg_thread_delay(1);
}
CYG_ASSERT(1 == handler_thread_in_use[handler_slot],
"Handler usage count wrong!");
prio = P_BASE_HANDLER+handler_slot;
CYG_ASSERT(0 == priority_in_use[prio], "Priority already in use!");
priority_in_use[prio]++;
name = &thread_name[prio][0];
sprintf(name, "handler-%02d/%02d", handler_slot, prio);
priority_translation[prio] =
sc_thread_create(prio, handler_program,
(cyg_addrword_t) handler_slot,
name, (void *) handler_stack[handler_slot],
STACK_SIZE_HANDLER, &handlerH[handler_slot],
&handler_thread_s[handler_slot]);
cyg_thread_resume(handlerH[handler_slot]);
++statistics.handler_invocation_histogram[handler_slot];
}
/* free a locked handler thread */
void stop_handler(int handler_id, int handler_pri)
{
// Finally delete the handler thread. This must be done in a
// loop, waiting for the call to return true. If it returns
// false, go to sleep for a bit, so the killed thread gets a
// chance to run and complete its business.
while (!cyg_thread_delete(handlerH[handler_id])) {
cyg_thread_delay(1);
}
++statistics.thread_exits;
// Free the handler resources.
cyg_mutex_lock(&handler_slot_lock); {
handler_thread_in_use[handler_id]--;
handler_thread_in_use_count--;
priority_in_use[handler_pri]--;
CYG_ASSERT(0 == priority_in_use[handler_pri],
"Priority not in use!");
CYG_ASSERT(0 == handler_thread_in_use[handler_id],
"Handler not in use!");
CYG_ASSERT(0 <= handler_thread_in_use_count,
"Stopped more handlers than was started!");
} cyg_mutex_unlock(&handler_slot_lock);
}
/* do things which will stress the system */
void perform_stressful_tasks()
{
#define MAX_MALLOCED_SPACES 100 /* do this many mallocs at most */
#define MALLOCED_BASE_SIZE 1 /* basic size in bytes */
char *spaces[MAX_MALLOCED_SPACES];
int sizes[MAX_MALLOCED_SPACES];
unsigned int i, j, size;
cyg_uint8 pool_space[10][100];
cyg_handle_t mempool_handles[10];
cyg_mempool_fix mempool_objects[10];
/* here I use malloc, which uses the kernel's variable memory pools.
note that malloc/free is a bit simple-minded here: it does not
try to really fragment things, and it does not try to make the
allocation/deallocation concurrent with other thread execution
(although I'm about to throw in a yield()) */
for (i = 0; i < MAX_MALLOCED_SPACES; ++i) {
++statistics.malloc_tries;
size = (i*2+1)*MALLOCED_BASE_SIZE;
spaces[i] = (char *) malloc(size);
sizes[i] = size;
if (spaces[i] != NULL) {
// Fill with a known value (differs between chunk).
for (j = 0; j < size; ++j) {
spaces[i][j] = 0x50 | ((j+i) & 0x0f);
}
}
if (i % (MAX_MALLOCED_SPACES/10) == 0) {
cyg_thread_yield();
}
if (i % (MAX_MALLOCED_SPACES/15) == 0) {
cyg_thread_delay(i % 5);
}
}
cyg_thread_delay(5);
/* now free it all up */
for (i = 0; i < MAX_MALLOCED_SPACES; ++i) {
if (spaces[i] != NULL) {
size = sizes[i];
for (j = 0; j < size; ++j) {
// Validate chunk data.
if ((0x50 | ((j+i) & 0x0f)) != spaces[i][j]) {
printf("Bad byte in chunk\n");
}
spaces[i][j] = 0xAA; /* write a bit pattern */
}
free(spaces[i]);
} else {
++statistics.malloc_failures;
}
}
/* now allocate and then free some fixed-size memory pools; for
now this is simple-minded because it does not have many threads
sharing the memory pools and racing for memory. */
for (i = 0; i < 10; ++i) {
cyg_mempool_fix_create(pool_space[i], 100, (i+1)*3,
&mempool_handles[i], &mempool_objects[i]);
}
for (i = 0; i < 10; ++i) {
spaces[i] = cyg_mempool_fix_try_alloc(mempool_handles[i]);
}
for (i = 0; i < 10; ++i) {
if (spaces[i]) {
cyg_mempool_fix_delete(mempool_handles[i]);
}
}
}
/* report_alarm_func() is invoked as an alarm handler, so it should be
quick and simple. in this case it sets a global flag which is
checked by main_program. */
void report_alarm_func(cyg_handle_t alarmH, cyg_addrword_t data)
{
time_to_report = 1;
}
#ifdef DEATH_TIME_LIMIT
/* this sets up death alarms. it gets the handle and alarm from the
caller, since they must persist for the life of the alarm */
void setup_death_alarm(cyg_addrword_t data, cyg_handle_t *deathHp,
cyg_alarm *death_alarm_p, int *killed_p)
{
cyg_handle_t system_clockH, counterH;
cyg_resolution_t rtc_res;
system_clockH = cyg_real_time_clock();
cyg_clock_to_counter(system_clockH, &counterH);
cyg_alarm_create(counterH, death_alarm_func,
(cyg_addrword_t) killed_p,
deathHp, death_alarm_p);
rtc_res = cyg_clock_get_resolution(system_clockH);
{
cyg_tick_count_t tick_delay;
tick_delay = (long long)
((1000000000.0*rtc_res.divisor)
*((double)DEATH_TIME_LIMIT)/((double)rtc_res.dividend));
if ( cyg_test_is_simulator )
tick_delay /= SIM_DELAY_DIVISOR;
#ifdef CYGPKG_HAL_SYNTH
// 20 seconds is a long time compared to the run time of other tests.
// Reduce to 10 seconds, allowing more tests to get run.
tick_delay /= 2;
#endif
cyg_alarm_initialize(*deathHp, cyg_current_time() + tick_delay, 0);
}
}
#endif
/* death_alarm_func() is the alarm handler that kills the current
thread after a specified timeout. It does so by setting a flag the
thread is constantly checking. */
void death_alarm_func(cyg_handle_t alarmH, cyg_addrword_t data)
{
int *killed_p;
killed_p = (int *) data;
*killed_p = 1;
}
/* now I write the sc_ versions of the cyg_functions */
cyg_addrword_t sc_thread_create(
cyg_addrword_t sched_info, /* scheduling info (eg pri) */
cyg_thread_entry_t *entry, /* entry point function */
cyg_addrword_t entry_data, /* entry data */
char *name, /* optional thread name */
void *stack_base, /* stack base, NULL = alloc */
cyg_ucount32 stack_size, /* stack size, 0 = default */
cyg_handle_t *handle, /* returned thread handle */
cyg_thread *thread /* put thread here */
)
{
++statistics.thread_creations;
cyg_thread_create(sched_info, entry, entry_data, name,
stack_base, stack_size, handle, thread);
return cyg_thread_get_priority(*handle);
}
#define MINS_HOUR (60)
#define MINS_DAY (60*24)
void print_statistics(int print_full)
{
int i;
static int stat_dumps = 0;
static int print_count = 0;
static int shift_count = 0;
int minutes;
stat_dumps++;
// Find number of minutes.
minutes = time_report_delay*stat_dumps / 60;
if (!print_full) {
// Return if time/minutes not integer.
if ((time_report_delay*stat_dumps % 60) != 0)
return;
// After the first day, only dump stat once per day. Do print
// a . on the hour though.
if ((minutes > MINS_DAY) && ((minutes % MINS_DAY) != 0)) {
if ((minutes % MINS_HOUR) == 0) {
printf(".");
fflush(stdout);
}
return;
}
// After the first hour of the first day, only dump stat once
// per hour. Do print . each minute though.
if ((minutes < MINS_DAY) && (minutes > MINS_HOUR)
&& ((minutes % MINS_HOUR) != 0)) {
printf(".");
fflush(stdout);
return;
}
}
printf("\nState dump %d (%d hours, %d minutes) [numbers >>%d]\n",
++print_count, minutes / MINS_HOUR, minutes % MINS_HOUR,
shift_count);
cyg_mutex_lock(&statistics_print_lock); {
//--------------------------------
// Information private to this test:
printf(" Handler-invocations: ");
for (i = 0; i < MAX_HANDLERS; ++i) {
printf("%4lu ", statistics.handler_invocation_histogram[i]);
}
printf("\n");
printf(" malloc()-tries/failures: -- %7lu %7lu\n",
statistics.malloc_tries, statistics.malloc_failures);
printf(" client_makes_request: %d\n", client_makes_request);
// Check for big numbers and reduce if getting close to overflow
if (statistics.malloc_tries > 0x40000000) {
shift_count++;
for (i = 0; i < MAX_HANDLERS; ++i) {
statistics.handler_invocation_histogram[i] >>= 1;
}
statistics.malloc_tries >>= 1;
statistics.malloc_failures >>= 1;
}
} cyg_mutex_unlock(&statistics_print_lock);
#if CYGINT_ISO_MALLINFO
//--------------------------------
// System information
{
struct mallinfo mem_info;
mem_info = mallinfo();
printf(" Memory system: Total=0x%08x Free=0x%08x Max=0x%08x\n",
mem_info.arena, mem_info.fordblks, mem_info.maxfree);
}
#endif
// Dump stack status
printf(" Stack usage:\n");
cyg_test_dump_interrupt_stack_stats( " Interrupt" );
cyg_test_dump_idlethread_stack_stats( " Idle" );
cyg_test_dump_stack_stats(" Main", main_stack,
main_stack + sizeof(main_stack));
for (i = 0; i < MAX_HANDLERS; i++) {
cyg_test_dump_stack_stats(" Handler", handler_stack[i],
handler_stack[i] + sizeof(handler_stack[i]));
}
for (i = 0; i < N_LISTENERS; i++) {
cyg_test_dump_stack_stats(" Listener", listener_stack[i],
listener_stack[i] + sizeof(listener_stack[i]));
}
for (i = 0; i < N_CLIENTS; i++) {
cyg_test_dump_stack_stats(" Client", client_stack[i],
client_stack[i] + sizeof(client_stack[i]));
}
}
#else /* (CYGNUM_KERNEL_SCHED_PRIORITIES >= */
/* (N_MAIN+N_CLIENTS+N_LISTENERS+MAX_HANDLERS)) */
#define N_A_MSG "not enough priorities available"
#endif /* (CYGNUM_KERNEL_SCHED_PRIORITIES >= */
/* (N_MAIN+N_CLIENTS+N_LISTENERS+MAX_HANDLERS)) */
#else /* CYGINT_ISO_MALLOC */
# define N_A_MSG "this test needs malloc"
#endif /* CYGINT_ISO_MALLOC */
#else /* CYGFUN_KERNEL_THREADS_TIMER */
# define N_A_MSG "this test needs kernel threads timer"
#endif /* CYGFUN_KERNEL_THREADS_TIMER */
#else /* CYGPKG_LIBM */
# define N_A_MSG "this test needs libm"
#endif /* CYGPKG_LIBM */
#else /* CYGINT_ISO_STDIO_FORMATTED_IO */
# define N_A_MSG "this test needs stdio formatted I/O"
#endif /* CYGINT_ISO_STDIO_FORMATTED_IO */
#else // def CYGFUN_KERNEL_API_C
# define N_A_MSG "this test needs Kernel C API"
#endif
#else // def CYGPKG_KERNEL && CYGPKG_IO && CYGPKG_ISOINFRA
# define N_A_MSG "this tests needs Kernel, isoinfra and IO"
#endif
#ifdef N_A_MSG
externC void
cyg_start( void )
{
CYG_TEST_INIT();
CYG_TEST_NA( N_A_MSG);
}
#endif // N_A_MSG
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -