Mercurial > flash_v2
comparison packages/kernel/current/tests/stress_threads.c @ 4:1d7f19c9e4d1 ecos-sw-1999-05-11
Merge from eCos master repository on 1999-05-11-21:11:10-BST
| author | jlarmour |
|---|---|
| date | Tue, 11 May 1999 14:07:25 +0000 |
| parents | 443894e2e912 |
| children | ece80412419a |
comparison
equal
deleted
inserted
replaced
| 3:69e820d8bae1 | 4:1d7f19c9e4d1 |
|---|---|
| 28 //####COPYRIGHTEND#### | 28 //####COPYRIGHTEND#### |
| 29 //========================================================================== | 29 //========================================================================== |
| 30 //#####DESCRIPTIONBEGIN#### | 30 //#####DESCRIPTIONBEGIN#### |
| 31 // | 31 // |
| 32 // Author(s): rosalia | 32 // Author(s): rosalia |
| 33 // Contributors: rosalia | 33 // Contributors: rosalia, jskov |
| 34 // Date: 1999-04-13 | 34 // Date: 1999-04-13 |
| 35 // Description: Very simple thread stress test, with some memory | 35 // Description: Very simple thread stress test, with some memory |
| 36 // allocation and alarm handling. | 36 // allocation and alarm handling. |
| 37 // | |
| 38 // Notes: | |
| 39 // If client_makes_request is big, it means that there are made many more | |
| 40 // client requests than can be serviced. Consequently, clients are wasting | |
| 41 // CPU time and should be sleeping more. | |
| 42 // | |
| 43 // The list of handler invocations show how many threads are running | |
| 44 // at the same time. The more powerful the CPU, the more the numbers | |
| 45 // should spread out. | |
| 37 //####DESCRIPTIONEND#### | 46 //####DESCRIPTIONEND#### |
| 38 | 47 |
| 39 #include <pkgconf/system.h> | 48 #include <pkgconf/system.h> |
| 40 #include <cyg/infra/testcase.h> | 49 #include <cyg/infra/testcase.h> |
| 41 | 50 |
| 63 #if defined(CYGFUN_KERNEL_THREADS_TIMER) | 72 #if defined(CYGFUN_KERNEL_THREADS_TIMER) |
| 64 #if defined(CYGPKG_LIBC_MALLOC) | 73 #if defined(CYGPKG_LIBC_MALLOC) |
| 65 | 74 |
| 66 /* if TIME_LIMIT is defined, it represents the number of seconds this | 75 /* if TIME_LIMIT is defined, it represents the number of seconds this |
| 67 test should last; if it is undefined the test will go forever */ | 76 test should last; if it is undefined the test will go forever */ |
| 68 #define DEATH_TIME_LIMIT 15 | 77 #define DEATH_TIME_LIMIT 20 |
| 69 /* #undef DEATH_TIME_LIMIT */ | 78 /* #undef DEATH_TIME_LIMIT */ |
| 70 | 79 |
| 71 #define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL) | 80 #define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL) |
| 72 #define STACK_SIZE2 (8*1024 + CYGNUM_HAL_STACK_SIZE_TYPICAL) | 81 #define STACK_SIZE2 (8*1024 + CYGNUM_HAL_STACK_SIZE_TYPICAL) |
| 73 | 82 |
| 83 /* Allocate priorities in this order. This ensures that handlers | |
| 84 (which are the ones using the CPU) get enough CPU time to actually | |
| 85 complete their tasks. */ | |
| 86 #define N_MAIN 1 | |
| 87 #define MAX_HANDLERS 19 | |
| 88 #define N_LISTENERS 4 | |
| 74 #define N_CLIENTS 4 | 89 #define N_CLIENTS 4 |
| 75 #define N_LISTENERS 4 | 90 |
| 76 #define MAX_HANDLERS 19 | 91 #if (CYGNUM_KERNEL_SCHED_PRIORITIES >= (N_MAIN+MAX_HANDLERS+N_LISTENERS+N_CLIENTS)) |
| 77 | |
| 78 #if (CYGNUM_KERNEL_SCHED_PRIORITIES < (N_CLIENTS+N_LISTENERS+MAX_HANDLERS)) | |
| 79 # error "not enough priorities available" | |
| 80 #endif | |
| 81 | 92 |
| 82 /* if we use the bitmap scheduler we must make sure we don't use the | 93 /* if we use the bitmap scheduler we must make sure we don't use the |
| 83 same priority more than once, so we must store those already in use */ | 94 same priority more than once, so we must store those already in use */ |
| 84 static char priority_in_use[N_CLIENTS+N_LISTENERS+MAX_HANDLERS]; | 95 static volatile char priority_in_use[N_MAIN+MAX_HANDLERS+N_LISTENERS+N_CLIENTS]; |
| 85 | 96 |
| 86 /* now declare (and allocate space for) some kernel objects, like the | 97 /* now declare (and allocate space for) some kernel objects, like the |
| 87 threads we will use */ | 98 threads we will use */ |
| 99 cyg_thread main_thread_s; | |
| 100 cyg_thread handler_thread_s[MAX_HANDLERS]; | |
| 101 cyg_thread listener_thread_s[N_LISTENERS]; | |
| 88 cyg_thread client_thread_s[N_CLIENTS]; | 102 cyg_thread client_thread_s[N_CLIENTS]; |
| 89 cyg_thread listener_thread_s[N_LISTENERS]; | |
| 90 cyg_thread handler_thread_s[MAX_HANDLERS]; | |
| 91 | 103 |
| 92 /* space for stacks for all threads */ | 104 /* space for stacks for all threads */ |
| 105 char main_stack[STACK_SIZE]; | |
| 106 char handler_stack[MAX_HANDLERS][STACK_SIZE2]; | |
| 107 char listener_stack[N_LISTENERS][STACK_SIZE]; | |
| 93 char client_stack[N_CLIENTS][STACK_SIZE]; | 108 char client_stack[N_CLIENTS][STACK_SIZE]; |
| 94 char listener_stack[N_LISTENERS][STACK_SIZE]; | |
| 95 char handler_stack[MAX_HANDLERS][STACK_SIZE2]; | |
| 96 | 109 |
| 97 /* now the handles for the threads */ | 110 /* now the handles for the threads */ |
| 111 cyg_handle_t mainH; | |
| 112 cyg_handle_t handlerH[MAX_HANDLERS]; | |
| 113 cyg_handle_t listenerH[N_LISTENERS]; | |
| 98 cyg_handle_t clientH[N_CLIENTS]; | 114 cyg_handle_t clientH[N_CLIENTS]; |
| 99 cyg_handle_t listenerH[N_LISTENERS]; | |
| 100 cyg_handle_t handlerH[MAX_HANDLERS]; | |
| 101 | |
| 102 #ifdef DEATH_TIME_LIMIT | |
| 103 /* how many client threads have been killed by the death handler */ | |
| 104 int n_clients_killed = 0; | |
| 105 #endif /* DEATH_TIME_LIMIT */ | |
| 106 | 115 |
| 107 /* and now variables for the procedure which is the thread */ | 116 /* and now variables for the procedure which is the thread */ |
| 108 cyg_thread_entry_t client_program, listener_program, handler_program; | 117 cyg_thread_entry_t main_program, client_program, listener_program, |
| 118 handler_program; | |
| 109 | 119 |
| 110 /* a few mutexes used in the code */ | 120 /* a few mutexes used in the code */ |
| 111 cyg_mutex_t client_request_lock, handler_slot_lock, statistics_print_lock; | 121 cyg_mutex_t client_request_lock, handler_slot_lock, statistics_print_lock, |
| 122 free_handler_lock; | |
| 123 | |
| 124 /* global variables with which the handler IDs and thread priorities | |
| 125 to free are communicated from handlers to main_program. Access to | |
| 126 these are protected by free_handler_lock. An id of -1 means the | |
| 127 that the variables are empty. */ | |
| 128 volatile int free_handler_pri = 0; | |
| 129 volatile int free_handler_id = -1; | |
| 112 | 130 |
| 113 /* a global variable with which the client and server coordinate */ | 131 /* a global variable with which the client and server coordinate */ |
| 114 int client_makes_request = 0; | 132 int client_makes_request = 0; |
| 115 | 133 |
| 116 /* indicates that it's time to print out a report */ | 134 /* indicates that it's time to print out a report */ |
| 136 struct s_statistics statistics; | 154 struct s_statistics statistics; |
| 137 | 155 |
| 138 /* some function prototypes; those with the sc_ prefix are | 156 /* some function prototypes; those with the sc_ prefix are |
| 139 "statistics-collecting" versions of the cyg_ primitives */ | 157 "statistics-collecting" versions of the cyg_ primitives */ |
| 140 void sc_thread_create( | 158 void sc_thread_create( |
| 141 cyg_addrword_t sched_info, /* scheduling info (eg pri) */ | 159 cyg_addrword_t sched_info, /* scheduling info (eg pri) */ |
| 142 cyg_thread_entry_t *entry, /* entry point function */ | 160 cyg_thread_entry_t *entry, /* entry point function */ |
| 143 cyg_addrword_t entry_data, /* entry data */ | 161 cyg_addrword_t entry_data, /* entry data */ |
| 144 char *name, /* optional thread name */ | 162 char *name, /* optional thread name */ |
| 145 void *stack_base, /* stack base, NULL = alloc */ | 163 void *stack_base, /* stack base, NULL = alloc */ |
| 146 cyg_ucount32 stack_size, /* stack size, 0 = default */ | 164 cyg_ucount32 stack_size, /* stack size, 0 = default */ |
| 147 cyg_handle_t *handle, /* returned thread handle */ | 165 cyg_handle_t *handle, /* returned thread handle */ |
| 148 cyg_thread *thread /* put thread here */ | 166 cyg_thread *thread /* put thread here */ |
| 149 ); | 167 ); |
| 150 void sc_thread_exit(void); | |
| 151 | 168 |
| 152 int get_handler_slot(cyg_handle_t current_threadH); | 169 int get_handler_slot(cyg_handle_t current_threadH); |
| 153 void perform_stressful_tasks(void); | 170 void perform_stressful_tasks(void); |
| 154 void permute_array(char a[], int size, int seed); | 171 void permute_array(char a[], int size, int seed); |
| 155 void setup_death_alarm(cyg_addrword_t data, cyg_handle_t *deathHp, | 172 void setup_death_alarm(cyg_addrword_t data, cyg_handle_t *deathHp, |
| 156 cyg_alarm *death_alarm_p, int *killed_p); | 173 cyg_alarm *death_alarm_p, int *killed_p); |
| 157 void handle_death(cyg_handle_t deathH, cyg_handle_t alarmH); | |
| 158 void print_statistics(void); | 174 void print_statistics(void); |
| 159 | 175 |
| 160 /* we need to declare the alarm handling function (which is defined | 176 /* we need to declare the alarm handling function (which is defined |
| 161 below), so that we can pass it to cyg_alarm_initialize() */ | 177 below), so that we can pass it to cyg_alarm_initialize() */ |
| 162 cyg_alarm_t report_alarm_func, death_alarm_func; | 178 cyg_alarm_t report_alarm_func, death_alarm_func; |
| 173 CYG_TEST_INIT(); | 189 CYG_TEST_INIT(); |
| 174 CYG_TEST_INFO("# Entering stress's cyg_user_start() function"); | 190 CYG_TEST_INFO("# Entering stress's cyg_user_start() function"); |
| 175 | 191 |
| 176 cyg_mutex_init(&client_request_lock); | 192 cyg_mutex_init(&client_request_lock); |
| 177 cyg_mutex_init(&statistics_print_lock); | 193 cyg_mutex_init(&statistics_print_lock); |
| 194 cyg_mutex_init(&free_handler_lock); | |
| 178 | 195 |
| 179 /* initialize statistics */ | 196 /* initialize statistics */ |
| 180 memset(&statistics, 0, sizeof(statistics)); | 197 memset(&statistics, 0, sizeof(statistics)); |
| 198 | |
| 199 /* clear priority table */ | |
| 200 for (i = 0; i < sizeof(priority_in_use); i++) | |
| 201 priority_in_use[i] = 0; | |
| 202 | |
| 203 /* initialize main thread */ | |
| 204 { | |
| 205 char thread_name[] = "main"; | |
| 206 | |
| 207 sc_thread_create(0, main_program, (cyg_addrword_t) 0, | |
| 208 thread_name, (void *) main_stack, STACK_SIZE, | |
| 209 &mainH, &main_thread_s); | |
| 210 priority_in_use[0]++; | |
| 211 } | |
| 181 | 212 |
| 182 /* initialize all handler threads to not be in use */ | 213 /* initialize all handler threads to not be in use */ |
| 183 for (i = 0; i < MAX_HANDLERS; ++i) { | 214 for (i = 0; i < MAX_HANDLERS; ++i) { |
| 184 handler_thread_in_use[i] = 0; | 215 handler_thread_in_use[i] = 0; |
| 216 } | |
| 217 for (i = 0; i < N_LISTENERS; ++i) { | |
| 218 int prio; | |
| 219 char thread_name[20]; | |
| 220 sprintf(thread_name, "listener-%02d", i); | |
| 221 prio = N_MAIN + MAX_HANDLERS + i; | |
| 222 sc_thread_create(prio, listener_program, (cyg_addrword_t) i, | |
| 223 thread_name, (void *) listener_stack[i], STACK_SIZE, | |
| 224 &listenerH[i], &listener_thread_s[i]); | |
| 225 CYG_ASSERT(0 == priority_in_use[prio], "Priority already in use!"); | |
| 226 priority_in_use[prio]++; | |
| 185 } | 227 } |
| 186 for (i = 0; i < N_CLIENTS; ++i) { | 228 for (i = 0; i < N_CLIENTS; ++i) { |
| 187 int prio; | 229 int prio; |
| 188 char thread_name[20]; | 230 char thread_name[20]; |
| 189 sprintf(thread_name, "client-%02d", i); | 231 sprintf(thread_name, "client-%02d", i); |
| 190 prio = i; | 232 prio = N_MAIN + MAX_HANDLERS + N_LISTENERS + i; |
| 191 sc_thread_create(prio, client_program, (cyg_addrword_t) i, | 233 sc_thread_create(prio, client_program, (cyg_addrword_t) i, |
| 192 thread_name, (void *) client_stack[i], STACK_SIZE, | 234 thread_name, (void *) client_stack[i], STACK_SIZE, |
| 193 &(clientH[i]), &client_thread_s[i]); | 235 &(clientH[i]), &client_thread_s[i]); |
| 194 priority_in_use[prio] = 1; | 236 CYG_ASSERT(0 == priority_in_use[prio], "Priority already in use!"); |
| 195 } | 237 priority_in_use[prio]++; |
| 196 for (i = 0; i < N_LISTENERS; ++i) { | 238 } |
| 197 int prio; | 239 |
| 198 char thread_name[20]; | 240 cyg_thread_resume(mainH); |
| 199 sprintf(thread_name, "listener-%02d", i); | |
| 200 prio = N_CLIENTS + i; | |
| 201 sc_thread_create(prio, listener_program, (cyg_addrword_t) i, | |
| 202 thread_name, (void *) listener_stack[i], STACK_SIZE, | |
| 203 &listenerH[i], &listener_thread_s[i]); | |
| 204 priority_in_use[prio] = 1; | |
| 205 } | |
| 206 | |
| 207 for (i = 0; i < N_CLIENTS; ++i) { | 241 for (i = 0; i < N_CLIENTS; ++i) { |
| 208 cyg_thread_resume(clientH[i]); | 242 cyg_thread_resume(clientH[i]); |
| 209 } | 243 } |
| 210 for (i = 0; i < N_LISTENERS; ++i) { | 244 for (i = 0; i < N_LISTENERS; ++i) { |
| 211 cyg_thread_resume(listenerH[i]); | 245 cyg_thread_resume(listenerH[i]); |
| 218 | 252 |
| 219 cyg_alarm_create(counterH, report_alarm_func, | 253 cyg_alarm_create(counterH, report_alarm_func, |
| 220 (cyg_addrword_t) 4000, | 254 (cyg_addrword_t) 4000, |
| 221 &report_alarmH, &report_alarm); | 255 &report_alarmH, &report_alarm); |
| 222 if (cyg_test_is_simulator) { | 256 if (cyg_test_is_simulator) { |
| 223 cyg_alarm_initialize(report_alarmH, cyg_current_time()+300, 400); | 257 cyg_alarm_initialize(report_alarmH, cyg_current_time()+200, 200); |
| 224 } else { | 258 } else { |
| 225 cyg_alarm_initialize(report_alarmH, cyg_current_time()+300, 4000); | 259 cyg_alarm_initialize(report_alarmH, cyg_current_time()+300, 4000); |
| 226 } | 260 } |
| 227 | 261 } |
| 262 | |
| 263 /* main_program() -- frees resources and prints status. */ | |
| 264 void main_program(cyg_addrword_t data) | |
| 265 { | |
| 266 #ifdef DEATH_TIME_LIMIT | |
| 267 cyg_handle_t deathH; | |
| 268 cyg_alarm death_alarm; | |
| 269 int is_dead = 0; | |
| 270 | |
| 271 setup_death_alarm(0, &deathH, &death_alarm, &is_dead); | |
| 272 #endif /* DEATH_TIME_LIMIT */ | |
| 273 | |
| 274 printf("# Starting main\n"); | |
| 275 | |
| 276 for (;;) { | |
| 277 int handler_id = -1; | |
| 278 int handler_pri = 0; | |
| 279 | |
| 280 cyg_mutex_lock(&free_handler_lock); { | |
| 281 // If any handler has left its ID, copy the ID and | |
| 282 // priority values to local variables, and free up the | |
| 283 // global communication variables again. | |
| 284 if (-1 != free_handler_id) { | |
| 285 handler_id = free_handler_id; | |
| 286 handler_pri = free_handler_pri; | |
| 287 free_handler_id = -1; | |
| 288 } | |
| 289 } cyg_mutex_unlock(&free_handler_lock); | |
| 290 | |
| 291 if (-1 != handler_id) { | |
| 292 // Free the handler resources. This is done outside of the | |
| 293 // free_handler_lock to avoid deadlocks. | |
| 294 cyg_mutex_lock(&handler_slot_lock); { | |
| 295 CYG_ASSERT(1 == priority_in_use[handler_pri], | |
| 296 "Priority not in use!"); | |
| 297 CYG_ASSERT(1 == handler_thread_in_use[handler_id], | |
| 298 "Handler not in use!"); | |
| 299 handler_thread_in_use[handler_id]--; | |
| 300 priority_in_use[handler_pri]--; | |
| 301 // Finally delete the handler thread. | |
| 302 { | |
| 303 // workaround for PRs 20054-20058/20065 | |
| 304 cyg_thread_kill(handlerH[handler_id]); | |
| 305 } | |
| 306 cyg_thread_delete(handlerH[handler_id]); | |
| 307 } cyg_mutex_unlock(&handler_slot_lock); | |
| 308 } | |
| 309 | |
| 310 // Print status if time. | |
| 311 if (time_to_report) { | |
| 312 time_to_report = 0; | |
| 313 print_statistics(); | |
| 314 } | |
| 315 | |
| 316 #ifdef DEATH_TIME_LIMIT | |
| 317 // Stop test if time. | |
| 318 if (is_dead) { | |
| 319 print_statistics(); | |
| 320 CYG_TEST_PASS_FINISH("Kernel thread stress test OK"); | |
| 321 } | |
| 322 #endif /* DEATH_TIME_LIMIT */ | |
| 323 | |
| 324 cyg_thread_delay(3); | |
| 325 } | |
| 228 } | 326 } |
| 229 | 327 |
| 230 /* client_program() -- an obnoxious client which makes a lot of requests */ | 328 /* client_program() -- an obnoxious client which makes a lot of requests */ |
| 231 void client_program(cyg_addrword_t data) | 329 void client_program(cyg_addrword_t data) |
| 232 { | 330 { |
| 233 int delay; | 331 int delay; |
| 234 | 332 |
| 235 cyg_handle_t counterH, deathH, system_clockH; | |
| 236 cyg_alarm death_alarm; | |
| 237 int is_dead = 0; | |
| 238 | |
| 239 setup_death_alarm(data, &deathH, &death_alarm, &is_dead); | |
| 240 | |
| 241 printf("# Starting client-%d\n", (int) data); | 333 printf("# Starting client-%d\n", (int) data); |
| 242 | 334 |
| 243 system_clockH = cyg_real_time_clock(); | 335 system_clockH = cyg_real_time_clock(); |
| 244 cyg_clock_to_counter(system_clockH, &counterH); | 336 cyg_clock_to_counter(system_clockH, &counterH); |
| 245 | 337 |
| 246 for (;;) { | 338 for (;;) { |
| 247 delay = (rand() % 3); | 339 delay = (rand() % 20); |
| 248 | 340 |
| 249 /* now send a request to the server */ | 341 /* now send a request to the server */ |
| 250 cyg_mutex_lock(&client_request_lock); { | 342 cyg_mutex_lock(&client_request_lock); { |
| 251 ++client_makes_request; | 343 ++client_makes_request; |
| 252 /* printf("client_makes_request %d\n", client_makes_request); */ | 344 /* printf("client_makes_request %d\n", client_makes_request); */ |
| 253 } cyg_mutex_unlock(&client_request_lock); | 345 } cyg_mutex_unlock(&client_request_lock); |
| 254 | 346 |
| 255 cyg_thread_delay(10+delay); | 347 cyg_thread_delay(10+delay); |
| 256 /* cyg_thread_delay(0); */ | 348 /* cyg_thread_delay(0); */ |
| 257 #ifdef DEATH_TIME_LIMIT | |
| 258 if (is_dead) { | |
| 259 handle_death(deathH, report_alarmH); | |
| 260 } | |
| 261 #endif /* DEATH_TIME_LIMIT */ | |
| 262 } | 349 } |
| 263 } | 350 } |
| 264 | 351 |
| 265 /* listener_program() -- listens for a request and spawns a handler to | 352 /* listener_program() -- listens for a request and spawns a handler to |
| 266 take care of the request */ | 353 take care of the request */ |
| 267 void listener_program(cyg_addrword_t data) | 354 void listener_program(cyg_addrword_t data) |
| 268 { | 355 { |
| 269 /* int message = (int) data; */ | 356 /* int message = (int) data; */ |
| 270 int handler_slot; | 357 int handler_slot; |
| 271 | 358 |
| 272 printf("# Beginning execution; thread data is %d\n", (int) data); | 359 printf("# Beginning execution; thread data is %d\n", (int) data); |
| 273 | 360 |
| 274 for (;;) { | 361 for (;;) { |
| 275 #ifdef DEATH_TIME_LIMIT | 362 int make_request = 0; |
| 276 /* as an extra task, the listener sees if all clients have been | 363 cyg_mutex_lock(&client_request_lock); { |
| 277 killed off, so it can report that the test is over */ | 364 if (client_makes_request > 0) { |
| 278 if (n_clients_killed == N_CLIENTS) { | 365 --client_makes_request; |
| 279 n_clients_killed = -1; /* so we don't call this again */ | 366 make_request = 1; |
| 280 CYG_TEST_PASS_FINISH("Kernel thread stress test OK"); | 367 } |
| 281 } | 368 } cyg_mutex_unlock(&client_request_lock); |
| 282 #endif /* DEATH_TIME_LIMIT */ | 369 |
| 283 if (client_makes_request > 0) { | 370 if (make_request) { |
| 284 int prio; | 371 int prio; |
| 285 /* printf("just got a request from a client (count = %d)\n", */ | 372 /* printf("just got a request from a client (count = %d)\n", */ |
| 286 /* client_makes_request); */ | 373 /* client_makes_request); */ |
| 287 cyg_mutex_lock(&client_request_lock); { | 374 |
| 288 --client_makes_request; | 375 handler_slot = get_handler_slot(listenerH[(int) data]); |
| 289 } cyg_mutex_unlock(&client_request_lock); | 376 prio = N_MAIN+handler_slot; |
| 290 | 377 |
| 291 handler_slot = get_handler_slot(listenerH[(int) data]); | 378 CYG_ASSERT(0 == priority_in_use[prio], "Priority already in use!"); |
| 292 prio = N_CLIENTS+N_LISTENERS+handler_slot; | 379 priority_in_use[prio]++; |
| 293 priority_in_use[prio] = 1; | 380 sc_thread_create(prio, handler_program, |
| 294 sc_thread_create(prio, handler_program, | 381 (cyg_addrword_t) handler_slot, |
| 295 (cyg_addrword_t) handler_slot, | 382 "handler", (void *) handler_stack[handler_slot], |
| 296 "handler", (void *) handler_stack[handler_slot], | 383 STACK_SIZE2, &handlerH[handler_slot], |
| 297 STACK_SIZE2, &handlerH[handler_slot], | 384 &handler_thread_s[handler_slot]); |
| 298 &handler_thread_s[handler_slot]); | 385 cyg_thread_resume(handlerH[handler_slot]); |
| 299 cyg_thread_resume(handlerH[handler_slot]); | 386 ++statistics.handler_invocation_histogram[handler_slot]; |
| 300 ++statistics.handler_invocation_histogram[handler_slot]; | 387 } |
| 301 } | 388 |
| 302 cyg_thread_delay(1); | 389 cyg_thread_delay(2 + (rand() % 10)); |
| 303 } | 390 } |
| 304 } | 391 } |
| 305 | 392 |
| 306 /* handler_program() -- is spawned to handle each incoming request */ | 393 /* handler_program() -- is spawned to handle each incoming request */ |
| 307 void handler_program(cyg_addrword_t data) | 394 void handler_program(cyg_addrword_t data) |
| 308 { | 395 { |
| 309 /* here is where we perform specific stressful tasks */ | 396 /* here is where we perform specific stressful tasks */ |
| 310 perform_stressful_tasks(); | 397 perform_stressful_tasks(); |
| 311 | 398 |
| 312 if (time_to_report) { | |
| 313 time_to_report = 0; | |
| 314 print_statistics(); | |
| 315 } | |
| 316 | |
| 317 cyg_thread_delay(4 + (int) (0.5*log(1.0 + fabs((rand() % 1000000))))); | 399 cyg_thread_delay(4 + (int) (0.5*log(1.0 + fabs((rand() % 1000000))))); |
| 318 /* cyg_thread_delay(0); */ | 400 /* cyg_thread_delay(0); */ |
| 319 | 401 |
| 320 /* lock the scheduler before we declare this thread slot available | 402 ++statistics.thread_exits; |
| 321 and quit; note that cyg_thread_exit() will unlock the scheduler | 403 { |
| 322 as many times as necessary */ | 404 // Loop until the handler id and priority can be communicated to |
| 323 cyg_mutex_lock(&handler_slot_lock); { | 405 // the main_program. |
| 324 handler_thread_in_use[data] = 0; | 406 int freed = 0; |
| 325 priority_in_use[N_CLIENTS + N_LISTENERS + (int) data] = 0; | 407 do { |
| 326 } cyg_mutex_unlock(&handler_slot_lock); | 408 cyg_mutex_lock(&free_handler_lock); { |
| 327 /* FIXME: could there be a race condition right here? I unlock the | 409 if (-1 == free_handler_id) { |
| 328 scheduler, so I could get pre-empted out, but meanwhile I have | 410 free_handler_id = data; |
| 329 declared this thread available again. must fix it. */ | 411 free_handler_pri = N_MAIN+(int) data; |
| 330 sc_thread_exit(); | 412 freed = 1; |
| 413 } | |
| 414 } cyg_mutex_unlock(&free_handler_lock); | |
| 415 if (!freed) | |
| 416 cyg_thread_delay(2); | |
| 417 } while (!freed); | |
| 418 } | |
| 419 | |
| 420 // Then wait for the main_program to kill us. | |
| 421 for (;;) { | |
| 422 cyg_thread_delay(100); | |
| 423 } | |
| 331 } | 424 } |
| 332 | 425 |
| 333 /* look for an available handler thread */ | 426 /* look for an available handler thread */ |
| 334 int get_handler_slot(cyg_handle_t current_threadH) | 427 int get_handler_slot(cyg_handle_t current_threadH) |
| 335 { | 428 { |
| 336 int i; | 429 int i; |
| 337 int found = 0; | 430 int found = 0; |
| 338 | 431 |
| 339 while (!found) { | 432 while (!found) { |
| 340 for (i = 0; i < MAX_HANDLERS; ++i) { | 433 cyg_mutex_lock(&handler_slot_lock); { |
| 341 cyg_mutex_lock(&handler_slot_lock); { | 434 for (i = 0; i < MAX_HANDLERS; ++i) { |
| 342 if (!handler_thread_in_use[i]) { | 435 if (!handler_thread_in_use[i]) { |
| 343 found = 1; | 436 found = 1; |
| 344 handler_thread_in_use[i] = 1; | 437 handler_thread_in_use[i]++; |
| 345 } | 438 break; |
| 346 } cyg_mutex_unlock(&handler_slot_lock); | 439 } |
| 347 if (found) { | 440 } |
| 348 break; | 441 } cyg_mutex_unlock(&handler_slot_lock); |
| 349 } | 442 if (!found) |
| 350 #ifdef DEATH_TIME_LIMIT | 443 cyg_thread_delay(1); |
| 351 /* must do a check here to see if all clients have been killed, | 444 } |
| 352 since otherwise we might end up in an infinite loop */ | 445 |
| 353 if (n_clients_killed == N_CLIENTS) { | 446 CYG_ASSERT(1 == handler_thread_in_use[i], "Handler usage count wrong!"); |
| 354 n_clients_killed = -1; /* so we don't call this again */ | 447 |
| 355 CYG_TEST_PASS_FINISH("Kernel thread stress test OK"); | 448 return i; |
| 356 } | |
| 357 #endif | |
| 358 } | |
| 359 cyg_thread_delay(1); | |
| 360 } | |
| 361 return i; | |
| 362 } | 449 } |
| 363 | 450 |
| 364 /* do things which will stress the system */ | 451 /* do things which will stress the system */ |
| 365 void perform_stressful_tasks() | 452 void perform_stressful_tasks() |
| 366 { | 453 { |
| 384 (although I'm about to throw in a yield()) */ | 471 (although I'm about to throw in a yield()) */ |
| 385 for (i = 0; i < MAX_MALLOCED_SPACES; ++i) { | 472 for (i = 0; i < MAX_MALLOCED_SPACES; ++i) { |
| 386 ++statistics.malloc_tries; | 473 ++statistics.malloc_tries; |
| 387 /* spaces[i] = (char *) malloc(((int)(sqrt(i*2.0))+1)*MALLOCED_BASE_SIZE); */ | 474 /* spaces[i] = (char *) malloc(((int)(sqrt(i*2.0))+1)*MALLOCED_BASE_SIZE); */ |
| 388 spaces[i] = (char *) malloc(((int)i*2.0+1)*MALLOCED_BASE_SIZE); | 475 spaces[i] = (char *) malloc(((int)i*2.0+1)*MALLOCED_BASE_SIZE); |
| 389 if (i % 100 == 0) { | 476 if (i % (MAX_MALLOCED_SPACES/10) == 0) { |
| 390 cyg_thread_yield(); | 477 cyg_thread_yield(); |
| 478 } | |
| 479 if (i % (MAX_MALLOCED_SPACES/15) == 0) { | |
| 480 cyg_thread_delay(i % 5); | |
| 391 } | 481 } |
| 392 } | 482 } |
| 393 | 483 |
| 394 /* now free it all up */ | 484 /* now free it all up */ |
| 395 for (i = 0; i < MAX_MALLOCED_SPACES; ++i) { | 485 for (i = 0; i < MAX_MALLOCED_SPACES; ++i) { |
| 424 cyg_mutex_destroy(&tmp_lock); | 514 cyg_mutex_destroy(&tmp_lock); |
| 425 } | 515 } |
| 426 | 516 |
| 427 /* report_alarm_func() is invoked as an alarm handler, so it should be | 517 /* report_alarm_func() is invoked as an alarm handler, so it should be |
| 428 quick and simple. in this case it sets a global flag which is | 518 quick and simple. in this case it sets a global flag which is |
| 429 checked by threads. */ | 519 checked by main_program. */ |
| 430 void report_alarm_func(cyg_handle_t alarmH, cyg_addrword_t data) | 520 void report_alarm_func(cyg_handle_t alarmH, cyg_addrword_t data) |
| 431 { | 521 { |
| 432 time_to_report = 1; | 522 time_to_report = 1; |
| 433 } | 523 } |
| 434 | 524 |
| 435 /* this sets up death alarms. it gets the handle and alarm from the | 525 /* this sets up death alarms. it gets the handle and alarm from the |
| 436 caller, since they must persist for the life of the alarm */ | 526 caller, since they must persist for the life of the alarm */ |
| 437 void setup_death_alarm(cyg_addrword_t data, cyg_handle_t *deathHp, | 527 void setup_death_alarm(cyg_addrword_t data, cyg_handle_t *deathHp, |
| 438 cyg_alarm *death_alarm_p, int *killed_p) | 528 cyg_alarm *death_alarm_p, int *killed_p) |
| 439 { | 529 { |
| 440 #ifdef DEATH_TIME_LIMIT | |
| 441 cyg_handle_t system_clockH, counterH; | 530 cyg_handle_t system_clockH, counterH; |
| 442 cyg_resolution_t rtc_res; | 531 cyg_resolution_t rtc_res; |
| 443 | 532 |
| 444 system_clockH = cyg_real_time_clock(); | 533 system_clockH = cyg_real_time_clock(); |
| 445 cyg_clock_to_counter(system_clockH, &counterH); | 534 cyg_clock_to_counter(system_clockH, &counterH); |
| 453 tick_delay = (long long) | 542 tick_delay = (long long) |
| 454 ((1000000000.0*rtc_res.divisor) | 543 ((1000000000.0*rtc_res.divisor) |
| 455 *((double)DEATH_TIME_LIMIT)/((double)rtc_res.dividend)); | 544 *((double)DEATH_TIME_LIMIT)/((double)rtc_res.dividend)); |
| 456 if ( cyg_test_is_simulator ) | 545 if ( cyg_test_is_simulator ) |
| 457 tick_delay /= 10; | 546 tick_delay /= 10; |
| 547 #ifdef CYGPKG_HAL_I386_LINUX | |
| 548 // 20 seconds is a long time compared to the run time of other tests. | |
| 549 // Reduce to 10 seconds, allowing more tests to get run. | |
| 550 tick_delay /= 2; | |
| 551 #endif | |
| 552 | |
| 458 cyg_alarm_initialize(*deathHp, cyg_current_time() + tick_delay, 0); | 553 cyg_alarm_initialize(*deathHp, cyg_current_time() + tick_delay, 0); |
| 459 } | 554 } |
| 460 #endif /* DEATH_TIME_LIMIT */ | |
| 461 } | 555 } |
| 462 | 556 |
| 463 /* death_alarm_func() is the alarm handler that kills the current | 557 /* death_alarm_func() is the alarm handler that kills the current |
| 464 thread after a specified timeout. It does so by setting a flag the | 558 thread after a specified timeout. It does so by setting a flag the |
| 465 thread is constantly checking. */ | 559 thread is constantly checking. */ |
| 468 int *killed_p; | 562 int *killed_p; |
| 469 killed_p = (int *) data; | 563 killed_p = (int *) data; |
| 470 *killed_p = 1; | 564 *killed_p = 1; |
| 471 } | 565 } |
| 472 | 566 |
| 473 #ifdef DEATH_TIME_LIMIT | |
| 474 /* handle_death is called by a client thread when it dies; it kills | |
| 475 off the alarm */ | |
| 476 void handle_death(cyg_handle_t deathH, cyg_handle_t alarmH) | |
| 477 { | |
| 478 ++n_clients_killed; | |
| 479 cyg_alarm_delete(deathH); | |
| 480 cyg_alarm_delete(alarmH); | |
| 481 cyg_thread_exit(); | |
| 482 } | |
| 483 #endif /* DEATH_TIME_LIMIT */ | |
| 484 | |
| 485 /* now I write the sc_ versions of the cyg_functions */ | 567 /* now I write the sc_ versions of the cyg_functions */ |
| 486 void sc_thread_create( | 568 void sc_thread_create( |
| 487 cyg_addrword_t sched_info, /* scheduling info (eg pri) */ | 569 cyg_addrword_t sched_info, /* scheduling info (eg pri) */ |
| 488 cyg_thread_entry_t *entry, /* entry point function */ | 570 cyg_thread_entry_t *entry, /* entry point function */ |
| 489 cyg_addrword_t entry_data, /* entry data */ | 571 cyg_addrword_t entry_data, /* entry data */ |
| 490 char *name, /* optional thread name */ | 572 char *name, /* optional thread name */ |
| 491 void *stack_base, /* stack base, NULL = alloc */ | 573 void *stack_base, /* stack base, NULL = alloc */ |
| 492 cyg_ucount32 stack_size, /* stack size, 0 = default */ | 574 cyg_ucount32 stack_size, /* stack size, 0 = default */ |
| 493 cyg_handle_t *handle, /* returned thread handle */ | 575 cyg_handle_t *handle, /* returned thread handle */ |
| 494 cyg_thread *thread /* put thread here */ | 576 cyg_thread *thread /* put thread here */ |
| 499 ++statistics.thread_creations; | 581 ++statistics.thread_creations; |
| 500 cyg_thread_create(sched_info, entry, entry_data, name, | 582 cyg_thread_create(sched_info, entry, entry_data, name, |
| 501 stack_base, stack_size, handle, thread); | 583 stack_base, stack_size, handle, thread); |
| 502 } | 584 } |
| 503 | 585 |
| 504 void sc_thread_exit() | |
| 505 { | |
| 506 /* printf("exiting\n"); */ | |
| 507 /* fflush(stdout); */ | |
| 508 ++statistics.thread_exits; | |
| 509 cyg_thread_exit(); | |
| 510 } | |
| 511 | |
| 512 void print_statistics(void) | 586 void print_statistics(void) |
| 513 { | 587 { |
| 514 int i; | 588 int i; |
| 515 | 589 |
| 516 cyg_mutex_lock(&statistics_print_lock); { | 590 cyg_mutex_lock(&statistics_print_lock); { |
| 523 statistics.malloc_tries, statistics.malloc_failures); | 597 statistics.malloc_tries, statistics.malloc_failures); |
| 524 printf("client_makes_request: %d\n", client_makes_request); | 598 printf("client_makes_request: %d\n", client_makes_request); |
| 525 } cyg_mutex_unlock(&statistics_print_lock); | 599 } cyg_mutex_unlock(&statistics_print_lock); |
| 526 } | 600 } |
| 527 | 601 |
| 602 #else /* (CYGNUM_KERNEL_SCHED_PRIORITIES >= */ | |
| 603 /* (N_MAIN+N_CLIENTS+N_LISTENERS+MAX_HANDLERS)) */ | |
| 604 #define N_A_MSG "not enough priorities available" | |
| 605 #endif /* (CYGNUM_KERNEL_SCHED_PRIORITIES >= */ | |
| 606 /* (N_MAIN+N_CLIENTS+N_LISTENERS+MAX_HANDLERS)) */ | |
| 607 | |
| 528 #else /* CYGSEM_LIBC_MALLOC */ | 608 #else /* CYGSEM_LIBC_MALLOC */ |
| 529 # define N_A_MSG "this test needs malloc" | 609 # define N_A_MSG "this test needs malloc" |
| 530 #endif /* CYGSEM_LIBC_MALLOC */ | 610 #endif /* CYGSEM_LIBC_MALLOC */ |
| 531 | 611 |
| 532 #else /* CYGFUN_KERNEL_THREADS_TIMER */ | 612 #else /* CYGFUN_KERNEL_THREADS_TIMER */ |
