URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [kernel/] [current/] [tests/] [thread_gdb.c] - Rev 786
Compare with Previous | Blame | View Log
//========================================================================== // // thread_gdb.c // // A test for thread support in GDB // //========================================================================== // ####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 or (at your option) any later // version. // // eCos is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License // along with eCos; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // As a special exception, if other files instantiate templates or use // macros or inline functions from this file, or you compile this file // and link it with other works to produce a work based on this file, // this file does not by itself cause the resulting work to be covered by // the GNU General Public License. However the source code for this file // must still be made available in accordance with section (3) of the GNU // General Public License v2. // // This exception does not invalidate any other reasons why a work based // on this file might be covered by the GNU General Public License. // ------------------------------------------- // ####ECOSGPLCOPYRIGHTEND#### //========================================================================== //#####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) &&\ (CYGNUM_KERNEL_SCHED_PRIORITIES > 26) #include <cyg/hal/hal_arch.h> // for CYGNUM_HAL_STACK_SIZE_TYPICAL #include CYGHWR_MEMORY_LAYOUT_H // ------------------------------------------------------------------------- #if (CYGMEM_REGION_ram_SIZE <= 32768) # define THREADS 5 #elif (CYGMEM_REGION_ram_SIZE <= 49152) # define THREADS 8 #else # define THREADS 10 #endif #ifdef CYGNUM_HAL_STACK_SIZE_TYPICAL #define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL #else #define STACKSIZE (2*1024) #endif #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 && ... */ // ------------------------------------------------------------------------- // EOF thread_gdb.c