diff packages/kernel/current/tests/stress_threads.c @ 38:e7ba79f6d3a8 ecos-sw-1999-09-23

Merge from eCos master repository on 1999-09-23-20:10:25-BST
author jlarmour
date Thu, 23 Sep 1999 19:52:27 +0000
parents e97d78785e2d
children a3cc6665b684
line wrap: on
line diff
--- a/packages/kernel/current/tests/stress_threads.c
+++ b/packages/kernel/current/tests/stress_threads.c
@@ -165,16 +165,23 @@ volatile int free_handler_pri = 0;
 volatile int free_handler_id = -1;
 
 /* a global variable with which the client and server coordinate */
-int client_makes_request = 0;
+volatile int client_makes_request = 0;
+
+/* if this is true, clients will not make requests */
+volatile int clients_paused = 0;
+
 
 /* indicates that it's time to print out a report */
-int time_to_report = 0;
+volatile int time_to_report = 0;
 /* print status after a delay of this many secs. */
 int time_report_delay;
 
 /*** now application-specific variables ***/
 /* an array that stores whether the handler threads are in use */
-int handler_thread_in_use[MAX_HANDLERS];
+volatile int handler_thread_in_use[MAX_HANDLERS];
+/* total count of active handlers */
+volatile int handler_thread_in_use_count;
+
 
 /***** statistics-gathering variables *****/
 struct s_statistics {
@@ -204,7 +211,8 @@ void sc_thread_create(
     cyg_thread          *thread                 /* put thread here           */
     );
 
-int get_handler_slot(cyg_handle_t current_threadH);
+void start_handler(void);
+void stop_handler(int handler_id, int handler_pri);
 void perform_stressful_tasks(void);
 void permute_array(char a[], int size, int seed);
 void setup_death_alarm(cyg_addrword_t data, cyg_handle_t *deathHp,
@@ -251,6 +259,7 @@ main(void)
     for (i = 0; i < MAX_HANDLERS; ++i) {
         handler_thread_in_use[i] = 0;
     }
+    handler_thread_in_use_count = 0;
     for (i = 0; i < N_LISTENERS; ++i) {
         int prio = P_BASE_LISTENER + i;
         char* name = &thread_name[prio][0];
@@ -327,34 +336,34 @@ void main_program(cyg_addrword_t data)
         } cyg_mutex_unlock(&free_handler_lock);
 
         if (-1 != handler_id) {
-            // Free the handler resources. This is done outside of the
-            // free_handler_lock to avoid deadlocks.
-            cyg_mutex_lock(&handler_slot_lock); {
-                CYG_ASSERT(1 == priority_in_use[handler_pri], 
-                           "Priority not in use!");
-                CYG_ASSERT(1 == handler_thread_in_use[handler_id], 
-                           "Handler not in use!");
-                handler_thread_in_use[handler_id]--;
-                priority_in_use[handler_pri]--;
-
-                // Finally delete the handler thread. This must be done in a
-                // loop, waiting for the call to return true. If it returns
-                // false, go to sleep for a bit, so the killed thread gets a
-                // chance to run and complete its business.
-                while (!cyg_thread_delete(handlerH[handler_id])) {
-                    cyg_thread_delay(2);
-                }
-            } cyg_mutex_unlock(&handler_slot_lock);
+            stop_handler(handler_id, handler_pri);
         }
 
-        // Print status if time.
+        // If it's time to report status or quit, set pause flag and
+        // keep looping until all handlers have stopped.
         if (time_to_report) {
-            time_to_report = 0;
-            print_statistics(0);
+            // Pause clients
+            cyg_mutex_lock(&client_request_lock); {
+                clients_paused = 1;
+            } cyg_mutex_unlock(&client_request_lock);
+
+            // When all handlers have stopped, we can print statistics
+            // knowing that all (handler allocated) resources should have
+            // been freed. That is, we should be able to determine leaks.
+            if (0 == handler_thread_in_use_count) {
+                print_statistics(0);
+
+                // We've done the printing now. Resume the system.
+                time_to_report = 0;
+                cyg_mutex_lock(&client_request_lock); {
+                    clients_paused = 0;
+                } cyg_mutex_unlock(&client_request_lock);
+            } 
         }
 
 #ifdef DEATH_TIME_LIMIT
-        // Stop test if time.
+        // Stop test if time. We don't care about resource state here
+        // since we've only run for a limited time anyway.
         if (is_dead) {
             print_statistics(1);
             CYG_TEST_PASS_FINISH("Kernel thread stress test OK");
@@ -378,7 +387,8 @@ void client_program(cyg_addrword_t data)
 
         /* now send a request to the server */
         cyg_mutex_lock(&client_request_lock); {
-            ++client_makes_request;
+            if (0 == clients_paused)
+                client_makes_request++;
         } cyg_mutex_unlock(&client_request_lock);
 
         cyg_thread_delay(10+delay);
@@ -389,9 +399,6 @@ void client_program(cyg_addrword_t data)
    take care of the request */
 void listener_program(cyg_addrword_t data)
 {
-/*   int message = (int) data; */
-    int handler_slot;
-
     for (;;) {
         int make_request = 0;
         cyg_mutex_lock(&client_request_lock); {
@@ -401,27 +408,9 @@ void listener_program(cyg_addrword_t dat
             }
         } cyg_mutex_unlock(&client_request_lock);
         
-        if (make_request) {
-            int prio;
-            char* name;
-
-            handler_slot = get_handler_slot(listenerH[(int) data]);
-            prio = P_BASE_HANDLER+handler_slot;
-
-            name = &thread_name[prio][0];
-            sprintf(name, "handler-%02d/%02d", handler_slot, prio);
-
-            CYG_ASSERT(0 == priority_in_use[prio], "Priority already in use!");
-            priority_in_use[prio]++;
-            sc_thread_create(prio, handler_program,
-                             (cyg_addrword_t) handler_slot,
-                             name, (void *) handler_stack[handler_slot],
-                             STACK_SIZE_HANDLER, &handlerH[handler_slot],
-                             &handler_thread_s[handler_slot]);
-            cyg_thread_resume(handlerH[handler_slot]);
-            ++statistics.handler_invocation_histogram[handler_slot];
-        }
-
+        if (make_request)
+            start_handler();
+        
         cyg_thread_delay(2 + (rand() % 10));
     }
 }
@@ -434,7 +423,6 @@ void handler_program(cyg_addrword_t data
 
     cyg_thread_delay(4 + (int) (0.5*log(1.0 + fabs((rand() % 1000000)))));
 
-    ++statistics.thread_exits;
     {
         // Loop until the handler id and priority can be communicated to
         // the main_program.
@@ -456,18 +444,21 @@ void handler_program(cyg_addrword_t data
     cyg_thread_exit();
 }
 
-/* look for an available handler thread */
-int get_handler_slot(cyg_handle_t current_threadH)
+/* start a new handler */
+void start_handler(void)
 {
-    int i;
+    int prio;
+    char* name;
+    int handler_slot;
     int found = 0;
 
     while (!found) {
         cyg_mutex_lock(&handler_slot_lock); {
-            for (i = 0; i < MAX_HANDLERS; ++i) {
-                if (!handler_thread_in_use[i]) {
+            for (handler_slot = 0; handler_slot < MAX_HANDLERS;++handler_slot){
+                if (!handler_thread_in_use[handler_slot]) {
                     found = 1;
-                    handler_thread_in_use[i]++;
+                    handler_thread_in_use[handler_slot]++;
+                    handler_thread_in_use_count++;
                     break;
                 }
             }
@@ -476,27 +467,66 @@ int get_handler_slot(cyg_handle_t curren
             cyg_thread_delay(1);
     }
 
-    CYG_ASSERT(1 == handler_thread_in_use[i], "Handler usage count wrong!");
+    CYG_ASSERT(1 == handler_thread_in_use[handler_slot], 
+               "Handler usage count wrong!");
+
+    prio = P_BASE_HANDLER+handler_slot;
+    CYG_ASSERT(0 == priority_in_use[prio], "Priority already in use!");
+    priority_in_use[prio]++;
+
+    name = &thread_name[prio][0];
+    sprintf(name, "handler-%02d/%02d", handler_slot, prio);
+
+    sc_thread_create(prio, handler_program,
+                     (cyg_addrword_t) handler_slot,
+                     name, (void *) handler_stack[handler_slot],
+                     STACK_SIZE_HANDLER, &handlerH[handler_slot],
+                     &handler_thread_s[handler_slot]);
+    cyg_thread_resume(handlerH[handler_slot]);
+    ++statistics.handler_invocation_histogram[handler_slot];
+}
 
-    return i;
+/* free a locked handler thread */
+void stop_handler(int handler_id, int handler_pri)
+{
+    // Finally delete the handler thread. This must be done in a
+    // loop, waiting for the call to return true. If it returns
+    // false, go to sleep for a bit, so the killed thread gets a
+    // chance to run and complete its business.
+    while (!cyg_thread_delete(handlerH[handler_id])) {
+        cyg_thread_delay(1);
+    }
+    ++statistics.thread_exits;
+    
+    // Free the handler resources.
+    cyg_mutex_lock(&handler_slot_lock); {
+        handler_thread_in_use[handler_id]--;
+        handler_thread_in_use_count--;
+        priority_in_use[handler_pri]--;
+        CYG_ASSERT(0 == priority_in_use[handler_pri], 
+                   "Priority not in use!");
+        CYG_ASSERT(0 == handler_thread_in_use[handler_id], 
+                   "Handler not in use!");
+        CYG_ASSERT(0 <= handler_thread_in_use_count, 
+                   "Stopped more handlers than was started!");
+    } cyg_mutex_unlock(&handler_slot_lock);
+        
 }
 
+
 /* do things which will stress the system */
 void perform_stressful_tasks()
 {
 #define MAX_MALLOCED_SPACES 100  /* do this many mallocs at most */
 #define MALLOCED_BASE_SIZE 1    /* basic size in bytes */
     char *spaces[MAX_MALLOCED_SPACES];
-    unsigned int i;
-
-    cyg_mutex_t tmp_lock;
+    int  sizes[MAX_MALLOCED_SPACES];
+    unsigned int i, j, size;
 
     cyg_uint8 pool_space[10][100];
     cyg_handle_t mempool_handles[10];
     cyg_mempool_fix mempool_objects[10];
 
-    cyg_mutex_init(&tmp_lock);
-
     /* here I use malloc, which uses the kernel's variable memory pools.
        note that malloc/free is a bit simple-minded here: it does not
        try to really fragment things, and it does not try to make the
@@ -504,8 +534,17 @@ void perform_stressful_tasks()
        (although I'm about to throw in a yield()) */
     for (i = 0; i < MAX_MALLOCED_SPACES; ++i) {
         ++statistics.malloc_tries;
-/*      spaces[i] = (char *) malloc(((int)(sqrt(i*2.0))+1)*MALLOCED_BASE_SIZE); */
-        spaces[i] = (char *) malloc(((int)i*2.0+1)*MALLOCED_BASE_SIZE);
+        size = (i*2+1)*MALLOCED_BASE_SIZE;
+        spaces[i] = (char *) malloc(size);
+        sizes[i] = size;
+
+        if (spaces[i] != NULL) {
+            // Fill with a known value (differs between chunk).
+            for (j = 0; j < size; ++j) {
+                spaces[i][j] = 0x50 | ((j+i) & 0x0f);
+            }
+        }
+
         if (i % (MAX_MALLOCED_SPACES/10) == 0) {
             cyg_thread_yield();
         }
@@ -514,11 +553,17 @@ void perform_stressful_tasks()
         }
     }
 
+    cyg_thread_delay(5);
+
     /* now free it all up */
     for (i = 0; i < MAX_MALLOCED_SPACES; ++i) {
         if (spaces[i] != NULL) {
-            unsigned int j;
-            for (j = 0; j < (i*2+1)*MALLOCED_BASE_SIZE; ++j) {
+            size = sizes[i];
+            for (j = 0; j < size; ++j) {
+                // Validate chunk data.
+                if ((0x50 | ((j+i) & 0x0f)) != spaces[i][j]) {
+                    printf("Bad byte in chunk\n");
+                }
                 spaces[i][j] = 0xAA;    /* write a bit pattern */
             }
             free(spaces[i]);
@@ -526,6 +571,7 @@ void perform_stressful_tasks()
             ++statistics.malloc_failures;
         }
     }
+
     /* now allocate and then free some fixed-size memory pools; for
        now this is simple-minded because it does not have many threads
        sharing the memory pools and racing for memory. */
@@ -543,8 +589,6 @@ void perform_stressful_tasks()
             cyg_mempool_fix_delete(mempool_handles[i]);
         }
     }
-
-    cyg_mutex_destroy(&tmp_lock);
 }
 
 /* report_alarm_func() is invoked as an alarm handler, so it should be
@@ -622,7 +666,7 @@ void sc_thread_create(
 
 #define MINS_HOUR (60)
 #define MINS_DAY  (60*24)
-externC void *cyg_libc_get_pool( void );
+externC void *cyg_libc_get_malloc_pool( void );
 
 void print_statistics(int print_full)
 {
@@ -660,7 +704,8 @@ void print_statistics(int print_full)
     }
 
     printf("\nState dump %d (%d hours, %d minutes) [numbers >>%d]\n",
-           ++print_count, minutes / MINS_HOUR, minutes, shift_count);
+           ++print_count, minutes / MINS_HOUR, minutes % MINS_HOUR, 
+           shift_count);
 
     cyg_mutex_lock(&statistics_print_lock); {
         //--------------------------------
@@ -683,24 +728,18 @@ void print_statistics(int print_full)
             statistics.malloc_tries >>= 1;
             statistics.malloc_failures >>= 1;
         }
+    } cyg_mutex_unlock(&statistics_print_lock);
 
-        //--------------------------------
-        // System information
-#if 0
-        // We want to (occasionally) pause the test so all memory is
-        // freed. Otherwise it's hard to tell if there's a malloc
-        // leak.
-        {
-            cyg_mempool_info mem_info;
+    //--------------------------------
+    // System information
+    {
+        cyg_mempool_info mem_info;
 
-            cyg_mempool_var_get_info((cyg_handle_t) cyg_libc_get_pool(), 
-                                     &mem_info);
-            printf(" Memory system: Total=0x%08x Free=0x%08x Max=0x%08x\n", 
-                   mem_info.totalmem, mem_info.freemem, mem_info.maxfree);
-        }
-#endif
-
-    } cyg_mutex_unlock(&statistics_print_lock);
+        cyg_mempool_var_get_info((cyg_handle_t) cyg_libc_get_malloc_pool(), 
+                                 &mem_info);
+        printf(" Memory system: Total=0x%08x Free=0x%08x Max=0x%08x\n", 
+               mem_info.totalmem, mem_info.freemem, mem_info.maxfree);
+    }
 
     // Dump stack status
     printf(" Stack usage:\n");