|
2
|
1 //========================================================================== |
|
|
2 // |
|
|
3 // stress_threads.cxx |
|
|
4 // |
|
|
5 // Basic thread stress test |
|
|
6 // |
|
|
7 //========================================================================== |
|
|
8 //####COPYRIGHTBEGIN#### |
|
|
9 // |
|
|
10 // ------------------------------------------- |
|
|
11 // The contents of this file are subject to the Cygnus eCos Public License |
|
|
12 // Version 1.0 (the "License"); you may not use this file except in |
|
|
13 // compliance with the License. You may obtain a copy of the License at |
|
|
14 // http://sourceware.cygnus.com/ecos |
|
|
15 // |
|
|
16 // Software distributed under the License is distributed on an "AS IS" |
|
|
17 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the |
|
|
18 // License for the specific language governing rights and limitations under |
|
|
19 // the License. |
|
|
20 // |
|
|
21 // The Original Code is eCos - Embedded Cygnus Operating System, released |
|
|
22 // September 30, 1998. |
|
|
23 // |
|
|
24 // The Initial Developer of the Original Code is Cygnus. Portions created |
|
|
25 // by Cygnus are Copyright (C) 1998,1999 Cygnus Solutions. All Rights Reserved. |
|
|
26 // ------------------------------------------- |
|
|
27 // |
|
|
28 //####COPYRIGHTEND#### |
|
|
29 //========================================================================== |
|
|
30 //#####DESCRIPTIONBEGIN#### |
|
|
31 // |
|
|
32 // Author(s): rosalia |
|
|
33 // Contributors: rosalia |
|
|
34 // Date: 1999-04-13 |
|
|
35 // Description: Very simple thread stress test, with some memory |
|
|
36 // allocation and alarm handling. |
|
|
37 //####DESCRIPTIONEND#### |
|
|
38 |
|
|
39 #include <pkgconf/system.h> |
|
|
40 #include <cyg/infra/testcase.h> |
|
|
41 |
|
|
42 #include <cyg/hal/hal_arch.h> |
|
|
43 |
|
|
44 #if defined(CYGPKG_KERNEL) && defined(CYGPKG_IO) && defined(CYGPKG_LIBC) |
|
|
45 |
|
|
46 #include <pkgconf/kernel.h> |
|
|
47 #include <pkgconf/libc.h> |
|
|
48 |
|
|
49 #if defined(CYGFUN_KERNEL_API_C) |
|
|
50 |
|
|
51 #include <cyg/kernel/kapi.h> |
|
|
52 |
|
|
53 #ifdef CYGPKG_LIBC_STDIO |
|
|
54 |
|
|
55 #include <stdio.h> |
|
|
56 #include <stdlib.h> |
|
|
57 |
|
|
58 #if defined(CYGPKG_LIBM) |
|
|
59 |
|
|
60 #include <math.h> |
|
|
61 #include <assert.h> |
|
|
62 |
|
|
63 #if defined(CYGFUN_KERNEL_THREADS_TIMER) |
|
|
64 #if defined(CYGPKG_LIBC_MALLOC) |
|
|
65 |
|
|
66 /* 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 */ |
|
|
68 #define DEATH_TIME_LIMIT 15 |
|
|
69 /* #undef DEATH_TIME_LIMIT */ |
|
|
70 |
|
|
71 #define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL) |
|
|
72 #define STACK_SIZE2 (8*1024 + CYGNUM_HAL_STACK_SIZE_TYPICAL) |
|
|
73 |
|
|
74 #define N_CLIENTS 4 |
|
|
75 #define N_LISTENERS 4 |
|
|
76 #define MAX_HANDLERS 19 |
|
|
77 |
|
|
78 #if (CYGNUM_KERNEL_SCHED_PRIORITIES < (N_CLIENTS+N_LISTENERS+MAX_HANDLERS)) |
|
|
79 # error "not enough priorities available" |
|
|
80 #endif |
|
|
81 |
|
|
82 /* 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 */ |
|
|
84 static char priority_in_use[N_CLIENTS+N_LISTENERS+MAX_HANDLERS]; |
|
|
85 |
|
|
86 /* now declare (and allocate space for) some kernel objects, like the |
|
|
87 threads we will use */ |
|
|
88 cyg_thread client_thread_s[N_CLIENTS]; |
|
|
89 cyg_thread listener_thread_s[N_LISTENERS]; |
|
|
90 cyg_thread handler_thread_s[MAX_HANDLERS]; |
|
|
91 |
|
|
92 /* space for stacks for all threads */ |
|
|
93 char client_stack[N_CLIENTS][STACK_SIZE]; |
|
|
94 char listener_stack[N_LISTENERS][STACK_SIZE]; |
|
|
95 char handler_stack[MAX_HANDLERS][STACK_SIZE2]; |
|
|
96 |
|
|
97 /* now the handles for the threads */ |
|
|
98 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 |
|
|
107 /* and now variables for the procedure which is the thread */ |
|
|
108 cyg_thread_entry_t client_program, listener_program, handler_program; |
|
|
109 |
|
|
110 /* a few mutexes used in the code */ |
|
|
111 cyg_mutex_t client_request_lock, handler_slot_lock, statistics_print_lock; |
|
|
112 |
|
|
113 /* a global variable with which the client and server coordinate */ |
|
|
114 int client_makes_request = 0; |
|
|
115 |
|
|
116 /* indicates that it's time to print out a report */ |
|
|
117 int time_to_report = 0; |
|
|
118 |
|
|
119 /*** now application-specific variables ***/ |
|
|
120 /* an array that stores whether the handler threads are in use */ |
|
|
121 int handler_thread_in_use[MAX_HANDLERS]; |
|
|
122 |
|
|
123 /***** statistics-gathering variables *****/ |
|
|
124 struct s_statistics { |
|
|
125 /* store the number of times each handler has been invoked */ |
|
|
126 unsigned long handler_invocation_histogram[MAX_HANDLERS]; |
|
|
127 |
|
|
128 /* store how many times malloc has been attempted and how many times |
|
|
129 it has failed */ |
|
|
130 unsigned long malloc_tries, malloc_failures; |
|
|
131 |
|
|
132 /* how many threads have been created */ |
|
|
133 unsigned long thread_creations, thread_exits; |
|
|
134 }; |
|
|
135 |
|
|
136 struct s_statistics statistics; |
|
|
137 |
|
|
138 /* some function prototypes; those with the sc_ prefix are |
|
|
139 "statistics-collecting" versions of the cyg_ primitives */ |
|
|
140 void sc_thread_create( |
|
|
141 cyg_addrword_t sched_info, /* scheduling info (eg pri) */ |
|
|
142 cyg_thread_entry_t *entry, /* entry point function */ |
|
|
143 cyg_addrword_t entry_data, /* entry data */ |
|
|
144 char *name, /* optional thread name */ |
|
|
145 void *stack_base, /* stack base, NULL = alloc */ |
|
|
146 cyg_ucount32 stack_size, /* stack size, 0 = default */ |
|
|
147 cyg_handle_t *handle, /* returned thread handle */ |
|
|
148 cyg_thread *thread /* put thread here */ |
|
|
149 ); |
|
|
150 void sc_thread_exit(void); |
|
|
151 |
|
|
152 int get_handler_slot(cyg_handle_t current_threadH); |
|
|
153 void perform_stressful_tasks(void); |
|
|
154 void permute_array(char a[], int size, int seed); |
|
|
155 void setup_death_alarm(cyg_addrword_t data, cyg_handle_t *deathHp, |
|
|
156 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); |
|
|
159 |
|
|
160 /* we need to declare the alarm handling function (which is defined |
|
|
161 below), so that we can pass it to cyg_alarm_initialize() */ |
|
|
162 cyg_alarm_t report_alarm_func, death_alarm_func; |
|
|
163 |
|
|
164 /* handle and alarm for the report alarm */ |
|
|
165 cyg_handle_t report_alarmH, counterH, system_clockH; |
|
|
166 cyg_alarm report_alarm; |
|
|
167 |
|
|
168 /* we install our own startup routine which sets up threads */ |
|
|
169 void cyg_user_start(void) |
|
|
170 { |
|
|
171 int i; |
|
|
172 |
|
|
173 CYG_TEST_INIT(); |
|
|
174 CYG_TEST_INFO("# Entering stress's cyg_user_start() function"); |
|
|
175 |
|
|
176 cyg_mutex_init(&client_request_lock); |
|
|
177 cyg_mutex_init(&statistics_print_lock); |
|
|
178 |
|
|
179 /* initialize statistics */ |
|
|
180 memset(&statistics, 0, sizeof(statistics)); |
|
|
181 |
|
|
182 /* initialize all handler threads to not be in use */ |
|
|
183 for (i = 0; i < MAX_HANDLERS; ++i) { |
|
|
184 handler_thread_in_use[i] = 0; |
|
|
185 } |
|
|
186 for (i = 0; i < N_CLIENTS; ++i) { |
|
|
187 int prio; |
|
|
188 char thread_name[20]; |
|
|
189 sprintf(thread_name, "client-%02d", i); |
|
|
190 prio = i; |
|
|
191 sc_thread_create(prio, client_program, (cyg_addrword_t) i, |
|
|
192 thread_name, (void *) client_stack[i], STACK_SIZE, |
|
|
193 &(clientH[i]), &client_thread_s[i]); |
|
|
194 priority_in_use[prio] = 1; |
|
|
195 } |
|
|
196 for (i = 0; i < N_LISTENERS; ++i) { |
|
|
197 int prio; |
|
|
198 char thread_name[20]; |
|
|
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) { |
|
|
208 cyg_thread_resume(clientH[i]); |
|
|
209 } |
|
|
210 for (i = 0; i < N_LISTENERS; ++i) { |
|
|
211 cyg_thread_resume(listenerH[i]); |
|
|
212 } |
|
|
213 |
|
|
214 /* set up the alarm which gives periodic wakeups to say "time to |
|
|
215 print a report */ |
|
|
216 system_clockH = cyg_real_time_clock(); |
|
|
217 cyg_clock_to_counter(system_clockH, &counterH); |
|
|
218 |
|
|
219 cyg_alarm_create(counterH, report_alarm_func, |
|
|
220 (cyg_addrword_t) 4000, |
|
|
221 &report_alarmH, &report_alarm); |
|
|
222 if (cyg_test_is_simulator) { |
|
|
223 cyg_alarm_initialize(report_alarmH, cyg_current_time()+300, 400); |
|
|
224 } else { |
|
|
225 cyg_alarm_initialize(report_alarmH, cyg_current_time()+300, 4000); |
|
|
226 } |
|
|
227 |
|
|
228 } |
|
|
229 |
|
|
230 /* client_program() -- an obnoxious client which makes a lot of requests */ |
|
|
231 void client_program(cyg_addrword_t data) |
|
|
232 { |
|
|
233 int delay; |
|
|
234 |
|
|
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); |
|
|
242 |
|
|
243 system_clockH = cyg_real_time_clock(); |
|
|
244 cyg_clock_to_counter(system_clockH, &counterH); |
|
|
245 |
|
|
246 for (;;) { |
|
|
247 delay = (rand() % 3); |
|
|
248 |
|
|
249 /* now send a request to the server */ |
|
|
250 cyg_mutex_lock(&client_request_lock); { |
|
|
251 ++client_makes_request; |
|
|
252 /* printf("client_makes_request %d\n", client_makes_request); */ |
|
|
253 } cyg_mutex_unlock(&client_request_lock); |
|
|
254 |
|
|
255 cyg_thread_delay(10+delay); |
|
|
256 /* 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 } |
|
|
263 } |
|
|
264 |
|
|
265 /* listener_program() -- listens for a request and spawns a handler to |
|
|
266 take care of the request */ |
|
|
267 void listener_program(cyg_addrword_t data) |
|
|
268 { |
|
|
269 /* int message = (int) data; */ |
|
|
270 int handler_slot; |
|
|
271 |
|
|
272 printf("# Beginning execution; thread data is %d\n", (int) data); |
|
|
273 |
|
|
274 for (;;) { |
|
|
275 #ifdef DEATH_TIME_LIMIT |
|
|
276 /* as an extra task, the listener sees if all clients have been |
|
|
277 killed off, so it can report that the test is over */ |
|
|
278 if (n_clients_killed == N_CLIENTS) { |
|
|
279 n_clients_killed = -1; /* so we don't call this again */ |
|
|
280 CYG_TEST_PASS_FINISH("Kernel thread stress test OK"); |
|
|
281 } |
|
|
282 #endif /* DEATH_TIME_LIMIT */ |
|
|
283 if (client_makes_request > 0) { |
|
|
284 int prio; |
|
|
285 /* printf("just got a request from a client (count = %d)\n", */ |
|
|
286 /* client_makes_request); */ |
|
|
287 cyg_mutex_lock(&client_request_lock); { |
|
|
288 --client_makes_request; |
|
|
289 } cyg_mutex_unlock(&client_request_lock); |
|
|
290 |
|
|
291 handler_slot = get_handler_slot(listenerH[(int) data]); |
|
|
292 prio = N_CLIENTS+N_LISTENERS+handler_slot; |
|
|
293 priority_in_use[prio] = 1; |
|
|
294 sc_thread_create(prio, handler_program, |
|
|
295 (cyg_addrword_t) handler_slot, |
|
|
296 "handler", (void *) handler_stack[handler_slot], |
|
|
297 STACK_SIZE2, &handlerH[handler_slot], |
|
|
298 &handler_thread_s[handler_slot]); |
|
|
299 cyg_thread_resume(handlerH[handler_slot]); |
|
|
300 ++statistics.handler_invocation_histogram[handler_slot]; |
|
|
301 } |
|
|
302 cyg_thread_delay(1); |
|
|
303 } |
|
|
304 } |
|
|
305 |
|
|
306 /* handler_program() -- is spawned to handle each incoming request */ |
|
|
307 void handler_program(cyg_addrword_t data) |
|
|
308 { |
|
|
309 /* here is where we perform specific stressful tasks */ |
|
|
310 perform_stressful_tasks(); |
|
|
311 |
|
|
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))))); |
|
|
318 /* cyg_thread_delay(0); */ |
|
|
319 |
|
|
320 /* lock the scheduler before we declare this thread slot available |
|
|
321 and quit; note that cyg_thread_exit() will unlock the scheduler |
|
|
322 as many times as necessary */ |
|
|
323 cyg_mutex_lock(&handler_slot_lock); { |
|
|
324 handler_thread_in_use[data] = 0; |
|
|
325 priority_in_use[N_CLIENTS + N_LISTENERS + (int) data] = 0; |
|
|
326 } cyg_mutex_unlock(&handler_slot_lock); |
|
|
327 /* FIXME: could there be a race condition right here? I unlock the |
|
|
328 scheduler, so I could get pre-empted out, but meanwhile I have |
|
|
329 declared this thread available again. must fix it. */ |
|
|
330 sc_thread_exit(); |
|
|
331 } |
|
|
332 |
|
|
333 /* look for an available handler thread */ |
|
|
334 int get_handler_slot(cyg_handle_t current_threadH) |
|
|
335 { |
|
|
336 int i; |
|
|
337 int found = 0; |
|
|
338 |
|
|
339 while (!found) { |
|
|
340 for (i = 0; i < MAX_HANDLERS; ++i) { |
|
|
341 cyg_mutex_lock(&handler_slot_lock); { |
|
|
342 if (!handler_thread_in_use[i]) { |
|
|
343 found = 1; |
|
|
344 handler_thread_in_use[i] = 1; |
|
|
345 } |
|
|
346 } cyg_mutex_unlock(&handler_slot_lock); |
|
|
347 if (found) { |
|
|
348 break; |
|
|
349 } |
|
|
350 #ifdef DEATH_TIME_LIMIT |
|
|
351 /* must do a check here to see if all clients have been killed, |
|
|
352 since otherwise we might end up in an infinite loop */ |
|
|
353 if (n_clients_killed == N_CLIENTS) { |
|
|
354 n_clients_killed = -1; /* so we don't call this again */ |
|
|
355 CYG_TEST_PASS_FINISH("Kernel thread stress test OK"); |
|
|
356 } |
|
|
357 #endif |
|
|
358 } |
|
|
359 cyg_thread_delay(1); |
|
|
360 } |
|
|
361 return i; |
|
|
362 } |
|
|
363 |
|
|
364 /* do things which will stress the system */ |
|
|
365 void perform_stressful_tasks() |
|
|
366 { |
|
|
367 #define MAX_MALLOCED_SPACES 100 /* do this many mallocs at most */ |
|
|
368 #define MALLOCED_BASE_SIZE 1 /* basic size in bytes */ |
|
|
369 char *spaces[MAX_MALLOCED_SPACES]; |
|
|
370 unsigned int i; |
|
|
371 |
|
|
372 cyg_mutex_t tmp_lock; |
|
|
373 |
|
|
374 cyg_uint8 pool_space[10][100]; |
|
|
375 cyg_handle_t mempool_handles[10]; |
|
|
376 cyg_mempool_fix mempool_objects[10]; |
|
|
377 |
|
|
378 cyg_mutex_init(&tmp_lock); |
|
|
379 |
|
|
380 /* here I use malloc, which uses the kernel's variable memory pools. |
|
|
381 note that malloc/free is a bit simple-minded here: it does not |
|
|
382 try to really fragment things, and it does not try to make the |
|
|
383 allocation/deallocation concurrent with other thread execution |
|
|
384 (although I'm about to throw in a yield()) */ |
|
|
385 for (i = 0; i < MAX_MALLOCED_SPACES; ++i) { |
|
|
386 ++statistics.malloc_tries; |
|
|
387 /* 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); |
|
|
389 if (i % 100 == 0) { |
|
|
390 cyg_thread_yield(); |
|
|
391 } |
|
|
392 } |
|
|
393 |
|
|
394 /* now free it all up */ |
|
|
395 for (i = 0; i < MAX_MALLOCED_SPACES; ++i) { |
|
|
396 if (spaces[i] != NULL) { |
|
|
397 unsigned int j; |
|
|
398 for (j = 0; j < (i*2+1)*MALLOCED_BASE_SIZE; ++j) { |
|
|
399 spaces[i][j] = 0xAA; /* write a bit pattern */ |
|
|
400 } |
|
|
401 free(spaces[i]); |
|
|
402 } else { |
|
|
403 ++statistics.malloc_failures; |
|
|
404 } |
|
|
405 } |
|
|
406 /* now allocate and then free some fixed-size memory pools; for |
|
|
407 now this is simple-minded because it does not have many threads |
|
|
408 sharing the memory pools and racing for memory. */ |
|
|
409 for (i = 0; i < 10; ++i) { |
|
|
410 cyg_mempool_fix_create(pool_space[i], 100, (i+1)*3, |
|
|
411 &mempool_handles[i], &mempool_objects[i]); |
|
|
412 } |
|
|
413 |
|
|
414 for (i = 0; i < 10; ++i) { |
|
|
415 spaces[i] = cyg_mempool_fix_try_alloc(mempool_handles[i]); |
|
|
416 } |
|
|
417 |
|
|
418 for (i = 0; i < 10; ++i) { |
|
|
419 if (spaces[i]) { |
|
|
420 cyg_mempool_fix_delete(mempool_handles[i]); |
|
|
421 } |
|
|
422 } |
|
|
423 |
|
|
424 cyg_mutex_destroy(&tmp_lock); |
|
|
425 } |
|
|
426 |
|
|
427 /* 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 |
|
|
429 checked by threads. */ |
|
|
430 void report_alarm_func(cyg_handle_t alarmH, cyg_addrword_t data) |
|
|
431 { |
|
|
432 time_to_report = 1; |
|
|
433 } |
|
|
434 |
|
|
435 /* 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 */ |
|
|
437 void setup_death_alarm(cyg_addrword_t data, cyg_handle_t *deathHp, |
|
|
438 cyg_alarm *death_alarm_p, int *killed_p) |
|
|
439 { |
|
|
440 #ifdef DEATH_TIME_LIMIT |
|
|
441 cyg_handle_t system_clockH, counterH; |
|
|
442 cyg_resolution_t rtc_res; |
|
|
443 |
|
|
444 system_clockH = cyg_real_time_clock(); |
|
|
445 cyg_clock_to_counter(system_clockH, &counterH); |
|
|
446 |
|
|
447 cyg_alarm_create(counterH, death_alarm_func, |
|
|
448 (cyg_addrword_t) killed_p, |
|
|
449 deathHp, death_alarm_p); |
|
|
450 rtc_res = cyg_clock_get_resolution(system_clockH); |
|
|
451 { |
|
|
452 cyg_tick_count_t tick_delay; |
|
|
453 tick_delay = (long long) |
|
|
454 ((1000000000.0*rtc_res.divisor) |
|
|
455 *((double)DEATH_TIME_LIMIT)/((double)rtc_res.dividend)); |
|
|
456 if ( cyg_test_is_simulator ) |
|
|
457 tick_delay /= 10; |
|
|
458 cyg_alarm_initialize(*deathHp, cyg_current_time() + tick_delay, 0); |
|
|
459 } |
|
|
460 #endif /* DEATH_TIME_LIMIT */ |
|
|
461 } |
|
|
462 |
|
|
463 /* 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 |
|
|
465 thread is constantly checking. */ |
|
|
466 void death_alarm_func(cyg_handle_t alarmH, cyg_addrword_t data) |
|
|
467 { |
|
|
468 int *killed_p; |
|
|
469 killed_p = (int *) data; |
|
|
470 *killed_p = 1; |
|
|
471 } |
|
|
472 |
|
|
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 */ |
|
|
486 void sc_thread_create( |
|
|
487 cyg_addrword_t sched_info, /* scheduling info (eg pri) */ |
|
|
488 cyg_thread_entry_t *entry, /* entry point function */ |
|
|
489 cyg_addrword_t entry_data, /* entry data */ |
|
|
490 char *name, /* optional thread name */ |
|
|
491 void *stack_base, /* stack base, NULL = alloc */ |
|
|
492 cyg_ucount32 stack_size, /* stack size, 0 = default */ |
|
|
493 cyg_handle_t *handle, /* returned thread handle */ |
|
|
494 cyg_thread *thread /* put thread here */ |
|
|
495 ) |
|
|
496 { |
|
|
497 /*printf("Creating a thread -- priority is %lu\n", (unsigned long) sched_info);*/ |
|
|
498 /* fflush(stdout); */ |
|
|
499 ++statistics.thread_creations; |
|
|
500 cyg_thread_create(sched_info, entry, entry_data, name, |
|
|
501 stack_base, stack_size, handle, thread); |
|
|
502 } |
|
|
503 |
|
|
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) |
|
|
513 { |
|
|
514 int i; |
|
|
515 |
|
|
516 cyg_mutex_lock(&statistics_print_lock); { |
|
|
517 printf("Handler-invocations: "); |
|
|
518 for (i = 0; i < MAX_HANDLERS; ++i) { |
|
|
519 printf("%4lu ", statistics.handler_invocation_histogram[i]); |
|
|
520 } |
|
|
521 printf("\n"); |
|
|
522 printf("malloc()-tries/failures: -- %7lu %7lu\n", |
|
|
523 statistics.malloc_tries, statistics.malloc_failures); |
|
|
524 printf("client_makes_request: %d\n", client_makes_request); |
|
|
525 } cyg_mutex_unlock(&statistics_print_lock); |
|
|
526 } |
|
|
527 |
|
|
528 #else /* CYGSEM_LIBC_MALLOC */ |
|
|
529 # define N_A_MSG "this test needs malloc" |
|
|
530 #endif /* CYGSEM_LIBC_MALLOC */ |
|
|
531 |
|
|
532 #else /* CYGFUN_KERNEL_THREADS_TIMER */ |
|
|
533 # define N_A_MSG "this test needs kernel threads timer" |
|
|
534 #endif /* CYGFUN_KERNEL_THREADS_TIMER */ |
|
|
535 |
|
|
536 #else /* CYGPKG_LIBM */ |
|
|
537 # define N_A_MSG "this test needs libm" |
|
|
538 #endif /* CYGPKG_LIBM */ |
|
|
539 |
|
|
540 #else /* CYGSEM_LIBC_STDIO */ |
|
|
541 # define N_A_MSG "this test needs stdio" |
|
|
542 #endif /* CYGSEM_LIBC_STDIO */ |
|
|
543 |
|
|
544 #else // def CYGFUN_KERNEL_API_C |
|
|
545 # define N_A_MSG "this test needs Kernel C API" |
|
|
546 #endif |
|
|
547 |
|
|
548 #else // def CYGPKG_KERNEL && CYGPKG_IO && CYGPKG_LIBC |
|
|
549 # define N_A_MSG "this tests needs Kernel, libc and IO" |
|
|
550 #endif |
|
|
551 |
|
|
552 #ifdef N_A_MSG |
|
|
553 externC void |
|
|
554 cyg_start( void ) |
|
|
555 { |
|
|
556 CYG_TEST_INIT(); |
|
|
557 CYG_TEST_NA( N_A_MSG); |
|
|
558 } |
|
|
559 #endif // N_A_MSG |