]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/kernel/v2_0/tests/stress_threads.c
daedf7f54b2c59d69a68aef75fc0fa1845e6395d
[karo-tx-redboot.git] / packages / kernel / v2_0 / tests / stress_threads.c
1 //==========================================================================
2 //
3 //        stress_threads.cxx
4 //
5 //        Basic thread stress test
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):     rosalia
44 // Contributors:  rosalia, jskov
45 // Date:          1999-04-13
46 // Description:   Very simple thread stress test, with some memory
47 //                allocation and alarm handling.
48 //
49 // Notes:
50 //  If client_makes_request is big, it means that there are made many more
51 //  client requests than can be serviced. Consequently, clients are wasting
52 //  CPU time and should be sleeping more.
53 //
54 //  The list of handler invocations show how many threads are running
55 //  at the same time. The more powerful the CPU, the more the numbers
56 //  should spread out.
57 //####DESCRIPTIONEND####
58
59 #include <pkgconf/system.h>
60 #include <cyg/infra/testcase.h>
61
62 #include <cyg/hal/hal_arch.h>
63
64 #if defined(CYGPKG_KERNEL) && defined(CYGPKG_IO) && defined(CYGPKG_ISOINFRA)
65
66 #include <pkgconf/kernel.h>
67 #include <pkgconf/isoinfra.h>
68 #include CYGHWR_MEMORY_LAYOUT_H
69
70 #if defined(CYGFUN_KERNEL_API_C)
71
72 #include <cyg/kernel/kapi.h>
73
74 #ifdef CYGINT_ISO_STDIO_FORMATTED_IO
75
76 #include <stdio.h>
77 #include <stdlib.h>
78
79 #if defined(CYGPKG_LIBM)
80
81 #include <math.h>
82 #include <assert.h>
83
84 #include <cyg/kernel/test/stackmon.h>
85
86 #if defined(CYGFUN_KERNEL_THREADS_TIMER)
87 #if CYGINT_ISO_MALLOC
88
89 /* if TIME_LIMIT is defined, it represents the number of seconds this
90    test should last; if it is undefined the test will go forever */
91 #define DEATH_TIME_LIMIT 20
92 /* #undef DEATH_TIME_LIMIT */
93
94 // STACK_SIZE is typical +2kB for printf family calls which use big
95 // auto variables. Add more for handler which calls perform_stressful_tasks()
96 #define STACK_SIZE (2*1024 + CYGNUM_HAL_STACK_SIZE_TYPICAL)
97 #define STACK_SIZE_HANDLER (STACK_SIZE + 30*CYGNUM_HAL_STACK_FRAME_SIZE)
98
99 #define N_MAIN 1
100
101 // If we have instrumentation enabled, make the execution time in the
102 // simulator even shorter that we were going to anyway.
103 #ifdef CYGPKG_KERNEL_INSTRUMENT
104 #define SIM_DELAY_DIVISOR 100
105 #else
106 #define SIM_DELAY_DIVISOR 10
107 #endif
108
109 //-----------------------------------------------------------------------
110 // Some targets need to define a smaller number of handlers due to
111 // memory restrictions.
112 #if defined(CYGMEM_REGION_ram_SIZE) && (CYGMEM_REGION_ram_SIZE < 0x80000)
113 #define MAX_HANDLERS 4
114 #define N_LISTENERS 1
115 #define N_CLIENTS 1
116
117 #undef STACK_SIZE
118 #undef STACK_SIZE_HANDLER
119 #define STACK_SIZE (1024 + CYGNUM_HAL_STACK_SIZE_TYPICAL)
120 #define STACK_SIZE_HANDLER (STACK_SIZE + 10*CYGNUM_HAL_STACK_FRAME_SIZE)
121 #endif
122
123 //-----------------------------------------------------------------------
124 // If no target specific definitions, use defaults
125 #ifndef MAX_HANDLERS
126 #define MAX_HANDLERS 19
127 #define N_LISTENERS 4
128 #define N_CLIENTS 4
129 #endif
130
131 /* Allocate priorities in this order. This ensures that handlers
132    (which are the ones using the CPU) get enough CPU time to actually
133    complete their tasks. 
134
135    The empty space ensures that if libc main() thread should happen to
136    be in the priority range of the handlers, no handlers are
137    accidently reduced so much in priority to get below
138    listeners/clients. */
139
140 #define P_MAIN_PROGRAM    1
141 #define P_MAIN_PROGRAM_E  (P_MAIN_PROGRAM+N_MAIN)
142
143 #define P_BASE_HANDLER    (P_MAIN_PROGRAM_E)
144 #define P_BASE_HANDLER_E  (P_BASE_HANDLER+MAX_HANDLERS)
145
146 #define P_BASE_EMPTY      (P_BASE_HANDLER_E)
147 #define P_BASE_EMPTY_E    (P_BASE_EMPTY+2)
148
149 #define P_BASE_LISTENER   (P_BASE_EMPTY_E)
150 #define P_BASE_LISTENER_E (P_BASE_LISTENER+N_LISTENERS)
151
152 #define P_BASE_CLIENT     (P_BASE_LISTENER_E)
153 #define P_BASE_CLIENT_E   (P_BASE_CLIENT+N_CLIENTS)
154
155 #define P_MAX             (P_BASE_CLIENT_E)
156
157 /* Ensure there's room for what we request */
158 #if (CYGNUM_KERNEL_SCHED_PRIORITIES >= P_MAX)
159
160 /* if we use the bitmap scheduler we must make sure we don't use the
161    same priority more than once, so we must store those already in use */
162 static volatile char priority_in_use[P_MAX];
163
164 /* We may not get the priority we ask for (scheduler may decide to ignore
165    schedule hint). So keep a table of priorities actually assigned to
166    the threads. This information may come in handy for debugging - it's
167    not actively used by the code. */
168 static volatile int  priority_translation[P_MAX];
169
170 /* now declare (and allocate space for) some kernel objects, like the
171    threads we will use */
172 cyg_thread main_thread_s;
173 cyg_thread handler_thread_s[MAX_HANDLERS];
174 cyg_thread listener_thread_s[N_LISTENERS];
175 cyg_thread client_thread_s[N_CLIENTS];
176
177 /* space for stacks for all threads */
178 char main_stack[STACK_SIZE];
179 char handler_stack[MAX_HANDLERS][STACK_SIZE_HANDLER];
180 char listener_stack[N_LISTENERS][STACK_SIZE];
181 char client_stack[N_CLIENTS][STACK_SIZE];
182
183 /* now the handles for the threads */
184 cyg_handle_t mainH;
185 cyg_handle_t handlerH[MAX_HANDLERS];
186 cyg_handle_t listenerH[N_LISTENERS];
187 cyg_handle_t clientH[N_CLIENTS];
188
189 /* space for thread names */
190 char thread_name[P_MAX][20];
191
192 /* and now variables for the procedure which is the thread */
193 cyg_thread_entry_t main_program, client_program, listener_program, 
194     handler_program;
195
196 /* a few mutexes used in the code */
197 cyg_mutex_t client_request_lock, handler_slot_lock, statistics_print_lock, 
198     free_handler_lock;
199
200 /* global variables with which the handler IDs and thread priorities
201    to free are communicated from handlers to main_program. Access to
202    these are protected by free_handler_lock. An id of -1 means the
203    that the variables are empty. */
204 volatile int free_handler_pri = 0;
205 volatile int free_handler_id = -1;
206
207 /* a global variable with which the client and server coordinate */
208 volatile int client_makes_request = 0;
209
210 /* if this is true, clients will not make requests */
211 volatile int clients_paused = 0;
212
213
214 /* indicates that it's time to print out a report */
215 volatile int time_to_report = 0;
216 /* print status after a delay of this many secs. */
217 int time_report_delay;
218
219 /*** now application-specific variables ***/
220 /* an array that stores whether the handler threads are in use */
221 volatile int handler_thread_in_use[MAX_HANDLERS];
222 /* total count of active handlers */
223 volatile int handler_thread_in_use_count;
224
225
226 /***** statistics-gathering variables *****/
227 struct s_statistics {
228     /* store the number of times each handler has been invoked */
229     unsigned long handler_invocation_histogram[MAX_HANDLERS];
230
231     /* store how many times malloc has been attempted and how many times
232        it has failed */
233     unsigned long malloc_tries, malloc_failures;
234
235     /* how many threads have been created */
236     unsigned long thread_creations, thread_exits;
237 };
238
239 struct s_statistics statistics;
240
241 /* some function prototypes; those with the sc_ prefix are
242    "statistics-collecting" versions of the cyg_ primitives */
243 cyg_addrword_t sc_thread_create(
244     cyg_addrword_t      sched_info,             /* scheduling info (eg pri)  */
245     cyg_thread_entry_t  *entry,                 /* entry point function      */
246     cyg_addrword_t      entry_data,             /* entry data                */
247     char                *name,                  /* optional thread name      */
248     void                *stack_base,            /* stack base, NULL = alloc  */
249     cyg_ucount32        stack_size,             /* stack size, 0 = default   */
250     cyg_handle_t        *handle,                /* returned thread handle    */
251     cyg_thread          *thread                 /* put thread here           */
252     );
253
254 void start_handler(void);
255 void stop_handler(int handler_id, int handler_pri);
256 void perform_stressful_tasks(void);
257 void permute_array(char a[], int size, int seed);
258 void setup_death_alarm(cyg_addrword_t data, cyg_handle_t *deathHp,
259                        cyg_alarm *death_alarm_p, int *killed_p);
260 void print_statistics(int print_full);
261
262 /* we need to declare the alarm handling function (which is defined
263    below), so that we can pass it to cyg_alarm_initialize() */
264 cyg_alarm_t report_alarm_func, death_alarm_func;
265
266 /* handle and alarm for the report alarm */
267 cyg_handle_t report_alarmH, counterH, system_clockH;
268 cyg_alarm report_alarm;
269
270 /* main launches all the threads of the test */
271 int
272 main(void)
273 {
274     int i;
275
276     CYG_TEST_INIT();
277     CYG_TEST_INFO("Stress threads test compiled on " __DATE__);
278
279     cyg_mutex_init(&client_request_lock);
280     cyg_mutex_init(&statistics_print_lock);
281     cyg_mutex_init(&free_handler_lock);
282
283     /* initialize statistics */
284     memset(&statistics, 0, sizeof(statistics));
285
286     /* clear priority table */
287     for (i = 0; i < sizeof(priority_in_use); i++)
288         priority_in_use[i] = 0;
289
290     /* initialize main thread */
291     {
292         priority_translation[P_MAIN_PROGRAM] =
293             sc_thread_create(P_MAIN_PROGRAM, main_program, (cyg_addrword_t) 0,
294                              "main_program", (void *) main_stack, STACK_SIZE,
295                              &mainH, &main_thread_s);
296         priority_in_use[P_MAIN_PROGRAM]++;
297     }
298
299     /* initialize all handler threads to not be in use */
300     for (i = 0; i < MAX_HANDLERS; ++i) {
301         handler_thread_in_use[i] = 0;
302     }
303     handler_thread_in_use_count = 0;
304     for (i = 0; i < N_LISTENERS; ++i) {
305         int prio = P_BASE_LISTENER + i;
306         char* name = &thread_name[prio][0];
307         sprintf(name, "listener-%02d", i);
308         priority_translation[prio] =
309             sc_thread_create(prio, listener_program, (cyg_addrword_t) i,
310                              name, (void *) listener_stack[i], STACK_SIZE,
311                              &listenerH[i], &listener_thread_s[i]);
312         CYG_ASSERT(0 == priority_in_use[prio], "Priority already in use!");
313         priority_in_use[prio]++;
314     }
315     for (i = 0; i < N_CLIENTS; ++i) {
316         int prio = P_BASE_CLIENT + i;
317         char* name = &thread_name[prio][0];
318         sprintf(name, "client-%02d", i);
319         priority_translation[prio] =
320             sc_thread_create(prio, client_program, (cyg_addrword_t) i,
321                              name, (void *) client_stack[i], STACK_SIZE,
322                              &(clientH[i]), &client_thread_s[i]);
323         CYG_ASSERT(0 == priority_in_use[prio], "Priority already in use!");
324         priority_in_use[prio]++;
325     }
326
327     cyg_thread_resume(mainH);
328     for (i = 0; i < N_CLIENTS; ++i) {
329         cyg_thread_resume(clientH[i]);
330     }
331     for (i = 0; i < N_LISTENERS; ++i) {
332         cyg_thread_resume(listenerH[i]);
333     }
334
335     /* set up the alarm which gives periodic wakeups to say "time to
336        print a report */
337     system_clockH = cyg_real_time_clock();
338     cyg_clock_to_counter(system_clockH, &counterH);
339
340     cyg_alarm_create(counterH, report_alarm_func,
341                      (cyg_addrword_t) 4000,
342                      &report_alarmH, &report_alarm);
343     if (cyg_test_is_simulator) {
344         time_report_delay = 2;
345     } else {
346         time_report_delay = 60;
347     }
348
349     cyg_alarm_initialize(report_alarmH, cyg_current_time()+200, 
350                          time_report_delay*100);
351
352     return 0;
353 }
354
355 /* main_program() -- frees resources and prints status. */
356 void main_program(cyg_addrword_t data)
357 {
358 #ifdef DEATH_TIME_LIMIT
359     cyg_handle_t deathH;
360     cyg_alarm death_alarm;
361     int is_dead = 0;
362
363     setup_death_alarm(0, &deathH, &death_alarm, &is_dead);
364 #endif /* DEATH_TIME_LIMIT */
365
366     for (;;) {
367         int handler_id = -1;
368         int handler_pri = 0;
369
370         cyg_mutex_lock(&free_handler_lock); {
371             // If any handler has left its ID, copy the ID and
372             // priority values to local variables, and free up the
373             // global communication variables again.
374             if (-1 != free_handler_id) {
375                 handler_id = free_handler_id;
376                 handler_pri = free_handler_pri;
377                 free_handler_id = -1;
378             }
379         } cyg_mutex_unlock(&free_handler_lock);
380
381         if (-1 != handler_id) {
382             stop_handler(handler_id, handler_pri);
383         }
384
385         // If it's time to report status or quit, set pause flag and
386         // keep looping until all handlers have stopped.
387         if (time_to_report) {
388             // Pause clients
389             cyg_mutex_lock(&client_request_lock); {
390                 clients_paused = 1;
391             } cyg_mutex_unlock(&client_request_lock);
392
393             // When all handlers have stopped, we can print statistics
394             // knowing that all (handler allocated) resources should have
395             // been freed. That is, we should be able to determine leaks.
396             if (0 == handler_thread_in_use_count) {
397                 print_statistics(0);
398
399                 // We've done the printing now. Resume the system.
400                 time_to_report = 0;
401                 cyg_mutex_lock(&client_request_lock); {
402                     clients_paused = 0;
403                 } cyg_mutex_unlock(&client_request_lock);
404             } 
405         }
406
407 #ifdef DEATH_TIME_LIMIT
408         // Stop test if time.
409         if (is_dead) {
410             // Pause clients
411             cyg_mutex_lock(&client_request_lock); {
412                 clients_paused = 1;
413             } cyg_mutex_unlock(&client_request_lock);
414
415             // When all handlers have stopped, we can print statistics
416             // knowing that all (handler allocated) resources should have
417             // been freed. That is, we should be able to determine leaks.
418             if (0 == handler_thread_in_use_count) {
419                 print_statistics(1);
420                 CYG_TEST_PASS_FINISH("Kernel thread stress test OK");
421             }
422         }
423 #endif /* DEATH_TIME_LIMIT */
424
425         cyg_thread_delay(3);
426     }
427 }
428
429 /* client_program() -- an obnoxious client which makes a lot of requests */
430 void client_program(cyg_addrword_t data)
431 {
432     int delay;
433
434     system_clockH = cyg_real_time_clock();
435     cyg_clock_to_counter(system_clockH, &counterH);
436
437     for (;;) {
438         delay = (rand() % 20);
439
440         /* now send a request to the server */
441         cyg_mutex_lock(&client_request_lock); {
442             if (0 == clients_paused)
443                 client_makes_request++;
444         } cyg_mutex_unlock(&client_request_lock);
445
446         cyg_thread_delay(10+delay);
447     }
448 }
449
450 /* listener_program() -- listens for a request and spawns a handler to
451    take care of the request */
452 void listener_program(cyg_addrword_t data)
453 {
454     for (;;) {
455         int make_request = 0;
456         cyg_mutex_lock(&client_request_lock); {
457             if (client_makes_request > 0) {
458                 --client_makes_request;
459                 make_request = 1;
460             }
461         } cyg_mutex_unlock(&client_request_lock);
462         
463         if (make_request)
464             start_handler();
465         
466         cyg_thread_delay(2 + (rand() % 10));
467     }
468 }
469
470 /* handler_program() -- is spawned to handle each incoming request */
471 void handler_program(cyg_addrword_t data)
472 {
473     /* here is where we perform specific stressful tasks */
474     perform_stressful_tasks();
475
476     cyg_thread_delay(4 + (int) (0.5*log(1.0 + fabs((rand() % 1000000)))));
477
478     {
479         // Loop until the handler id and priority can be communicated to
480         // the main_program.
481         int freed = 0;
482         do {
483             cyg_mutex_lock(&free_handler_lock); {
484                 if (-1 == free_handler_id) {
485                     free_handler_id = data;
486                     free_handler_pri = P_BASE_HANDLER+(int) data;
487                     freed = 1;
488                 }
489             } cyg_mutex_unlock(&free_handler_lock);
490             if (!freed)
491                 cyg_thread_delay(2);
492         } while (!freed);
493     }
494
495     // Then exit.
496     cyg_thread_exit();
497 }
498
499 /* start a new handler */
500 void start_handler(void)
501 {
502     int prio;
503     char* name;
504     int handler_slot = 0;
505     int found = 0;
506
507     while (!found) {
508         cyg_mutex_lock(&handler_slot_lock); {
509             for (handler_slot = 0; handler_slot < MAX_HANDLERS;++handler_slot){
510                 if (!handler_thread_in_use[handler_slot]) {
511                     found = 1;
512                     handler_thread_in_use[handler_slot]++;
513                     handler_thread_in_use_count++;
514                     break;
515                 }
516             }
517         } cyg_mutex_unlock(&handler_slot_lock);
518         if (!found)
519             cyg_thread_delay(1);
520     }
521
522     CYG_ASSERT(1 == handler_thread_in_use[handler_slot], 
523                "Handler usage count wrong!");
524
525     prio = P_BASE_HANDLER+handler_slot;
526     CYG_ASSERT(0 == priority_in_use[prio], "Priority already in use!");
527     priority_in_use[prio]++;
528
529     name = &thread_name[prio][0];
530     sprintf(name, "handler-%02d/%02d", handler_slot, prio);
531
532     priority_translation[prio] =
533         sc_thread_create(prio, handler_program,
534                          (cyg_addrword_t) handler_slot,
535                          name, (void *) handler_stack[handler_slot],
536                          STACK_SIZE_HANDLER, &handlerH[handler_slot],
537                          &handler_thread_s[handler_slot]);
538     cyg_thread_resume(handlerH[handler_slot]);
539     ++statistics.handler_invocation_histogram[handler_slot];
540 }
541
542 /* free a locked handler thread */
543 void stop_handler(int handler_id, int handler_pri)
544 {
545     // Finally delete the handler thread. This must be done in a
546     // loop, waiting for the call to return true. If it returns
547     // false, go to sleep for a bit, so the killed thread gets a
548     // chance to run and complete its business.
549     while (!cyg_thread_delete(handlerH[handler_id])) {
550         cyg_thread_delay(1);
551     }
552     ++statistics.thread_exits;
553     
554     // Free the handler resources.
555     cyg_mutex_lock(&handler_slot_lock); {
556         handler_thread_in_use[handler_id]--;
557         handler_thread_in_use_count--;
558         priority_in_use[handler_pri]--;
559         CYG_ASSERT(0 == priority_in_use[handler_pri], 
560                    "Priority not in use!");
561         CYG_ASSERT(0 == handler_thread_in_use[handler_id], 
562                    "Handler not in use!");
563         CYG_ASSERT(0 <= handler_thread_in_use_count, 
564                    "Stopped more handlers than was started!");
565     } cyg_mutex_unlock(&handler_slot_lock);
566         
567 }
568
569
570 /* do things which will stress the system */
571 void perform_stressful_tasks()
572 {
573 #define MAX_MALLOCED_SPACES 100  /* do this many mallocs at most */
574 #define MALLOCED_BASE_SIZE 1    /* basic size in bytes */
575     char *spaces[MAX_MALLOCED_SPACES];
576     int  sizes[MAX_MALLOCED_SPACES];
577     unsigned int i, j, size;
578
579     cyg_uint8 pool_space[10][100];
580     cyg_handle_t mempool_handles[10];
581     cyg_mempool_fix mempool_objects[10];
582
583     /* here I use malloc, which uses the kernel's variable memory pools.
584        note that malloc/free is a bit simple-minded here: it does not
585        try to really fragment things, and it does not try to make the
586        allocation/deallocation concurrent with other thread execution
587        (although I'm about to throw in a yield()) */
588     for (i = 0; i < MAX_MALLOCED_SPACES; ++i) {
589         ++statistics.malloc_tries;
590         size = (i*2+1)*MALLOCED_BASE_SIZE;
591         spaces[i] = (char *) malloc(size);
592         sizes[i] = size;
593
594         if (spaces[i] != NULL) {
595             // Fill with a known value (differs between chunk).
596             for (j = 0; j < size; ++j) {
597                 spaces[i][j] = 0x50 | ((j+i) & 0x0f);
598             }
599         }
600
601         if (i % (MAX_MALLOCED_SPACES/10) == 0) {
602             cyg_thread_yield();
603         }
604         if (i % (MAX_MALLOCED_SPACES/15) == 0) {
605             cyg_thread_delay(i % 5);
606         }
607     }
608
609     cyg_thread_delay(5);
610
611     /* now free it all up */
612     for (i = 0; i < MAX_MALLOCED_SPACES; ++i) {
613         if (spaces[i] != NULL) {
614             size = sizes[i];
615             for (j = 0; j < size; ++j) {
616                 // Validate chunk data.
617                 if ((0x50 | ((j+i) & 0x0f)) != spaces[i][j]) {
618                     printf("Bad byte in chunk\n");
619                 }
620                 spaces[i][j] = 0xAA;    /* write a bit pattern */
621             }
622             free(spaces[i]);
623         } else {
624             ++statistics.malloc_failures;
625         }
626     }
627
628     /* now allocate and then free some fixed-size memory pools; for
629        now this is simple-minded because it does not have many threads
630        sharing the memory pools and racing for memory. */
631     for (i = 0; i < 10; ++i) {
632         cyg_mempool_fix_create(pool_space[i], 100, (i+1)*3,
633                                &mempool_handles[i], &mempool_objects[i]);
634     }
635
636     for (i = 0; i < 10; ++i) {
637         spaces[i] = cyg_mempool_fix_try_alloc(mempool_handles[i]);
638     }
639
640     for (i = 0; i < 10; ++i) {
641         if (spaces[i]) {
642             cyg_mempool_fix_delete(mempool_handles[i]);
643         }
644     }
645 }
646
647 /* report_alarm_func() is invoked as an alarm handler, so it should be
648    quick and simple.  in this case it sets a global flag which is
649    checked by main_program. */
650 void report_alarm_func(cyg_handle_t alarmH, cyg_addrword_t data)
651 {
652     time_to_report = 1;
653 }
654
655 #ifdef DEATH_TIME_LIMIT
656 /* this sets up death alarms. it gets the handle and alarm from the
657    caller, since they must persist for the life of the alarm */
658 void setup_death_alarm(cyg_addrword_t data, cyg_handle_t *deathHp,
659                        cyg_alarm *death_alarm_p, int *killed_p)
660 {
661     cyg_handle_t system_clockH, counterH;
662     cyg_resolution_t rtc_res;
663
664     system_clockH = cyg_real_time_clock();
665     cyg_clock_to_counter(system_clockH, &counterH);
666
667     cyg_alarm_create(counterH, death_alarm_func,
668                      (cyg_addrword_t) killed_p,
669                      deathHp, death_alarm_p);
670     rtc_res = cyg_clock_get_resolution(system_clockH);
671     {
672         cyg_tick_count_t tick_delay;
673         tick_delay = (long long)
674             ((1000000000.0*rtc_res.divisor)
675              *((double)DEATH_TIME_LIMIT)/((double)rtc_res.dividend));
676         if ( cyg_test_is_simulator )
677             tick_delay /= SIM_DELAY_DIVISOR;
678 #ifdef CYGPKG_HAL_SYNTH
679         // 20 seconds is a long time compared to the run time of other tests.
680         // Reduce to 10 seconds, allowing more tests to get run.
681         tick_delay /= 2;
682 #endif
683
684         cyg_alarm_initialize(*deathHp, cyg_current_time() + tick_delay, 0);
685     }
686 }
687 #endif
688
689 /* death_alarm_func() is the alarm handler that kills the current
690    thread after a specified timeout. It does so by setting a flag the
691    thread is constantly checking. */
692 void death_alarm_func(cyg_handle_t alarmH, cyg_addrword_t data)
693 {
694     int *killed_p;
695     killed_p = (int *) data;
696     *killed_p = 1;
697 }
698
699 /* now I write the sc_ versions of the cyg_functions */
700 cyg_addrword_t sc_thread_create(
701     cyg_addrword_t      sched_info,            /* scheduling info (eg pri)  */
702     cyg_thread_entry_t  *entry,                /* entry point function      */
703     cyg_addrword_t      entry_data,            /* entry data                */
704     char                *name,                 /* optional thread name      */
705     void                *stack_base,           /* stack base, NULL = alloc  */
706     cyg_ucount32        stack_size,            /* stack size, 0 = default   */
707     cyg_handle_t        *handle,               /* returned thread handle    */
708     cyg_thread          *thread                /* put thread here           */
709     )
710 {
711     ++statistics.thread_creations;
712
713     cyg_thread_create(sched_info, entry, entry_data, name,
714                       stack_base, stack_size, handle, thread);
715
716     return cyg_thread_get_priority(*handle);
717 }
718
719
720 #define MINS_HOUR (60)
721 #define MINS_DAY  (60*24)
722
723 void print_statistics(int print_full)
724 {
725     int i;
726     static int stat_dumps = 0;
727     static int print_count = 0;
728     static int shift_count = 0;
729     int minutes;
730
731     stat_dumps++;
732
733     // Find number of minutes.
734     minutes = time_report_delay*stat_dumps / 60;
735
736     if (!print_full) {
737         // Return if time/minutes not integer.
738         if ((time_report_delay*stat_dumps % 60) != 0)
739             return;
740
741         // After the first day, only dump stat once per day. Do print
742         // a . on the hour though.
743         if ((minutes > MINS_DAY) && ((minutes % MINS_DAY) != 0)) {
744             if ((minutes % MINS_HOUR) == 0) {
745                 printf(".");
746                 fflush(stdout);
747             }
748             return;
749         }
750
751         // After the first hour of the first day, only dump stat once
752         // per hour. Do print . each minute though.
753         if ((minutes < MINS_DAY) && (minutes > MINS_HOUR)
754             && ((minutes % MINS_HOUR) != 0)) {
755             printf(".");
756             fflush(stdout);
757             return;
758         }
759     }
760
761     printf("\nState dump %d (%d hours, %d minutes) [numbers >>%d]\n",
762            ++print_count, minutes / MINS_HOUR, minutes % MINS_HOUR, 
763            shift_count);
764
765     cyg_mutex_lock(&statistics_print_lock); {
766         //--------------------------------
767         // Information private to this test:
768         printf(" Handler-invocations: ");
769         for (i = 0; i < MAX_HANDLERS; ++i) {
770             printf("%4lu ", statistics.handler_invocation_histogram[i]);
771         }
772         printf("\n");
773         printf(" malloc()-tries/failures: -- %7lu %7lu\n",
774                statistics.malloc_tries, statistics.malloc_failures);
775         printf(" client_makes_request:       %d\n", client_makes_request);
776
777         // Check for big numbers and reduce if getting close to overflow
778         if (statistics.malloc_tries > 0x40000000) {
779             shift_count++;
780             for (i = 0; i < MAX_HANDLERS; ++i) {
781                 statistics.handler_invocation_histogram[i] >>= 1;
782             }
783             statistics.malloc_tries >>= 1;
784             statistics.malloc_failures >>= 1;
785         }
786     } cyg_mutex_unlock(&statistics_print_lock);
787
788 #if CYGINT_ISO_MALLINFO
789     //--------------------------------
790     // System information
791     {
792         struct mallinfo mem_info;
793        
794         mem_info = mallinfo();
795         
796         printf(" Memory system: Total=0x%08x Free=0x%08x Max=0x%08x\n", 
797                mem_info.arena, mem_info.fordblks, mem_info.maxfree);
798     }
799 #endif
800
801     // Dump stack status
802     printf(" Stack usage:\n");
803     cyg_test_dump_interrupt_stack_stats( "  Interrupt" );
804     cyg_test_dump_idlethread_stack_stats( "  Idle" );
805
806     cyg_test_dump_stack_stats("  Main", main_stack, 
807                               main_stack + sizeof(main_stack));
808     for (i = 0; i < MAX_HANDLERS; i++) {
809         cyg_test_dump_stack_stats("  Handler", handler_stack[i], 
810                                   handler_stack[i] + sizeof(handler_stack[i]));
811     }
812     for (i = 0; i < N_LISTENERS; i++) {
813         cyg_test_dump_stack_stats("  Listener", listener_stack[i], 
814                                   listener_stack[i] + sizeof(listener_stack[i]));
815     }
816     for (i = 0; i < N_CLIENTS; i++) {
817         cyg_test_dump_stack_stats("  Client", client_stack[i], 
818                                   client_stack[i] + sizeof(client_stack[i]));
819     }
820 }
821
822 #else /* (CYGNUM_KERNEL_SCHED_PRIORITIES >=    */
823 /* (N_MAIN+N_CLIENTS+N_LISTENERS+MAX_HANDLERS)) */
824 #define N_A_MSG "not enough priorities available"
825 #endif /* (CYGNUM_KERNEL_SCHED_PRIORITIES >=    */
826 /* (N_MAIN+N_CLIENTS+N_LISTENERS+MAX_HANDLERS)) */
827
828 #else /* CYGINT_ISO_MALLOC */
829 # define N_A_MSG "this test needs malloc"
830 #endif /* CYGINT_ISO_MALLOC */
831
832 #else /* CYGFUN_KERNEL_THREADS_TIMER */
833 # define N_A_MSG "this test needs kernel threads timer"
834 #endif /* CYGFUN_KERNEL_THREADS_TIMER */
835
836 #else /* CYGPKG_LIBM */
837 # define N_A_MSG "this test needs libm"
838 #endif /* CYGPKG_LIBM */
839
840 #else /* CYGINT_ISO_STDIO_FORMATTED_IO */
841 # define N_A_MSG "this test needs stdio formatted I/O"
842 #endif /* CYGINT_ISO_STDIO_FORMATTED_IO */
843
844 #else // def CYGFUN_KERNEL_API_C
845 # define N_A_MSG "this test needs Kernel C API"
846 #endif
847
848 #else // def CYGPKG_KERNEL && CYGPKG_IO && CYGPKG_ISOINFRA
849 # define N_A_MSG "this tests needs Kernel, isoinfra and IO"
850 #endif
851
852 #ifdef N_A_MSG
853 externC void
854 cyg_start( void )
855 {
856     CYG_TEST_INIT();
857     CYG_TEST_NA( N_A_MSG);
858 }
859 #endif // N_A_MSG