diff packages/kernel/current/tests/thread_gdb.c @ 0:3111d98ba7b3 ecos-v1_1-release

Initial commit of eCos version 1.1
author jlarmour
date Tue, 11 May 1999 11:16:07 +0000
parents
children 443894e2e912
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/packages/kernel/current/tests/thread_gdb.c
@@ -0,0 +1,395 @@
+//==========================================================================
+//
+//        thread_gdb.c
+//
+//        A test for thread support in GDB
+//
+//==========================================================================
+//####COPYRIGHTBEGIN####
+//
+// -------------------------------------------
+// The contents of this file are subject to the Cygnus eCos Public License
+// Version 1.0 (the "License"); you may not use this file except in
+// compliance with the License.  You may obtain a copy of the License at
+// http://sourceware.cygnus.com/ecos
+// 
+// Software distributed under the License is distributed on an "AS IS"
+// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the
+// License for the specific language governing rights and limitations under
+// the License.
+// 
+// The Original Code is eCos - Embedded Cygnus Operating System, released
+// September 30, 1998.
+// 
+// The Initial Developer of the Original Code is Cygnus.  Portions created
+// by Cygnus are Copyright (C) 1998 Cygnus Solutions.  All Rights Reserved.
+// -------------------------------------------
+//
+//####COPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):     nickg
+// Contributors:  nickg
+// Date:          1998-09-21
+// Description:   GDB thread support test.
+//####DESCRIPTIONEND####
+// 
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/cyg_ass.h>
+
+#include <cyg/infra/testcase.h>
+
+#if defined(CYGFUN_KERNEL_API_C) && defined(CYGSEM_KERNEL_SCHED_MLQUEUE)
+
+// -------------------------------------------------------------------------
+
+#define THREADS                 10
+
+#define STACKSIZE               (2*1024)
+
+#define CONTROLLER_PRI_HI       0
+#define CONTROLLER_PRI_LO       25
+
+#define WORKER_PRI              3
+#define WORKER_PRI_RANGE        20
+
+
+// -------------------------------------------------------------------------
+
+// array of stacks for threads
+char thread_stack[THREADS][STACKSIZE];
+
+// array of threads.
+cyg_thread thread[THREADS];
+
+cyg_handle_t thread_handle[THREADS];
+
+volatile cyg_uint8 worker_state;
+
+#define WORKER_STATE_WAIT       1
+#define WORKER_STATE_BREAK      2
+#define WORKER_STATE_EXIT       9
+
+cyg_mutex_t worker_mutex;
+cyg_cond_t worker_cv;
+
+cyg_count32 workers_asleep = 0;
+
+cyg_count32 thread_count[THREADS];
+
+cyg_priority_t thread_pri[THREADS];
+
+
+
+// -------------------------------------------------------------------------
+
+extern void breakme(void)
+{
+}
+
+// -------------------------------------------------------------------------
+
+void worker( cyg_addrword_t id )
+{
+    for(;;)
+    {
+        thread_count[id]++;
+        thread_pri[id] = cyg_thread_get_priority( cyg_thread_self() );
+        
+        switch( worker_state )
+        {
+        case WORKER_STATE_BREAK:
+            if( 0 == (id % 4) )
+                breakme();
+            
+        case WORKER_STATE_WAIT:
+            cyg_mutex_lock( &worker_mutex );
+            workers_asleep++;
+            cyg_cond_wait( &worker_cv );
+            workers_asleep--;
+            cyg_mutex_unlock( &worker_mutex );
+            break;
+
+        case WORKER_STATE_EXIT:
+            cyg_thread_exit();
+            
+        }
+    }
+}
+
+// -------------------------------------------------------------------------
+
+void controller( cyg_addrword_t id )
+{
+    cyg_priority_t pri;
+    int i;
+
+    cyg_mutex_init( &worker_mutex );
+    cyg_cond_init( &worker_cv, &worker_mutex );
+    
+// 1 thread, it is running, it calls BREAKME();
+//  +++ Thread status returned:
+//  +++ 1 thread, running, is the current one
+    
+    breakme();
+
+// Create N more threads; they are all suspended after creation.  Adjust
+// the priorities of all the threads to lower than the controlling thread.
+// Make them all be distinct priorities as far as possible.  BREAKME();
+//  +++ 1 thread, running, + N suspended ones of different prios.
+
+    for( i = 1; i < THREADS; i++ )
+    {
+        pri = CONTROLLER_PRI_HI + 1 + i % WORKER_PRI_RANGE;
+
+        cyg_thread_create(pri, worker, (cyg_addrword_t)i, "worker",
+                          (void *)(&thread_stack[i]), STACKSIZE,
+                          &thread_handle[i], &thread[i]);
+
+    }
+
+    breakme();
+
+// Adjust the priorities of all the threads to lower than the controlling
+// thread.  Make them all be THE SAME priority.  BREAKME();
+//  +++ 1 thread, running, + N suspended ones of same prio.
+
+    for( i = 1; i < THREADS; i++ )
+    {
+        cyg_thread_set_priority( thread_handle[i], WORKER_PRI );
+    }
+
+    breakme();
+    
+// Release all the N threads, BREAKME();
+//  +++ 1 thread, running, + N ready ones of same prio.
+
+    for( i = 1; i < THREADS; i++ )
+    {
+        cyg_thread_resume( thread_handle[i] );
+    }
+
+    breakme();
+
+// Adjust the priorities of all the threads, lower than the controlling
+// thread.  Make them all be distinct priorities as far as possible.
+// BREAKME();
+//  +++ 1 thread, running, + N ready ones of different prios.
+
+    for( i = 1; i < THREADS; i++ )
+    {
+        pri = CONTROLLER_PRI_HI + 1 + i % WORKER_PRI_RANGE;
+        
+        cyg_thread_set_priority( thread_handle[i], pri );
+    }
+
+    breakme();
+    
+// Command all the N threads to sleep; switch my own priority to lower
+// than theirs so that they all run and sleep, then I get back in and
+// BREAKME();
+// +++ 1 thread, running, + N sleeping ones of different prios.
+
+    worker_state = WORKER_STATE_WAIT;
+
+    cyg_thread_set_priority( thread_handle[0], CONTROLLER_PRI_LO );
+
+    breakme();
+    
+// Make them all be THE SAME priority; BREAKME();
+//  +++ 1 thread, running, + N sleeping ones of same prio.
+
+    for( i = 1; i < THREADS; i++ )
+    {
+        cyg_thread_set_priority( thread_handle[i], WORKER_PRI );
+    }
+
+    breakme();
+
+// Wake them all up, they'll loop once and sleep again; I get in and
+// BREAKME();
+//  +++ 1 thread, running, + N sleeping ones of same prio.
+
+    cyg_cond_broadcast( &worker_cv );
+
+    breakme();
+
+// Adjust the priorities of all the threads, higher than the controlling
+// thread.  Make them all be distinct priorities as far as possible.
+// BREAKME();
+//  +++ 1 thread, running, + N sleeping ones of different prios.
+
+    for( i = 1; i < THREADS; i++ )
+    {
+        pri = CONTROLLER_PRI_HI + 1 + i % WORKER_PRI_RANGE;
+        
+        cyg_thread_set_priority( thread_handle[i], pri );
+    }
+
+    breakme();
+
+// Wake them all up, they'll loop once and sleep again; I get in and
+// BREAKME();
+//  +++ 1 thread, running, + N sleeping ones of different prios.
+
+    cyg_cond_broadcast( &worker_cv );
+
+    breakme();
+
+// Set them all the same prio, set me to the same prio, BREAKME();
+//  +++ 1 running, + N sleeping, *all* the same prio.
+
+    for( i = 0; i < THREADS; i++ )
+    {
+        cyg_thread_set_priority( thread_handle[i], WORKER_PRI );
+    }
+
+    breakme();
+
+// Wake them all up, they'll loop once and sleep again; I get in and
+// BREAKME(); repeatedly until they have all slept again.
+//  +++ 1 running, + some sleeping, some ready, *all* the same prio.
+
+    cyg_cond_broadcast( &worker_cv );
+
+//    cyg_thread_yield();
+    
+    do
+    {
+        breakme();
+        
+    } while( workers_asleep != THREADS-1 ); 
+
+    breakme();
+    
+// Suspend some of the threads, BREAKME();
+//  +++ 1 running, + some sleeping, some suspended, *all* the same prio.
+
+    for( i = 1; i < THREADS; i++ )
+    {
+        // suspend every 3rd thread
+        if( 0 == (i % 3) ) cyg_thread_suspend( thread_handle[i] );
+    }
+
+    breakme();
+
+
+// Change the prios all different, change my prio to highest , BREAKME();
+//  +++ 1 running, + some sleeping, some suspended, different prios.
+
+    cyg_thread_set_priority( thread_handle[0], CONTROLLER_PRI_HI );
+        
+    for( i = 1; i < THREADS; i++ )
+    {
+        pri = CONTROLLER_PRI_HI + 1 + i % WORKER_PRI_RANGE;
+        
+        cyg_thread_set_priority( thread_handle[i], pri );
+    }
+
+    breakme();
+    
+// Wake up all the threads, BREAKME();
+//  +++ 1 running, + some ready, some suspended/ready, different prios.
+
+    cyg_cond_broadcast( &worker_cv );
+
+    breakme();
+
+
+// Change my prio to lowest, let all the threads run, BREAKME().
+//  +++ 1 running + some sleeping, some suspended/ready, different prios.
+
+    cyg_thread_set_priority( thread_handle[0], CONTROLLER_PRI_LO );
+    
+    breakme();
+    
+// Resume all the threads, BREAKME();
+//  +++ 1 running, + N ready, different prios.
+
+    for( i = 1; i < THREADS; i++ )
+    {
+        cyg_thread_resume( thread_handle[i] );
+    }
+    
+    breakme();
+    
+// Command some of the N threads to call BREAKME(); themselves (then sleep
+// again).  Change my prio to low, so that they all get to run and hit the
+// breakpoint.
+//  +++ A different one running every time, others in a mixture of
+// 	ready and sleeping states.
+    
+    worker_state = WORKER_STATE_BREAK;
+
+    cyg_cond_broadcast( &worker_cv );
+    
+    cyg_thread_set_priority( thread_handle[0], CONTROLLER_PRI_LO );
+    
+    breakme();
+    
+// Command all the threads to exit; switch my own priority to lower
+// than theirs so that they all run and exit, then I get back in and
+// BREAKME();
+//  +++ 1 thread, running, + N dormant ones.
+
+    worker_state = WORKER_STATE_EXIT;
+
+    cyg_cond_broadcast( &worker_cv );
+    
+    breakme();
+
+#if 0
+
+// Cannot do this yet...
+    
+// Destroy some of the N threads to invalidate their IDs.  Re-create them
+// with new IDs, so that we get IDs 1,2,4,6,8,11,12,13,14,15 in use instead
+// of 1,2,3,4,5,6,7,8,9, if you see what I mean.  Do all the above again.
+// Loop forever, or whatever...
+
+#endif
+
+    breakme();
+    
+    CYG_TEST_PASS_FINISH("GDB Thread test OK");
+    
+}
+
+// -------------------------------------------------------------------------
+
+externC void
+cyg_start( void )
+{
+
+    CYG_TEST_INIT();
+    
+    cyg_thread_create(CONTROLLER_PRI_HI, controller, (cyg_addrword_t)0, "controller",
+                      (void *)(&thread_stack[0]), STACKSIZE,
+                      &thread_handle[0], &thread[0]);
+    
+    // resume it
+    cyg_thread_resume(thread_handle[0]);
+
+    
+    // Get the world going
+    cyg_scheduler_start();
+
+    CYG_TEST_FAIL_FINISH("Not reached");
+    
+}
+
+#else /* def CYGFUN_KERNEL_API_C */
+
+externC void
+cyg_start( void )
+{
+    CYG_TEST_INIT();
+    CYG_TEST_PASS_FINISH("Incorrect configuration for this test");
+}
+#endif /* def CYGFUN_KERNEL_API_C && !def CYGSEM_KERNEL_SCHED_MLQUEUE */
+
+// -------------------------------------------------------------------------
+// EOF thread_gdb.c