📄 stress_threads.c
字号:
}#endif /* DEATH_TIME_LIMIT */ if (client_makes_request > 0) { int prio; /* printf("just got a request from a client (count = %d)\n", */ /* client_makes_request); */ cyg_mutex_lock(&client_request_lock); { --client_makes_request; } cyg_mutex_unlock(&client_request_lock); handler_slot = get_handler_slot(listenerH[(int) data]); prio = N_CLIENTS+N_LISTENERS+handler_slot; priority_in_use[prio] = 1; sc_thread_create(prio, handler_program, (cyg_addrword_t) handler_slot, "handler", (void *) handler_stack[handler_slot], STACK_SIZE2, &handlerH[handler_slot], &handler_thread_s[handler_slot]); cyg_thread_resume(handlerH[handler_slot]); ++statistics.handler_invocation_histogram[handler_slot]; } cyg_thread_delay(1); }}/* 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(); if (time_to_report) { time_to_report = 0; print_statistics(); } cyg_thread_delay(4 + (int) (0.5*log(1.0 + fabs((rand() % 1000000)))));/* cyg_thread_delay(0); */ /* lock the scheduler before we declare this thread slot available and quit; note that cyg_thread_exit() will unlock the scheduler as many times as necessary */ cyg_mutex_lock(&handler_slot_lock); { handler_thread_in_use[data] = 0; priority_in_use[N_CLIENTS + N_LISTENERS + (int) data] = 0; } cyg_mutex_unlock(&handler_slot_lock); /* FIXME: could there be a race condition right here? I unlock the scheduler, so I could get pre-empted out, but meanwhile I have declared this thread available again. must fix it. */ sc_thread_exit();}/* look for an available handler thread */int get_handler_slot(cyg_handle_t current_threadH){ int i; int found = 0; while (!found) { for (i = 0; i < MAX_HANDLERS; ++i) { cyg_mutex_lock(&handler_slot_lock); { if (!handler_thread_in_use[i]) { found = 1; handler_thread_in_use[i] = 1; } } cyg_mutex_unlock(&handler_slot_lock); if (found) { break; }#ifdef DEATH_TIME_LIMIT /* must do a check here to see if all clients have been killed, since otherwise we might end up in an infinite loop */ if (n_clients_killed == N_CLIENTS) { n_clients_killed = -1; /* so we don't call this again */ CYG_TEST_PASS_FINISH("Kernel thread stress test OK"); }#endif } cyg_thread_delay(1); } return i;}/* 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]; unsigned int i; cyg_mutex_t tmp_lock; cyg_uint8 pool_space[10][100]; cyg_handle_t mempool_handles[10]; cyg_mempool_fix mempool_objects[10]; cyg_mutex_init(&tmp_lock); /* 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;/* spaces[i] = (char *) malloc(((int)(sqrt(i*2.0))+1)*MALLOCED_BASE_SIZE); */ spaces[i] = (char *) malloc(((int)i*2.0+1)*MALLOCED_BASE_SIZE); if (i % 100 == 0) { cyg_thread_yield(); } } /* now free it all up */ for (i = 0; i < MAX_MALLOCED_SPACES; ++i) { if (spaces[i] != NULL) { unsigned int j; for (j = 0; j < (i*2+1)*MALLOCED_BASE_SIZE; ++j) { 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]); } } cyg_mutex_destroy(&tmp_lock);}/* 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 threads. */void report_alarm_func(cyg_handle_t alarmH, cyg_addrword_t data){ time_to_report = 1;}/* 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){#ifdef DEATH_TIME_LIMIT 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; cyg_alarm_initialize(*deathHp, cyg_current_time() + tick_delay, 0); }#endif /* DEATH_TIME_LIMIT */}/* 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;}#ifdef DEATH_TIME_LIMIT/* handle_death is called by a client thread when it dies; it kills off the alarm */void handle_death(cyg_handle_t deathH, cyg_handle_t alarmH){ ++n_clients_killed; cyg_alarm_delete(deathH); cyg_alarm_delete(alarmH); cyg_thread_exit();}#endif /* DEATH_TIME_LIMIT *//* now I write the sc_ versions of the cyg_functions */void 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 */){/*printf("Creating a thread -- priority is %lu\n", (unsigned long) sched_info);*//* fflush(stdout); */ ++statistics.thread_creations; cyg_thread_create(sched_info, entry, entry_data, name, stack_base, stack_size, handle, thread);}void sc_thread_exit(){/* printf("exiting\n"); *//* fflush(stdout); */ ++statistics.thread_exits; cyg_thread_exit();}void print_statistics(void){ int i; cyg_mutex_lock(&statistics_print_lock); { 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); } cyg_mutex_unlock(&statistics_print_lock);}#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 + -