📄 stress_threads.c
字号:
} 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; 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 /= 10;#ifdef CYGPKG_HAL_I386_LINUX // 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)externC void *cyg_libc_get_malloc_pool( void );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); //-------------------------------- // System information { cyg_mempool_info mem_info; cyg_mempool_var_get_info((cyg_handle_t) cyg_libc_get_malloc_pool(), &mem_info); printf(" Memory system: Total=0x%08x Free=0x%08x Max=0x%08x\n", mem_info.totalmem, mem_info.freemem, mem_info.maxfree); } // 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 /* CYGSEM_LIBC_MALLOC */# define N_A_MSG "this test needs malloc"#endif /* CYGSEM_LIBC_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 /* CYGSEM_LIBC_STDIO */# define N_A_MSG "this test needs stdio"#endif /* CYGSEM_LIBC_STDIO */#else // def CYGFUN_KERNEL_API_C# define N_A_MSG "this test needs Kernel C API"#endif#else // def CYGPKG_KERNEL && CYGPKG_IO && CYGPKG_LIBC# define N_A_MSG "this tests needs Kernel, libc and IO"#endif#ifdef N_A_MSGexternC voidcyg_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 + -