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 */