URL
https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk
Subversion Repositories openrisc_me
Compare Revisions
- This comparison shows the changes necessary to convert path
/openrisc/trunk/rtos/ecos-2.0/packages/kernel/v2_0/tests
- from Rev 27 to Rev 174
- ↔ Reverse comparison
Rev 27 → Rev 174
/kmutex1.c
0,0 → 1,188
/*================================================================= |
// |
// kmutex1.c |
// |
// Kernel C API Mutex test 1 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-03-23 |
// Description: Tests basic mutex functionality. |
// Omissions: Timed wait. |
//####DESCRIPTIONEND#### |
*/ |
|
#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
#include <cyg/kernel/kapi.h> |
|
#include <cyg/infra/testcase.h> |
|
#ifdef CYGFUN_KERNEL_API_C |
|
#include "testaux.h" |
|
#define NTHREADS 3 |
#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
static cyg_handle_t thread[NTHREADS]; |
|
static cyg_thread thread_obj[NTHREADS]; |
static char stack[NTHREADS][STACKSIZE]; |
|
|
static cyg_mutex_t m0, m1; |
static cyg_cond_t cvar0, cvar1, cvar2; |
|
static cyg_ucount8 m0d=0, m1d=0; |
|
static void finish( cyg_ucount8 t ) |
{ |
cyg_mutex_lock( &m1 ); { |
m1d |= 1<<t; |
if( 0x7 == m1d ) |
CYG_TEST_PASS_FINISH("Kernel C API Mutex 1 OK"); |
cyg_cond_wait( &cvar2 ); |
} /* cyg_mutex_unlock( &m1 ); */ |
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
static void entry0( cyg_addrword_t data ) |
{ |
cyg_mutex_lock( &m0 ); { |
CHECK( ! cyg_mutex_trylock( &m0 ) ); |
cyg_mutex_lock( &m1 ); { |
CHECK( ! cyg_mutex_trylock( &m0 ) ); |
} cyg_mutex_unlock( &m1 ); |
} cyg_mutex_unlock( &m0 ); |
|
cyg_mutex_lock( &m0 ); { |
while ( 0 == m0d ) |
cyg_cond_wait( &cvar0 ); |
CHECK( 1 == m0d++ ); |
cyg_cond_signal( &cvar0 ); |
while ( 4 != m0d ) |
cyg_cond_wait( &cvar1 ); |
CHECK( 4 == m0d ); |
} cyg_mutex_unlock( &m0 ); |
|
finish( (cyg_ucount8)data ); |
} |
|
static void entry1( cyg_addrword_t data ) |
{ |
cyg_mutex_lock( &m0 ); { |
CHECK( cyg_mutex_trylock( &m1 ) ); { |
} cyg_mutex_unlock( &m1 ); |
} cyg_mutex_unlock( &m0 ); |
|
cyg_mutex_lock( &m0 ); { |
CHECK( 0 == m0d++ ); |
cyg_cond_broadcast( &cvar0 ); |
} cyg_mutex_unlock( &m0 ); |
|
cyg_mutex_lock( &m0 ); { |
while( 1 == m0d ) |
cyg_cond_wait( &cvar0 ); |
CHECK( 2 == m0d++ ); |
cyg_cond_signal( &cvar0 ); |
while( 3 == m0d ) |
cyg_cond_wait( &cvar1 ); |
} cyg_mutex_unlock( &m0 ); |
|
finish( (cyg_ucount8)data ); |
} |
|
static void entry2( cyg_addrword_t data ) |
{ |
cyg_mutex_lock( &m0 ); { |
while( 3 != m0d ) { |
cyg_cond_wait( &cvar0 ); |
} |
CHECK( 3 == m0d++ ); |
cyg_cond_broadcast( &cvar1 ); |
} cyg_mutex_unlock( &m0 ); |
|
finish( (cyg_ucount8)data ); |
} |
|
void kmutex1_main( void ) |
{ |
CYG_TEST_INIT(); |
|
cyg_thread_create(4, entry0 , (cyg_addrword_t)0, "kmutex1-0", |
(void *)stack[0], STACKSIZE, &thread[0], &thread_obj[0]); |
cyg_thread_resume(thread[0]); |
|
cyg_thread_create(4, entry1 , (cyg_addrword_t)1, "kmutex1-1", |
(void *)stack[1], STACKSIZE, &thread[1], &thread_obj[1]); |
cyg_thread_resume(thread[1]); |
|
cyg_thread_create(4, entry2 , (cyg_addrword_t)2, "kmutex1-2", |
(void *)stack[2], STACKSIZE, &thread[2], &thread_obj[2]); |
cyg_thread_resume(thread[2]); |
|
cyg_mutex_init( &m0 ); |
cyg_mutex_init( &m1 ); |
|
cyg_cond_init( &cvar0, &m0 ); |
cyg_cond_init( &cvar1, &m0 ); |
cyg_cond_init( &cvar2, &m1 ); |
|
cyg_scheduler_start(); |
|
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
externC void |
cyg_start( void ) |
{ |
kmutex1_main(); |
} |
|
#else /* def CYGFUN_KERNEL_API_C */ |
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA("Kernel C API layer disabled"); |
} |
#endif /* def CYGFUN_KERNEL_API_C */ |
|
/* EOF kmutex1.c */ |
/kcache1.c
0,0 → 1,422
/*================================================================= |
// |
// kcache1.c |
// |
// Cache timing test |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm, nickg |
// Date: 1998-06-18 |
//####DESCRIPTIONEND#### |
*/ |
|
#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
#include <cyg/kernel/kapi.h> |
|
#include <cyg/infra/testcase.h> |
|
#include <cyg/hal/hal_cache.h> |
|
#if defined(HAL_DCACHE_SIZE) || defined(HAL_UCACHE_SIZE) |
#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK |
#ifdef CYGFUN_KERNEL_API_C |
|
#include <cyg/infra/diag.h> |
#include <cyg/hal/hal_intr.h> |
|
// ------------------------------------------------------------------------- |
// If the HAL does not supply this, we supply our own version |
|
#ifndef HAL_DCACHE_PURGE_ALL |
# ifdef HAL_DCACHE_SYNC |
|
#define HAL_DCACHE_PURGE_ALL() HAL_DCACHE_SYNC() |
|
# else |
|
static cyg_uint8 dca[HAL_DCACHE_SIZE + HAL_DCACHE_LINE_SIZE*2]; |
|
#define HAL_DCACHE_PURGE_ALL() \ |
CYG_MACRO_START \ |
volatile cyg_uint8 *addr = &dca[HAL_DCACHE_LINE_SIZE]; \ |
volatile cyg_uint8 tmp = 0; \ |
int i; \ |
for( i = 0; i < HAL_DCACHE_SIZE; i += HAL_DCACHE_LINE_SIZE ) \ |
{ \ |
tmp = addr[i]; \ |
} \ |
CYG_MACRO_END |
|
# endif |
#endif |
|
// ------------------------------------------------------------------------- |
|
#define NTHREADS 1 |
#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
static cyg_handle_t thread[NTHREADS]; |
|
static cyg_thread thread_obj[NTHREADS]; |
static char stack[NTHREADS][STACKSIZE]; |
|
#ifndef MAX_STRIDE |
#define MAX_STRIDE 64 |
#endif |
|
volatile char m[(HAL_DCACHE_SIZE/HAL_DCACHE_LINE_SIZE)*MAX_STRIDE]; |
|
// ------------------------------------------------------------------------- |
|
static void time0(register cyg_uint32 stride) |
{ |
register cyg_uint32 j,k; |
cyg_tick_count_t count0, count1; |
cyg_ucount32 t; |
register char c; |
|
count0 = cyg_current_time(); |
|
k = 0; |
if ( cyg_test_is_simulator ) |
k = 3960; |
|
for(; k<4000;k++) { |
for(j=0; j<(HAL_DCACHE_SIZE/HAL_DCACHE_LINE_SIZE); j++) { |
c=m[stride*j]; |
} |
} |
|
count1 = cyg_current_time(); |
t = count1 - count0; |
diag_printf("stride=%d, time=%d\n", stride, t); |
} |
|
// ------------------------------------------------------------------------- |
|
void time1(void) |
{ |
cyg_uint32 i; |
|
for(i=1; i<=MAX_STRIDE; i+=i) { |
time0(i); |
} |
} |
|
// ------------------------------------------------------------------------- |
// With an ICache invalidate in the middle: |
#ifdef HAL_ICACHE_INVALIDATE_ALL |
static void time0II(register cyg_uint32 stride) |
{ |
register cyg_uint32 j,k; |
cyg_tick_count_t count0, count1; |
cyg_ucount32 t; |
register char c; |
|
count0 = cyg_current_time(); |
|
k = 0; |
if ( cyg_test_is_simulator ) |
k = 3960; |
|
for(; k<4000;k++) { |
for(j=0; j<(HAL_DCACHE_SIZE/HAL_DCACHE_LINE_SIZE); j++) { |
HAL_ICACHE_INVALIDATE_ALL(); |
c=m[stride*j]; |
} |
} |
|
count1 = cyg_current_time(); |
t = count1 - count0; |
diag_printf("stride=%d, time=%d\n", stride, t); |
} |
|
// ------------------------------------------------------------------------- |
|
void time1II(void) |
{ |
cyg_uint32 i; |
|
for(i=1; i<=MAX_STRIDE; i+=i) { |
time0II(i); |
} |
} |
#endif |
// ------------------------------------------------------------------------- |
// With a DCache invalidate in the middle: |
// This is guaranteed to produce bogus timing results since interrupts |
// have to be disabled to prevent accidental loss of state. |
#ifdef HAL_DCACHE_INVALIDATE_ALL |
static void time0DI(register cyg_uint32 stride) |
{ |
register cyg_uint32 j,k; |
volatile cyg_tick_count_t count0; |
cyg_tick_count_t count1; |
cyg_ucount32 t; |
register char c; |
register CYG_INTERRUPT_STATE oldints; |
|
count0 = cyg_current_time(); |
|
HAL_DISABLE_INTERRUPTS(oldints); |
HAL_DCACHE_SYNC(); |
|
k = 0; |
if ( cyg_test_is_simulator ) |
k = 3960; |
|
for(; k<4000;k++) { |
for(j=0; j<(HAL_DCACHE_SIZE/HAL_DCACHE_LINE_SIZE); j++) { |
HAL_DCACHE_INVALIDATE_ALL(); |
c=m[stride*j]; |
} |
} |
HAL_RESTORE_INTERRUPTS(oldints); |
|
count1 = cyg_current_time(); |
t = count1 - count0; |
diag_printf("stride=%d, time=%d\n", stride, t); |
} |
|
// ------------------------------------------------------------------------- |
|
void time1DI(void) |
{ |
cyg_uint32 i; |
|
for(i=1; i<=MAX_STRIDE; i+=i) { |
time0DI(i); |
} |
} |
#endif |
// ------------------------------------------------------------------------- |
// This test could be improved by counting number of passes possible |
// in a given number of ticks. |
|
static void entry0( cyg_addrword_t data ) |
{ |
register CYG_INTERRUPT_STATE oldints; |
|
#ifdef HAL_CACHE_UNIFIED |
|
HAL_DISABLE_INTERRUPTS(oldints); |
HAL_DCACHE_PURGE_ALL(); // rely on above definition |
HAL_UCACHE_INVALIDATE_ALL(); |
HAL_UCACHE_DISABLE(); |
HAL_RESTORE_INTERRUPTS(oldints); |
CYG_TEST_INFO("Cache off"); |
time1(); |
|
HAL_DISABLE_INTERRUPTS(oldints); |
HAL_DCACHE_PURGE_ALL(); // rely on above definition |
HAL_UCACHE_INVALIDATE_ALL(); |
HAL_UCACHE_ENABLE(); |
HAL_RESTORE_INTERRUPTS(oldints); |
CYG_TEST_INFO("Cache on"); |
time1(); |
|
#ifdef HAL_DCACHE_INVALIDATE_ALL |
HAL_DISABLE_INTERRUPTS(oldints); |
HAL_DCACHE_PURGE_ALL(); |
HAL_UCACHE_INVALIDATE_ALL(); |
HAL_UCACHE_ENABLE(); |
HAL_RESTORE_INTERRUPTS(oldints); |
CYG_TEST_INFO("Cache on: invalidate Cache (expect bogus timing)"); |
time1DI(); |
#endif |
|
#else // HAL_CACHE_UNIFIED |
|
HAL_DISABLE_INTERRUPTS(oldints); |
HAL_DCACHE_PURGE_ALL(); |
HAL_ICACHE_INVALIDATE_ALL(); |
HAL_DCACHE_INVALIDATE_ALL(); |
HAL_ICACHE_DISABLE(); |
HAL_DCACHE_DISABLE(); |
HAL_RESTORE_INTERRUPTS(oldints); |
CYG_TEST_INFO("Dcache off Icache off"); |
time1(); |
|
HAL_DISABLE_INTERRUPTS(oldints); |
HAL_DCACHE_PURGE_ALL(); |
HAL_ICACHE_INVALIDATE_ALL(); |
HAL_DCACHE_INVALIDATE_ALL(); |
HAL_ICACHE_DISABLE(); |
HAL_DCACHE_ENABLE(); |
HAL_RESTORE_INTERRUPTS(oldints); |
CYG_TEST_INFO("Dcache on Icache off"); |
time1(); |
|
HAL_DISABLE_INTERRUPTS(oldints); |
HAL_DCACHE_PURGE_ALL(); |
HAL_ICACHE_INVALIDATE_ALL(); |
HAL_DCACHE_INVALIDATE_ALL(); |
HAL_ICACHE_ENABLE(); |
HAL_DCACHE_DISABLE(); |
HAL_RESTORE_INTERRUPTS(oldints); |
CYG_TEST_INFO("Dcache off Icache on"); |
time1(); |
|
HAL_DISABLE_INTERRUPTS(oldints); |
HAL_DCACHE_PURGE_ALL(); |
HAL_ICACHE_INVALIDATE_ALL(); |
HAL_DCACHE_INVALIDATE_ALL(); |
HAL_ICACHE_ENABLE(); |
HAL_DCACHE_ENABLE(); |
HAL_RESTORE_INTERRUPTS(oldints); |
CYG_TEST_INFO("Dcache on Icache on"); |
time1(); |
|
|
HAL_DISABLE_INTERRUPTS(oldints); |
HAL_DCACHE_PURGE_ALL(); |
HAL_ICACHE_INVALIDATE_ALL(); |
HAL_DCACHE_INVALIDATE_ALL(); |
HAL_ICACHE_DISABLE(); |
HAL_DCACHE_DISABLE(); |
HAL_RESTORE_INTERRUPTS(oldints); |
CYG_TEST_INFO("Dcache off Icache off (again)"); |
time1(); |
|
#if defined(HAL_DCACHE_INVALIDATE_ALL) || defined(HAL_ICACHE_INVALIDATE_ALL) |
HAL_DISABLE_INTERRUPTS(oldints); |
HAL_DCACHE_PURGE_ALL(); |
HAL_ICACHE_INVALIDATE_ALL(); |
HAL_DCACHE_INVALIDATE_ALL(); |
HAL_ICACHE_ENABLE(); |
HAL_DCACHE_ENABLE(); |
HAL_RESTORE_INTERRUPTS(oldints); |
CYG_TEST_INFO("Dcache on Icache on (again)"); |
time1(); |
|
#if defined(CYGPKG_HAL_MIPS) |
// In some architectures, the time taken for the next two tests is |
// very long, partly because HAL_XCACHE_INVALIDATE_ALL() is implemented |
// with a loop over the cache. Hence these tests take longer than the |
// testing infrastructure is prepared to wait. The simplest way to get |
// these tests to run quickly is to make them think they are running |
// under a simulator. |
// If the target actually is a simulator, skip the below - it's very |
// slow on the simulator, even with reduced loop counts. |
if (cyg_test_is_simulator) |
CYG_TEST_PASS_FINISH("End of test"); |
|
#if defined(CYGPKG_HAL_MIPS_TX49) |
// The TX49 has a large cache, and even with reduced loop count, |
// 90+ seconds elapses between each INFO output. |
CYG_TEST_PASS_FINISH("End of test"); |
#endif |
|
cyg_test_is_simulator = 1; |
#endif |
|
#ifdef HAL_ICACHE_INVALIDATE_ALL |
HAL_DISABLE_INTERRUPTS(oldints); |
HAL_DCACHE_PURGE_ALL(); |
HAL_ICACHE_INVALIDATE_ALL(); |
HAL_DCACHE_INVALIDATE_ALL(); |
HAL_ICACHE_ENABLE(); |
HAL_DCACHE_ENABLE(); |
HAL_RESTORE_INTERRUPTS(oldints); |
CYG_TEST_INFO("Dcache on Icache on: invalidate ICache each time"); |
time1II(); |
#endif |
#ifdef HAL_DCACHE_INVALIDATE_ALL |
HAL_DISABLE_INTERRUPTS(oldints); |
HAL_DCACHE_PURGE_ALL(); |
HAL_ICACHE_INVALIDATE_ALL(); |
HAL_DCACHE_INVALIDATE_ALL(); |
HAL_ICACHE_ENABLE(); |
HAL_DCACHE_ENABLE(); |
HAL_RESTORE_INTERRUPTS(oldints); |
CYG_TEST_INFO("Dcache on Icache on: invalidate DCache (expect bogus times)"); |
time1DI(); |
#endif |
#endif // either INVALIDATE_ALL macro |
|
#endif // HAL_CACHE_UNIFIED |
|
CYG_TEST_PASS_FINISH("End of test"); |
} |
|
// ------------------------------------------------------------------------- |
|
void kcache2_main( void ) |
{ |
CYG_TEST_INIT(); |
|
cyg_thread_create(4, entry0 , (cyg_addrword_t)0, "kcache1", |
(void *)stack[0], STACKSIZE, &thread[0], &thread_obj[0]); |
cyg_thread_resume(thread[0]); |
|
cyg_scheduler_start(); |
} |
|
// ------------------------------------------------------------------------- |
|
externC void |
cyg_start( void ) |
{ |
kcache2_main(); |
} |
|
// ------------------------------------------------------------------------- |
|
#else // def CYGFUN_KERNEL_API_C |
#define N_A_MSG "Kernel C API layer disabled" |
#endif // def CYGFUN_KERNEL_API_C |
#else // def CYGVAR_KERNEL_COUNTERS_CLOCK |
#define N_A_MSG "Kernel real-time clock disabled" |
#endif // def CYGVAR_KERNEL_COUNTERS_CLOCK |
#else // def HAL_DCACHE_SIZE |
#define N_A_MSG "No caches defined" |
#endif // def HAL_DCACHE_SIZE |
|
#ifdef N_A_MSG |
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA( N_A_MSG ); |
} |
#endif // N_A_MSG |
|
// ------------------------------------------------------------------------- |
/* EOF kcache1.c */ |
/release.cxx
0,0 → 1,129
//========================================================================== |
// |
// release.cxx |
// |
// Thread release test |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): nickg |
// Contributors: nickg |
// Date: 1998-04-24 |
// Description: Tests the functionality of thread release(). |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/thread.hxx> |
#include <cyg/kernel/thread.inl> |
#include <cyg/kernel/sched.hxx> |
#include <cyg/kernel/mutex.hxx> |
#include <cyg/kernel/sema.hxx> |
|
#include <cyg/infra/testcase.h> |
|
#include <cyg/kernel/sched.inl> |
|
#define NTHREADS 2 |
|
#include "testaux.hxx" |
|
static Cyg_Binary_Semaphore s0, s1; |
|
static void entry0( CYG_ADDRWORD data ) |
{ |
Cyg_Thread *self = Cyg_Thread::self(); |
|
if (!s0.wait() ) |
{ |
if( self->get_wake_reason() != Cyg_Thread::BREAK ) |
CYG_TEST_FAIL_FINISH("Wake reason not BREAK"); |
} |
else |
{ |
CYG_TEST_FAIL_FINISH("Thread not released"); |
} |
|
s1.post(); |
|
self->exit(); |
} |
|
|
static void entry1( CYG_ADDRWORD data ) |
{ |
Cyg_Thread *self = Cyg_Thread::self(); |
|
// Give the other thread a chance to wait in SMP systems. |
for( int i = 0; i < 100; i++ ) |
self->yield(); |
|
thread[0]->release(); |
|
s1.wait(); |
|
CYG_TEST_PASS_FINISH("Release OK"); |
|
Cyg_Thread::self()->exit(); |
} |
|
void release_main(void) |
{ |
CYG_TEST_INIT(); |
|
new_thread( entry0, 0); |
new_thread( entry1, 1); |
|
thread[0]->set_priority(5); |
thread[1]->set_priority(6); |
|
Cyg_Scheduler::start(); |
|
CYG_TEST_FAIL_FINISH("Not reached"); |
|
} |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
release_main(); |
} |
|
// EOF release.cxx |
/kcache2.c
0,0 → 1,920
/*================================================================= |
// |
// kcache2.c |
// |
// Cache feature/timing tests |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. |
// Copyright (C) 2003 Gary Thomas |
// |
// 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): jskov, based on kcache1.c by dsm |
// Contributors: jskov, gthomas |
// Date: 1998-12-10 |
// Description: Tests some of the more exotic cache macros. |
//####DESCRIPTIONEND#### |
*/ |
|
#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
#include <cyg/kernel/kapi.h> |
|
#include <cyg/infra/testcase.h> |
|
#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK |
#ifdef CYGFUN_KERNEL_API_C |
|
#include <cyg/infra/diag.h> |
#include <cyg/hal/hal_cache.h> |
|
// ------------------------------------------------------------------------- |
|
#define NTHREADS 1 |
#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
// The following are defaults for loop variables. Note they will be overriden |
// on simulator targets, where detected - there is no point testing a cache |
// which doesn't exist :-). |
|
#define TEST_DZERO_LOOPS 5000 // default number of loops for test_dzero() |
#define TIME_ILOCK_LOOPS 10000 // default number of loops for time_ilock() |
#define TIME_DLOCK_LOOPS 10000 // default number of loops for time_dlock() |
|
// Define this to enable a simple, but hopefully useful, data cache |
// test. It may help discover if the cache support has been defined |
// properly (in terms of size and shape) |
#ifdef HAL_DCACHE_LINE_SIZE |
#define _TEST_DCACHE_OPERATION |
#endif |
|
static cyg_handle_t thread[NTHREADS]; |
|
static cyg_thread thread_obj[NTHREADS]; |
static char stack[NTHREADS][STACKSIZE]; |
|
#define MAXSIZE 1<<18 |
|
volatile char m[MAXSIZE]; |
|
// ------------------------------------------------------------------------- |
// Test of data cache zero. |
// o Timing comparison with instructions doing the same amount of work. |
// o Check that area cleared with the DCACHE_ZERO macro contains zeros. |
#ifdef HAL_DCACHE_ZERO |
static void test_dzero(void) |
{ |
register cyg_uint32 k, i; |
cyg_tick_count_t count0, count1; |
cyg_ucount32 t; |
volatile cyg_uint32* aligned_p; |
volatile cyg_uint32* p; |
register CYG_INTERRUPT_STATE oldints; |
cyg_ucount32 test_dzero_loops = TEST_DZERO_LOOPS; |
|
CYG_TEST_INFO("Data cache zero"); |
|
if (cyg_test_is_simulator) |
test_dzero_loops=10; |
|
aligned_p = (volatile cyg_uint32*) |
(((unsigned long) &m[HAL_DCACHE_LINE_SIZE*2]) |
& ~(HAL_DCACHE_LINE_SIZE-1)); |
|
// Time with conventional instructions. |
HAL_DISABLE_INTERRUPTS(oldints); |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_DISABLE(); |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_INVALIDATE_ALL(); |
HAL_DCACHE_ENABLE(); |
HAL_RESTORE_INTERRUPTS(oldints); |
count0 = cyg_current_time(); |
for (k = 0; k < test_dzero_loops; k++) { |
p = aligned_p; |
for (i = 0; i < HAL_DCACHE_SETS; i++) { |
#if (16 == HAL_DCACHE_LINE_SIZE) |
*p++ = 0; |
*p++ = 0; |
*p++ = 0; |
*p++ = 0; |
#elif (32 == HAL_DCACHE_LINE_SIZE) |
*p++ = 0; |
*p++ = 0; |
*p++ = 0; |
*p++ = 0; |
*p++ = 0; |
*p++ = 0; |
*p++ = 0; |
*p++ = 0; |
#else |
#error "Not defined for this cache line size." |
#endif |
} |
|
HAL_DISABLE_INTERRUPTS(oldints); |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_DISABLE(); |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_INVALIDATE_ALL(); |
HAL_DCACHE_ENABLE(); |
HAL_RESTORE_INTERRUPTS(oldints); |
} |
count1 = cyg_current_time(); |
t = count1 - count0; |
diag_printf("time with instructions: %d\n", t); |
|
// Initialize the area with non-zero so we can check whether |
// the macro cleared the area properly. |
p = aligned_p; |
for (i = 0; |
i < HAL_DCACHE_SETS*HAL_DCACHE_LINE_SIZE/sizeof(cyg_uint32); |
i++) { |
*p++ = 0xdeadbeef; |
} |
|
// Time with DCACHE_ZERO. |
HAL_DISABLE_INTERRUPTS(oldints); |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_DISABLE(); |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_INVALIDATE_ALL(); |
HAL_DCACHE_ENABLE(); |
HAL_RESTORE_INTERRUPTS(oldints); |
count0 = cyg_current_time(); |
for (k = 0; k < test_dzero_loops; k++) { |
HAL_DCACHE_ZERO(aligned_p, HAL_DCACHE_SETS*HAL_DCACHE_LINE_SIZE); |
|
HAL_DISABLE_INTERRUPTS(oldints); |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_DISABLE(); |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_INVALIDATE_ALL(); |
HAL_DCACHE_ENABLE(); |
HAL_RESTORE_INTERRUPTS(oldints); |
} |
count1 = cyg_current_time(); |
t = count1 - count0; |
diag_printf("time with HAL_DCACHE_ZERO: %d\n", t); |
|
// Verify that the area was actually cleared. |
{ |
cyg_uint32 d; |
|
d = 0; |
p = aligned_p; |
for (i = 0; |
i < HAL_DCACHE_SETS*HAL_DCACHE_LINE_SIZE/sizeof(cyg_uint32); |
i++) { |
d |= *p++; |
} |
|
CYG_TEST_CHECK(0 == d, "region not properly cleared"); |
} |
|
} |
#endif |
|
// ------------------------------------------------------------------------- |
// Test of data cache write hint. |
// Just check that the macro compiles. |
#ifdef HAL_DCACHE_WRITE_HINT |
static void test_dwrite_hint(void) |
{ |
register cyg_uint32 k; |
register CYG_INTERRUPT_STATE oldints; |
|
CYG_TEST_INFO("Data cache write hint"); |
|
HAL_DISABLE_INTERRUPTS(oldints); |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_DISABLE(); |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_INVALIDATE_ALL(); |
HAL_DCACHE_ENABLE(); |
HAL_RESTORE_INTERRUPTS(oldints); |
|
HAL_DCACHE_WRITE_HINT(&m[HAL_DCACHE_LINE_SIZE*2], 2*HAL_DCACHE_LINE_SIZE); |
for (k = 0; k < 20; k++); |
m[HAL_DCACHE_LINE_SIZE*2] = 42; |
} |
#endif |
|
// ------------------------------------------------------------------------- |
// Test of data cache read hint. |
// Just check that the macro compiles. |
#ifdef HAL_DCACHE_READ_HINT |
static void test_dread_hint(void) |
{ |
register char c; |
register cyg_uint32 k; |
register CYG_INTERRUPT_STATE oldints; |
|
CYG_TEST_INFO("Data cache read hint"); |
|
HAL_DISABLE_INTERRUPTS(oldints); |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_DISABLE(); |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_INVALIDATE_ALL(); |
HAL_DCACHE_ENABLE(); |
HAL_RESTORE_INTERRUPTS(oldints); |
|
HAL_DCACHE_READ_HINT(&m[HAL_DCACHE_LINE_SIZE*2], 2*HAL_DCACHE_LINE_SIZE); |
for (k = 0; k < 20; k++); |
c = m[HAL_DCACHE_LINE_SIZE*2]; |
} |
#endif |
|
// ------------------------------------------------------------------------- |
// Test of data cache line store |
// o No semantic requirement. |
// o Check that flushed data is written to memory. |
// o Simple invocation check of macro. |
#ifdef HAL_DCACHE_STORE |
static void test_dstore(void) |
{ |
volatile cyg_uint8* aligned_p; |
cyg_int32 i; |
register CYG_INTERRUPT_STATE oldints; |
|
CYG_TEST_INFO("Data cache store region"); |
|
for (i = 0; i < HAL_DCACHE_LINE_SIZE*16; i++) |
m[i] = 0; |
|
HAL_DISABLE_INTERRUPTS(oldints); |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_DISABLE(); |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_INVALIDATE_ALL(); |
HAL_DCACHE_ENABLE(); |
|
aligned_p = (volatile cyg_uint8*) |
(((unsigned long) &m[HAL_DCACHE_LINE_SIZE*2]) |
& ~(HAL_DCACHE_LINE_SIZE-1)); |
|
aligned_p[0] = 42 + aligned_p[1]; // Load causes cache to be used! |
|
HAL_DCACHE_STORE(aligned_p, HAL_DCACHE_LINE_SIZE); |
|
CYG_TEST_CHECK(42 == aligned_p[0], |
"memory didn't contain flushed data"); |
|
HAL_DCACHE_INVALIDATE_ALL(); // Discard... |
|
CYG_TEST_CHECK(42 == aligned_p[0], |
"memory didn't contain flushed data after invalidate all"); |
|
HAL_RESTORE_INTERRUPTS(oldints); |
} |
#endif |
|
// ------------------------------------------------------------------------- |
// Test of data cache total flush (sync). |
// o No semantic requirement. |
// o Check that flushed data is written to memory. |
// o Simple invocation check of macro. |
#ifdef HAL_DCACHE_LINE_SIZE // So we can find our way around memory |
|
#ifdef _TEST_DCACHE_OPERATION |
static void |
test_dcache_operation(void) |
{ |
long *lp = (long *)m; |
int i, errs; |
cyg_uint32 oldints; |
|
CYG_TEST_INFO("Data cache basic"); |
|
HAL_DISABLE_INTERRUPTS(oldints); |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_DISABLE(); |
HAL_DCACHE_SYNC(); |
// Fill test buffer |
for (i = 0; i < sizeof(m)/sizeof(*lp); i++) { |
lp[i] = i; |
} |
HAL_DCACHE_INVALIDATE_ALL(); |
HAL_DCACHE_ENABLE(); |
// Now push data through the cache |
// Note: 256 seems like a reasonable offset. It may be useful to actually |
// compute this (and the size of the test region) based on cache geometry |
for (i = 256; i < 256+HAL_DCACHE_SIZE/sizeof(*lp); i++) { |
lp[i] = 0xFF000000 + i; |
} |
// Now force cache clean and off |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_DISABLE(); |
// Verify the data |
diag_printf("Verify data with cache off\n"); |
errs = 0; |
for (i = 0; i < sizeof(m)/sizeof(*lp); i++) { |
if ((i >= 256) && (i < 256+HAL_DCACHE_SIZE/sizeof(*lp))) { |
if (lp[i] != (0xFF000000 + i)) { |
if (++errs < 16) { |
diag_printf("Data inside test range changed - was: %x, is %x, index: %x\n", |
0xFF000000+i, lp[i], i); |
} |
} |
} else { |
if (lp[i] != i) { |
if (++errs < 16) { |
diag_printf("Data outside test range changed - was: %x, is %x, index: %x\n", |
i, lp[i], i); |
} |
} |
} |
} |
CYG_TEST_CHECK(0 == errs, "dcache basic failed"); |
#if 0 // Additional information |
diag_printf("%d total errors during compare\n", errs); |
diag_dump_buf(&lp[240], 128); |
#endif |
HAL_RESTORE_INTERRUPTS(oldints); |
} |
#endif |
|
static void test_dsync(void) |
{ |
volatile cyg_uint8* aligned_p; |
cyg_int32 i; |
register CYG_INTERRUPT_STATE oldints; |
|
CYG_TEST_INFO("Data cache sync all"); |
|
for (i = 0; i < HAL_DCACHE_LINE_SIZE*16; i++) |
m[i] = 0; |
|
HAL_DISABLE_INTERRUPTS(oldints); |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_DISABLE(); |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_INVALIDATE_ALL(); |
HAL_DCACHE_ENABLE(); |
|
aligned_p = (volatile cyg_uint8*) |
(((unsigned long) &m[HAL_DCACHE_LINE_SIZE*2]) |
& ~(HAL_DCACHE_LINE_SIZE-1)); |
|
aligned_p[0] = 42 + aligned_p[1]; // Load causes cache to be used! |
aligned_p[HAL_DCACHE_LINE_SIZE] = 43 + aligned_p[HAL_DCACHE_LINE_SIZE + 1]; |
|
HAL_DCACHE_SYNC(); |
|
CYG_TEST_CHECK(42 == aligned_p[0], |
"memory didn't contain flushed data"); |
CYG_TEST_CHECK(43 == aligned_p[HAL_DCACHE_LINE_SIZE], |
"memory didn't contain flushed data next block"); |
|
HAL_DCACHE_INVALIDATE_ALL(); |
|
CYG_TEST_CHECK(42 == aligned_p[0], |
"memory didn't contain flushed data after invalidate"); |
CYG_TEST_CHECK(43 == aligned_p[HAL_DCACHE_LINE_SIZE], |
"memory didn't contain flushed data next block after invalidate"); |
|
HAL_RESTORE_INTERRUPTS(oldints); |
|
HAL_ICACHE_INVALIDATE_ALL(); |
HAL_DCACHE_DISABLE(); |
|
CYG_TEST_CHECK(42 == aligned_p[0], |
"memory didn't contain flushed data after disable"); |
CYG_TEST_CHECK(43 == aligned_p[HAL_DCACHE_LINE_SIZE], |
"memory didn't contain flushed data next block after disable"); |
|
HAL_DCACHE_ENABLE(); |
} |
#endif // HAL_DCACHE_LINE_SIZE |
|
// ------------------------------------------------------------------------- |
// Test of data cache line flush. |
// o Requires write-back cache. |
// o Check that flushed data is written to memory. |
// o Simple range check of macro. |
#ifdef HAL_DCACHE_QUERY_WRITE_MODE // only if we know this, can we test: |
#ifdef HAL_DCACHE_FLUSH |
static void test_dflush(void) |
{ |
volatile cyg_uint8* aligned_p; |
cyg_int32 i; |
register CYG_INTERRUPT_STATE oldints; |
|
CYG_TEST_INFO("Data cache flush region"); |
|
for (i = 0; i < HAL_DCACHE_LINE_SIZE*16; i++) |
m[i] = 0; |
|
HAL_DISABLE_INTERRUPTS(oldints); |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_DISABLE(); |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_INVALIDATE_ALL(); |
HAL_DCACHE_ENABLE(); |
HAL_RESTORE_INTERRUPTS(oldints); |
|
aligned_p = (volatile cyg_uint8*) |
(((unsigned long) &m[HAL_DCACHE_LINE_SIZE*2]) |
& ~(HAL_DCACHE_LINE_SIZE-1)); |
|
HAL_DISABLE_INTERRUPTS(oldints); |
|
aligned_p[0] = 42 + aligned_p[1]; // Load causes cache to be used! |
aligned_p[HAL_DCACHE_LINE_SIZE] = 43 + aligned_p[HAL_DCACHE_LINE_SIZE + 1]; |
|
HAL_DCACHE_FLUSH(aligned_p, HAL_DCACHE_LINE_SIZE); |
|
HAL_DCACHE_DISABLE(); |
|
HAL_RESTORE_INTERRUPTS(oldints); |
|
CYG_TEST_CHECK(42 == aligned_p[0], |
"memory didn't contain flushed data"); |
CYG_TEST_CHECK(0 == aligned_p[HAL_DCACHE_LINE_SIZE], |
"flushed beyond region"); |
|
HAL_DCACHE_ENABLE(); |
} |
#endif |
#endif |
|
// ------------------------------------------------------------------------- |
// Test of data cache disable (which does NOT force contents out to RAM) |
// o Requires write-back cache [so NOT invoked unconditionally] |
// o Check that dirty data is not written to memory and is invalidated |
// in the cache. |
// o Simple invocation check of macro. |
#ifdef HAL_DCACHE_QUERY_WRITE_MODE // only if we know this, can we test: |
static void test_ddisable(void) |
{ |
volatile cyg_uint8* aligned_p; |
cyg_int32 i; |
register CYG_INTERRUPT_STATE oldints; |
|
CYG_TEST_INFO("Data cache gross disable"); |
|
for (i = 0; i < HAL_DCACHE_LINE_SIZE*16; i++) |
m[i] = 0; |
|
HAL_DISABLE_INTERRUPTS(oldints); |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_DISABLE(); |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_INVALIDATE_ALL(); |
HAL_DCACHE_ENABLE(); |
HAL_RESTORE_INTERRUPTS(oldints); |
|
aligned_p = (volatile cyg_uint8*) |
(((unsigned long) &m[HAL_DCACHE_LINE_SIZE*2]) |
& ~(HAL_DCACHE_LINE_SIZE-1)); |
|
HAL_DISABLE_INTERRUPTS(oldints); |
|
aligned_p[0] = 43 + aligned_p[1]; // Load causes cache to be used! |
aligned_p[HAL_DCACHE_LINE_SIZE-1] = 43; |
|
aligned_p[HAL_DCACHE_LINE_SIZE] = 42 + aligned_p[HAL_DCACHE_LINE_SIZE + 1]; |
|
HAL_DCACHE_DISABLE(); |
|
HAL_RESTORE_INTERRUPTS(oldints); |
|
CYG_TEST_CHECK(0 == aligned_p[0] && |
0 == aligned_p[HAL_DCACHE_LINE_SIZE-1], |
"cache/memory contained invalidated data"); |
CYG_TEST_CHECK(0 == aligned_p[HAL_DCACHE_LINE_SIZE], |
"next block contained invalidated data"); |
|
HAL_DCACHE_ENABLE(); |
} |
#endif // def HAL_DCACHE_QUERY_WRITE_MODE |
|
// ------------------------------------------------------------------------- |
// Test of data cache total invalidate. |
// o Requires write-back cache. |
// o Check that invalidated data is not written to memory and is invalidated |
// in the cache. |
// o Simple invocation check of macro. |
#ifdef HAL_DCACHE_QUERY_WRITE_MODE // only if we know this, can we test: |
#ifdef HAL_DCACHE_INVALIDATE_ALL |
static void test_dinvalidate_all(void) |
{ |
volatile cyg_uint8* aligned_p; |
cyg_int32 i; |
register CYG_INTERRUPT_STATE oldints; |
|
CYG_TEST_INFO("Data cache invalidate all"); |
|
for (i = 0; i < HAL_DCACHE_LINE_SIZE*16; i++) |
m[i] = 0; |
|
HAL_DISABLE_INTERRUPTS(oldints); |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_DISABLE(); |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_INVALIDATE_ALL(); |
HAL_DCACHE_ENABLE(); |
|
aligned_p = (volatile cyg_uint8*) |
(((unsigned long) &m[HAL_DCACHE_LINE_SIZE*2]) |
& ~(HAL_DCACHE_LINE_SIZE-1)); |
|
aligned_p[0] = 43 + aligned_p[1]; // Load causes cache to be used! |
aligned_p[HAL_DCACHE_LINE_SIZE-1] = 43; |
|
aligned_p[HAL_DCACHE_LINE_SIZE] = 42 + aligned_p[HAL_DCACHE_LINE_SIZE + 1]; |
|
HAL_DCACHE_INVALIDATE_ALL(); |
|
HAL_RESTORE_INTERRUPTS(oldints); |
|
CYG_TEST_CHECK(0 == aligned_p[0] && |
0 == aligned_p[HAL_DCACHE_LINE_SIZE-1], |
"cache/memory contained invalidated data"); |
CYG_TEST_CHECK(0 == aligned_p[HAL_DCACHE_LINE_SIZE], |
"next block contained invalidated data"); |
} |
#endif |
#endif // def HAL_DCACHE_QUERY_WRITE_MODE |
|
// ------------------------------------------------------------------------- |
// Test of data cache line invalidate. |
// o Requires write-back cache. |
// o Check that invalidated data is not written to memory and is invalidated |
// in the cache. |
// o Simple range check of macro. |
#ifdef HAL_DCACHE_QUERY_WRITE_MODE // only if we know this, can we test: |
#ifdef HAL_DCACHE_INVALIDATE |
static void test_dinvalidate(void) |
{ |
volatile cyg_uint8* aligned_p; |
cyg_int32 i; |
register CYG_INTERRUPT_STATE oldints; |
|
CYG_TEST_INFO("Data cache invalidate region"); |
|
for (i = 0; i < HAL_DCACHE_LINE_SIZE*16; i++) |
m[i] = 0; |
|
HAL_DISABLE_INTERRUPTS(oldints); |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_DISABLE(); |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_INVALIDATE_ALL(); |
HAL_DCACHE_ENABLE(); |
HAL_RESTORE_INTERRUPTS(oldints); |
|
aligned_p = (volatile cyg_uint8*) |
(((unsigned long) &m[HAL_DCACHE_LINE_SIZE*2]) |
& ~(HAL_DCACHE_LINE_SIZE-1)); |
|
HAL_DISABLE_INTERRUPTS(oldints); |
|
aligned_p[0] = 43 + aligned_p[1]; // Load causes cache to be used! |
aligned_p[HAL_DCACHE_LINE_SIZE-1] = 43; |
|
aligned_p[HAL_DCACHE_LINE_SIZE] = 42 + aligned_p[HAL_DCACHE_LINE_SIZE + 1]; |
|
HAL_DCACHE_INVALIDATE(aligned_p, HAL_DCACHE_LINE_SIZE); |
|
HAL_RESTORE_INTERRUPTS(oldints); |
|
CYG_TEST_CHECK(0 == aligned_p[0] && |
0 == aligned_p[HAL_DCACHE_LINE_SIZE-1], |
"cache/memory contained invalidated data"); |
CYG_TEST_CHECK(42 == aligned_p[HAL_DCACHE_LINE_SIZE], |
"invalidated beyond range"); |
|
HAL_DCACHE_SYNC(); |
HAL_DCACHE_DISABLE(); |
|
CYG_TEST_CHECK(0 == aligned_p[0] && |
0 == aligned_p[HAL_DCACHE_LINE_SIZE-1], |
"cache/memory contained invalidated data after SYNC/DIS"); |
CYG_TEST_CHECK(42 == aligned_p[HAL_DCACHE_LINE_SIZE], |
"invalidated beyond range after SYNC/DIS"); |
|
HAL_DCACHE_ENABLE(); |
} |
#endif |
#endif // def HAL_DCACHE_QUERY_WRITE_MODE |
|
// ------------------------------------------------------------------------- |
// Test of instruction cache locking. |
// o Time difference between repeatedly executing a bunch of instructions |
// with and without locking. |
#ifdef HAL_ICACHE_LOCK |
static void iloop(unsigned long* start, unsigned long* end, int dummy) |
{ |
// dummy is just used to fool the compiler to not move the labels |
// around. All callers should call with dummy=0; |
|
register char c; |
register CYG_INTERRUPT_STATE oldints; |
|
if (1 == dummy) goto label_end; |
|
label_start: |
// Invalidating shouldn't affect locked lines. |
HAL_DISABLE_INTERRUPTS(oldints); |
HAL_ICACHE_DISABLE(); |
HAL_ICACHE_INVALIDATE_ALL(); |
HAL_ICACHE_ENABLE(); |
HAL_RESTORE_INTERRUPTS(oldints); |
|
c = m[HAL_DCACHE_LINE_SIZE*0]; |
c = m[HAL_DCACHE_LINE_SIZE*1]; |
c = m[HAL_DCACHE_LINE_SIZE*2]; |
c = m[HAL_DCACHE_LINE_SIZE*3]; |
c = m[HAL_DCACHE_LINE_SIZE*4]; |
c = m[HAL_DCACHE_LINE_SIZE*5]; |
c = m[HAL_DCACHE_LINE_SIZE*6]; |
c = m[HAL_DCACHE_LINE_SIZE*7]; |
c = m[HAL_DCACHE_LINE_SIZE*8]; |
c = m[HAL_DCACHE_LINE_SIZE*9]; |
c = m[HAL_DCACHE_LINE_SIZE*10]; |
c = m[HAL_DCACHE_LINE_SIZE*11]; |
c = m[HAL_DCACHE_LINE_SIZE*12]; |
c = m[HAL_DCACHE_LINE_SIZE*13]; |
c = m[HAL_DCACHE_LINE_SIZE*14]; |
c = m[HAL_DCACHE_LINE_SIZE*15]; |
c = m[HAL_DCACHE_LINE_SIZE*16]; |
c = m[HAL_DCACHE_LINE_SIZE*17]; |
c = m[HAL_DCACHE_LINE_SIZE*18]; |
c = m[HAL_DCACHE_LINE_SIZE*19]; |
c = m[HAL_DCACHE_LINE_SIZE*20]; |
c = m[HAL_DCACHE_LINE_SIZE*21]; |
c = m[HAL_DCACHE_LINE_SIZE*22]; |
c = m[HAL_DCACHE_LINE_SIZE*23]; |
c = m[HAL_DCACHE_LINE_SIZE*24]; |
c = m[HAL_DCACHE_LINE_SIZE*25]; |
c = m[HAL_DCACHE_LINE_SIZE*26]; |
c = m[HAL_DCACHE_LINE_SIZE*27]; |
c = m[HAL_DCACHE_LINE_SIZE*28]; |
c = m[HAL_DCACHE_LINE_SIZE*29]; |
c = m[HAL_DCACHE_LINE_SIZE*30]; |
c = m[HAL_DCACHE_LINE_SIZE*31]; |
c = m[HAL_DCACHE_LINE_SIZE*32]; |
c = m[HAL_DCACHE_LINE_SIZE*33]; |
c = m[HAL_DCACHE_LINE_SIZE*34]; |
c = m[HAL_DCACHE_LINE_SIZE*35]; |
c = m[HAL_DCACHE_LINE_SIZE*36]; |
c = m[HAL_DCACHE_LINE_SIZE*37]; |
c = m[HAL_DCACHE_LINE_SIZE*38]; |
c = m[HAL_DCACHE_LINE_SIZE*39]; |
c = m[HAL_DCACHE_LINE_SIZE*40]; |
c = m[HAL_DCACHE_LINE_SIZE*41]; |
c = m[HAL_DCACHE_LINE_SIZE*42]; |
c = m[HAL_DCACHE_LINE_SIZE*43]; |
c = m[HAL_DCACHE_LINE_SIZE*44]; |
c = m[HAL_DCACHE_LINE_SIZE*45]; |
c = m[HAL_DCACHE_LINE_SIZE*46]; |
c = m[HAL_DCACHE_LINE_SIZE*47]; |
c = m[HAL_DCACHE_LINE_SIZE*48]; |
c = m[HAL_DCACHE_LINE_SIZE*49]; |
c = m[HAL_DCACHE_LINE_SIZE*50]; |
c = m[HAL_DCACHE_LINE_SIZE*51]; |
c = m[HAL_DCACHE_LINE_SIZE*52]; |
c = m[HAL_DCACHE_LINE_SIZE*53]; |
c = m[HAL_DCACHE_LINE_SIZE*54]; |
c = m[HAL_DCACHE_LINE_SIZE*55]; |
c = m[HAL_DCACHE_LINE_SIZE*56]; |
c = m[HAL_DCACHE_LINE_SIZE*57]; |
c = m[HAL_DCACHE_LINE_SIZE*58]; |
c = m[HAL_DCACHE_LINE_SIZE*59]; |
c = m[HAL_DCACHE_LINE_SIZE*60]; |
c = m[HAL_DCACHE_LINE_SIZE*61]; |
c = m[HAL_DCACHE_LINE_SIZE*62]; |
c = m[HAL_DCACHE_LINE_SIZE*63]; |
|
label_end: |
|
*start = (unsigned long) &&label_start; |
*end = (unsigned long) &&label_end; |
|
if (1 == dummy) goto label_start; |
} |
|
static void time_ilock(void) |
{ |
register cyg_ucount32 k; |
cyg_tick_count_t count0, count1; |
cyg_ucount32 t; |
unsigned long start, end; |
register cyg_ucount32 time_ilock_loops = TIME_ILOCK_LOOPS; |
|
CYG_TEST_INFO("Instruction cache lock"); |
|
if (cyg_test_is_simulator) |
time_ilock_loops = 10; |
|
count0 = cyg_current_time(); |
for (k = 0; k < time_ilock_loops; k++) { |
iloop(&start, &end, 0); |
} |
count1 = cyg_current_time(); |
t = count1 - count0; |
diag_printf("time without lock: %d\n", t); |
|
HAL_ICACHE_LOCK(start, end-start); |
|
count0 = cyg_current_time(); |
for (k = 0; k < time_ilock_loops; k++) { |
iloop(&start, &end, 0); |
} |
count1 = cyg_current_time(); |
t = count1 - count0; |
diag_printf("time with lock: %d\n", t); |
|
HAL_ICACHE_UNLOCK(start, end-start); |
} |
#endif // ifdef HAL_ICACHE_LOCK |
|
// ------------------------------------------------------------------------- |
// Test of data cache locking. |
// o Time difference between repeatedly accessing a memory region |
// with and without locking. |
#ifdef HAL_DCACHE_LOCK |
static void dloop(void) |
{ |
register cyg_uint32 j; |
register char c; |
register CYG_INTERRUPT_STATE oldints; |
|
HAL_DISABLE_INTERRUPTS(oldints); |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_DISABLE(); |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_INVALIDATE_ALL(); |
HAL_DCACHE_ENABLE(); |
HAL_RESTORE_INTERRUPTS(oldints); |
for (j = 0; j < HAL_DCACHE_SETS; j++) { |
c = m[HAL_DCACHE_LINE_SIZE*j]; |
} |
} |
|
static void time_dlock(void) |
{ |
register cyg_ucount32 k; |
cyg_tick_count_t count0, count1; |
cyg_ucount32 t; |
register cyg_ucount32 time_dlock_loops = TIME_DLOCK_LOOPS; |
|
CYG_TEST_INFO("Data cache lock"); |
|
if (cyg_test_is_simulator) |
time_dlock_loops = 10; |
|
count0 = cyg_current_time(); |
for (k = 0; k < time_dlock_loops; k++) { |
dloop(); |
} |
count1 = cyg_current_time(); |
t = count1 - count0; |
diag_printf("time without lock: %d\n", t); |
|
HAL_DCACHE_LOCK(&m[0], HAL_DCACHE_SETS*HAL_DCACHE_LINE_SIZE); |
|
count0 = cyg_current_time(); |
for (k = 0; k < time_dlock_loops; k++) { |
dloop(); |
} |
count1 = cyg_current_time(); |
t = count1 - count0; |
diag_printf("time with lock: %d\n", t); |
|
HAL_DCACHE_UNLOCK(&m[0], HAL_DCACHE_SETS*HAL_DCACHE_LINE_SIZE); |
} |
#endif // ifdef HAL_DCACHE_LOCK |
|
// ------------------------------------------------------------------------- |
static void entry0( cyg_addrword_t data ) |
{ |
int numtests = 0; |
#ifdef HAL_DCACHE_QUERY_WRITE_MODE |
int wmode; |
#endif |
#ifdef HAL_DCACHE_LOCK |
time_dlock(); numtests++; |
#endif |
#ifdef HAL_ICACHE_LOCK |
time_ilock(); numtests++; |
#endif |
#ifdef HAL_DCACHE_LINE_SIZE // So we can find our way around memory |
test_dsync(); numtests++; |
#endif |
#ifdef HAL_DCACHE_STORE |
test_dstore(); numtests++; |
#endif |
#ifdef _TEST_DCACHE_OPERATION |
test_dcache_operation(); numtests++; |
#endif |
#ifdef HAL_DCACHE_READ_HINT |
test_dread_hint(); numtests++; |
#endif |
#ifdef HAL_DCACHE_WRITE_HINT |
test_dwrite_hint(); numtests++; |
#endif |
#ifdef HAL_DCACHE_ZERO |
test_dzero(); numtests++; |
#endif |
|
// The below tests only work on a copy-back cache. |
#ifdef HAL_DCACHE_QUERY_WRITE_MODE |
HAL_DCACHE_QUERY_WRITE_MODE( wmode ); |
|
if ( HAL_DCACHE_WRITEBACK_MODE == wmode ) { |
test_ddisable(); numtests++; |
#ifdef HAL_DCACHE_INVALIDATE |
test_dinvalidate_all(); numtests++; |
#endif |
#ifdef HAL_DCACHE_FLUSH |
test_dflush(); numtests++; |
#endif |
#ifdef HAL_DCACHE_INVALIDATE |
test_dinvalidate(); numtests++; |
#endif |
} |
#endif // def HAL_DCACHE_QUERY_WRITE_MODE |
if ( numtests ) { |
CYG_TEST_PASS_FINISH("End of test"); |
} |
else { |
CYG_TEST_NA( "No applicable cache tests" ); |
} |
} |
|
// ------------------------------------------------------------------------- |
|
void kcache2_main( void ) |
{ |
CYG_TEST_INIT(); |
|
cyg_thread_create(4, entry0 , (cyg_addrword_t)0, "kcache2", |
(void *)stack[0], STACKSIZE, &thread[0], &thread_obj[0]); |
cyg_thread_resume(thread[0]); |
|
cyg_scheduler_start(); |
} |
|
// ------------------------------------------------------------------------- |
|
externC void |
cyg_start( void ) |
{ |
kcache2_main(); |
} |
|
// ------------------------------------------------------------------------- |
|
#else // def CYGFUN_KERNEL_API_C |
#define N_A_MSG "Kernel C API layer disabled" |
#endif // def CYGFUN_KERNEL_API_C |
#else // def CYGVAR_KERNEL_COUNTERS_CLOCK |
#define N_A_MSG "Kernel real-time clock disabled" |
#endif // def CYGVAR_KERNEL_COUNTERS_CLOCK |
|
#ifdef N_A_MSG |
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA( N_A_MSG ); |
} |
#endif // N_A_MSG |
|
// ------------------------------------------------------------------------- |
/* EOF kcache2.c */ |
/kmutex3.c
0,0 → 1,638
//========================================================================== |
// |
// kmutex3.c |
// |
// Mutex test 3 - priority inheritance |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): hmt |
// Contributors: hmt |
// Date: 2000-01-06, 2001-08-10 |
// Description: Tests mutex priority inheritance. This is simply a |
// translation of the similarly named kernel test to the |
// KAPI, with the intention of also testing the new |
// "set the protocol at run-time" extensions. |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/hal.h> |
#include <pkgconf/kernel.h> |
|
#include <cyg/infra/testcase.h> |
|
#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
#include <cyg/infra/diag.h> // diag_printf |
|
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
externC void |
cyg_hal_invoke_constructors(); |
#endif |
|
// ------------------------------------------------------------------------ |
// |
// These checks should be enough; any other scheduler which has priorities |
// should manifest as having no priority inheritance, but otherwise fine, |
// so the test should work correctly. |
|
#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK) && \ |
(CYGNUM_KERNEL_SCHED_PRIORITIES > 20) && \ |
defined(CYGFUN_KERNEL_API_C) && \ |
!defined(CYGPKG_KERNEL_SMP_SUPPORT) |
|
|
#include <cyg/kernel/kapi.h> |
|
#include <cyg/infra/cyg_ass.h> |
#include <cyg/infra/cyg_trac.h> |
#include <cyg/infra/diag.h> // diag_printf |
|
|
// ------------------------------------------------------------------------ |
// manufacture a simpler feature test macro for priority inheritance than |
// the configuration gives us. We have priority inheritance if it is configured |
// as the only protocol, or if it is the default protocol for dynamic protocol |
// choice. |
|
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT |
# ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC |
# ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_INHERIT |
# define PRIORITY_INHERITANCE "dynamic-default-inherit" |
# endif |
# else |
# define PRIORITY_INHERITANCE "static-inherit" |
# endif |
#endif |
|
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING |
# ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC |
# ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_CEILING |
# if CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY <= 5 |
# define PRIORITY_INHERITANCE "dynamic-default-ceiling-high" |
# elif CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY >= 15 |
# define NO_PRIORITY_INHERITANCE "dynamic-default-ceiling-low" |
# else |
# define PRIORITY_UNKNOWN "dynamic-default-ceiling-mid" |
# endif |
# endif |
# else |
# if CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY <= 5 |
# define PRIORITY_INHERITANCE "static-ceiling-high" |
# elif CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY >= 15 |
# define NO_PRIORITY_INHERITANCE "static-ceiling-low" |
# else |
# define PRIORITY_UNKNOWN "static-ceiling-mid" |
# endif |
# endif |
#endif |
|
#ifndef PRIORITY_INHERITANCE |
# ifndef NO_PRIORITY_INHERITANCE |
# define NO_PRIORITY_INHERITANCE "no scheme selected" |
# endif |
#endif |
|
// ------------------------------------------------------------------------ |
// Management functions |
// |
// Stolen from testaux.hxx and copied in here because I want to be able to |
// reset the world also. |
// |
// Translated into KAPI also. |
|
#define NTHREADS 7 |
|
#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
static cyg_handle_t thread[NTHREADS] = { 0 }; |
|
typedef cyg_uint64 CYG_ALIGNMENT_TYPE; |
|
static cyg_thread thread_obj[NTHREADS]; |
|
static CYG_ALIGNMENT_TYPE stack[NTHREADS] [ |
(STACKSIZE+sizeof(CYG_ALIGNMENT_TYPE)-1) |
/ sizeof(CYG_ALIGNMENT_TYPE) ]; |
|
static volatile int nthreads = 0; |
|
#undef NULL |
#define NULL (0) |
|
static cyg_handle_t new_thread( cyg_thread_entry_t *entry, |
cyg_addrword_t data, |
cyg_addrword_t priority, |
int do_resume ) |
{ |
int _nthreads = nthreads++; |
|
CYG_ASSERT(_nthreads < NTHREADS, |
"Attempt to create more than NTHREADS threads"); |
|
cyg_thread_create( priority, |
entry, |
data, |
NULL, // no name |
(void *)(stack[_nthreads]), |
STACKSIZE, |
&thread[_nthreads], |
&thread_obj[_nthreads] ); |
|
if ( do_resume ) |
cyg_thread_resume( thread[_nthreads] ); |
|
return thread[_nthreads]; |
} |
|
|
static void kill_threads( void ) |
{ |
CYG_ASSERT(nthreads <= NTHREADS, |
"More than NTHREADS threads"); |
CYG_ASSERT( cyg_thread_self() == thread[0], |
"kill_threads() not called from thread 0"); |
while ( nthreads > 1 ) { |
nthreads--; |
if ( NULL != thread[nthreads] ) { |
do |
cyg_thread_kill( thread[nthreads] ); |
while ( ! cyg_thread_delete ( thread[nthreads] ) ); |
thread[nthreads] = NULL; |
} |
} |
CYG_ASSERT(nthreads == 1, |
"No threads left"); |
} |
|
// ------------------------------------------------------------------------ |
|
#define DELAYFACTOR 1 // for debugging |
|
// ------------------------------------------------------------------------ |
|
static cyg_mutex_t mutex_obj; |
static cyg_mutex_t *mutex; |
|
// These are for reporting back to the master thread |
volatile int got_it = 0; |
volatile int t3ran = 0; |
volatile int t3ended = 0; |
volatile int extras[4] = {0,0,0,0}; |
|
volatile int go_flag = 0; // but this one controls thread 3 from thread 2 |
|
// ------------------------------------------------------------------------ |
// 0 to 3 of these run generally to interfere with the other processing, |
// to cause multiple prio inheritances, and clashes in any orders. |
|
static void extra_thread( cyg_addrword_t data ) |
{ |
cyg_handle_t self = cyg_thread_self(); |
|
#define XINFO( z ) \ |
do { z[13] = '0' + data; CYG_TEST_INFO( z ); } while ( 0 ) |
|
static char running[] = "Extra thread Xa running"; |
static char exiting[] = "Extra thread Xa exiting"; |
static char resumed[] = "Extra thread Xa resumed"; |
static char locked[] = "Extra thread Xa locked"; |
static char unlocked[] = "Extra thread Xa unlocked"; |
|
XINFO( running ); |
|
cyg_thread_suspend( self ); |
|
XINFO( resumed ); |
|
cyg_mutex_lock( mutex ); |
|
XINFO( locked ); |
|
cyg_mutex_unlock( mutex ); |
|
XINFO( unlocked ); |
|
extras[ data ] ++; |
|
XINFO( exiting ); |
|
} |
|
// ------------------------------------------------------------------------ |
|
static void t1( cyg_addrword_t data ) |
{ |
cyg_handle_t self = cyg_thread_self(); |
|
CYG_TEST_INFO( "Thread 1 running" ); |
|
cyg_thread_suspend( self ); |
|
cyg_mutex_lock( mutex ); |
|
got_it++; |
|
CYG_TEST_CHECK( 0 == t3ended, "T3 ended prematurely [T1,1]" ); |
|
cyg_mutex_unlock( mutex ); |
|
CYG_TEST_CHECK( 0 == t3ended, "T3 ended prematurely [T1,2]" ); |
|
// That's all. |
|
CYG_TEST_INFO( "Thread 1 exit" ); |
} |
|
// ------------------------------------------------------------------------ |
|
static void t2( cyg_addrword_t data ) |
{ |
cyg_handle_t self = cyg_thread_self(); |
int i; |
cyg_tick_count_t then, now; |
|
CYG_TEST_INFO( "Thread 2 running" ); |
|
CYG_TEST_CHECK( 0 == (data & ~0x77), "Bad T2 arg: extra bits" ); |
CYG_TEST_CHECK( 0 == (data & (data >> 4)), "Bad T2 arg: overlap" ); |
|
cyg_thread_suspend( self ); |
|
// depending on our config argument, optionally restart some of the |
// extra threads to throw noise into the scheduler: |
for ( i = 0; i < 3; i++ ) |
if ( (1 << i) & data ) // bits 0-2 control |
cyg_thread_resume( thread[i+4] ); // extras are thread[4-6] |
|
cyg_thread_delay( DELAYFACTOR * 10 ); // let those threads run |
|
cyg_scheduler_lock(); // do this next lot atomically |
|
go_flag = 1; // unleash thread 3 |
cyg_thread_resume( thread[1] ); // resume thread 1 |
|
// depending on our config argument, optionally restart some of the |
// extra threads to throw noise into the scheduler at this later point: |
for ( i = 4; i < 7; i++ ) |
if ( (1 << i) & data ) // bits 4-6 control |
cyg_thread_resume( thread[i] ); // extras are thread[4-6] |
|
cyg_scheduler_unlock(); // let scheduling proceed |
|
// Need a delay (but not a CPU yield) to allow t3 to awaken and act on |
// the go_flag, otherwise we check these details below too soon. |
// Actually, waiting for the clock to tick a couple of times would be |
// better, so that is what we will do. Must be a busy-wait. |
then = cyg_current_time(); |
do { |
now = cyg_current_time(); |
// Wait longer than the delay in t3 waiting on go_flag |
} while ( now < (then + 3) ); |
|
#ifdef PRIORITY_UNKNOWN |
CYG_TEST_INFO( "Not checking: " PRIORITY_UNKNOWN ); |
#else |
#ifdef PRIORITY_INHERITANCE |
CYG_TEST_INFO( "Checking priority scheme: " PRIORITY_INHERITANCE ); |
CYG_TEST_CHECK( 1 == t3ran, "Thread 3 did not run" ); |
CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" ); |
#else |
CYG_TEST_INFO( "Checking NO priority scheme: " NO_PRIORITY_INHERITANCE ); |
CYG_TEST_CHECK( 0 == t3ran, "Thread 3 DID run" ); |
CYG_TEST_CHECK( 0 == got_it, "Thread 1 DID get the mutex" ); |
#endif |
#endif |
|
CYG_TEST_CHECK( 0 == t3ended, "Thread 3 ended prematurely [T2,1]" ); |
|
cyg_thread_delay( DELAYFACTOR * 20 ); // let those threads run |
|
CYG_TEST_CHECK( 1 == t3ran, "Thread 3 did not run" ); |
CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" ); |
CYG_TEST_CHECK( 1 == t3ended, "Thread 3 has not ended" ); |
|
for ( i = 0; i < 3; i++ ) |
if ( (1 << i) & (data | data >> 4) ) // bits 0-2 and 4-6 control |
CYG_TEST_CHECK( 1 == extras[i+1], "Extra thread did not run" ); |
else |
CYG_TEST_CHECK( 0 == extras[i+1], "Extra thread ran" ); |
|
CYG_TEST_PASS( "Thread 2 exiting, AOK" ); |
// That's all: restart the control thread. |
cyg_thread_resume( thread[0] ); |
} |
|
// ------------------------------------------------------------------------ |
|
static void t3( cyg_addrword_t data ) |
{ |
CYG_TEST_INFO( "Thread 3 running" ); |
|
cyg_mutex_lock( mutex ); |
|
cyg_thread_delay( DELAYFACTOR * 5 ); // let thread 3a run |
|
cyg_thread_resume( thread[2] ); // resume thread 2 |
|
while ( 0 == go_flag ) |
cyg_thread_delay(1); // wait until we are told to go |
|
t3ran ++; // record the fact |
|
CYG_TEST_CHECK( 0 == got_it, "Thread 1 claims to have got my mutex" ); |
|
cyg_mutex_unlock( mutex ); |
|
t3ended ++; // record that we came back |
|
CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" ); |
|
CYG_TEST_INFO( "Thread 3 exit" ); |
} |
|
// ------------------------------------------------------------------------ |
|
static void control_thread( cyg_addrword_t data ) |
{ |
cyg_handle_t self = cyg_thread_self(); |
int i, z; |
|
CYG_TEST_INIT(); |
CYG_TEST_INFO( "Control Thread running" ); |
|
// Go through the 27 possibilities of resuming the extra threads |
// 0: not at all |
// 1: early in the process |
// 2: later on |
// which are represented by bits 0-3 and 4-6 resp in the argument to |
// thread 2 (none set means no resume at all). |
for ( i = 0; i < 27; i++ ) { |
static int xx[] = { 0, 1, 16 }; |
int j = i % 3; |
int k = (i / 3) % 3; |
int l = (i / 9) % 3; |
|
int d = xx[j] | (xx[k]<<1) | (xx[l]<<2) ; |
|
if ( cyg_test_is_simulator && (0 != i && 13 != i && 26 != i) ) |
continue; // 13 is 111 base 3, 26 is 222 base 3 |
|
#ifdef PRIORITY_INHERITANCE |
// If the simple scheme plus relay enhancement, or any other |
// *complete* scheme, we can run all three ancillary threads no |
// problem, so no special action here. |
|
#else |
// If no priority inheritance at all, running threads 1a and 2a is |
// OK, but not thread 3a; it blocks the world. |
if ( l ) // Cannot run thread 3a if no |
break; // priority inheritance at all. |
#endif |
|
mutex = &mutex_obj; |
cyg_mutex_init( mutex ); |
|
got_it = 0; |
t3ran = 0; |
t3ended = 0; |
for ( z = 0; z < 4; z++ ) extras[z] = 0; |
go_flag = 0; |
|
new_thread( t1, 0, 5, 1 ); // Slot 1 |
new_thread( t2, d, 10, 1 ); // Slot 2 |
new_thread( t3, 0, 15, 1 ); // Slot 3 |
|
new_thread( extra_thread, 1, 8, j ); // Slot 4 |
new_thread( extra_thread, 2, 12, k ); // Slot 5 |
new_thread( extra_thread, 3, 17, l ); // Slot 6 |
|
{ |
static char *a[] = { "inactive", "run early", "run late" }; |
diag_printf( "\n----- [%2d] New Cycle: 0x%02x, Threads 1a %s, 2a %s, 3a %s -----\n", |
i, d, a[j], a[k], a[l] ); |
} |
|
cyg_thread_suspend( self ); |
|
kill_threads(); |
cyg_mutex_destroy( mutex ); |
} |
CYG_TEST_EXIT( "Control Thread exit" ); |
} |
|
// ------------------------------------------------------------------------ |
|
externC void |
cyg_user_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
new_thread( control_thread, 0, 2, 1 ); |
} |
|
#else // CYGVAR_KERNEL_COUNTERS_CLOCK &c |
|
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_PASS_FINISH("KMutex3 test requires:\n" |
"CYGFUN_KERNEL_API_C &&\n" |
"CYGVAR_KERNEL_COUNTERS_CLOCK &&\n" |
"(CYGNUM_KERNEL_SCHED_PRIORITIES > 20) &&\n" |
"!defined(CYGPKG_KERNEL_SMP_SUPPORT)\n"); |
} |
#endif // CYGVAR_KERNEL_COUNTERS_CLOCK &c |
|
|
// ------------------------------------------------------------------------ |
// Documentation: enclosed is the design of this test. |
// |
// It has been carefully constructed so that it does NOT use other kernel |
// facilities (aside from delay-task) to test that priority inheritance is |
// working, or not, as intended by the configuration. |
// |
// These notes describe the flow of control in one run of the test with the |
// ancillary tasks optionally interspersed. The details of how those extra |
// tasks are or are not allowed to run are not described. |
// |
// |
// |
// The only change in the test that depends on whether there is inheritance or |
// not is the check in thread 2 on "3-ran" and "got it" flags marked **** |
// |
// |
// volatile &c booleans: |
// "got it" = FALSE |
// "3-ran" = FALSE |
// "3-ended" = FALSE |
// "extras"[3] = FALSE |
// |
// thread 1. prio 5, self-suspend. |
// |
// thread 1a, prio 8, self-suspend. |
// |
// thread 2. prio 10, self-suspend. |
// |
// thread 2a, prio 12, self-suspend. |
// |
// thread 3. prio 15, runs, lock mutex, resume(2) |
// |
// thread 3a, prio 17, self-suspend. |
// |
// 2. runs, |
// 2. resume(3a) +++OPTIONAL |
// 2. resume(2a) +++OPTIONAL |
// 2. resume(1a) +++OPTIONAL |
// [1a lock-fail] thread 3->prio := 8 |
// |
// [3. runs maybe, does the looping thing] |
// |
// 2. sleep a while... |
// |
// [2a lock-fail] thread 3->prio := 12 |
// |
// [3. runs maybe, does the looping thing] |
// |
// [3a lock-fail] thread 3->prio unchanged |
// |
// [3. runs maybe, does the looping thing] |
// |
// 2. lock scheduler |
// 2. set "go-flag" |
// 2. resume(1) |
// 2. resume(1a) +++OPTIONAL |
// 2. resume(2a) +++OPTIONAL |
// 2. resume(3a) +++OPTIONAL |
// 2. unlock scheduler |
// |
// 1. runs, lock mutex - thread 3 has it locked |
// |
// 2. busy-waits a bit for thread 3 to come out of its delay() loop. |
// This must be a *busy*wait so that 3 can only run via the |
// inherited raised priority. |
// |
// [xa. all do the same: lock mutex, ] |
// [xa. unlock mutex ] |
// [xa. set a flag "extras"[x] to say we are done. ] |
// [xa. exit ] |
// |
// |
// |
// INHERIT |
// ------- |
// |
// thread 3->prio := 5 |
// |
// 3. runs, |
// 3. set a flag to say "3-ran", |
// 3. loop with a sleep(1) until "go-flag" is set. |
// 3. check "got it" is false, |
// 3. then unlock mutex, |
// |
// thread 3->prio := 15 |
// |
// 1. runs, set a flag to say "got it", |
// 1. check "3-ended" flag is false |
// 1. unlock mutex, |
// 1. check "3-ended" flag is still false |
// 1. exit. |
// |
// [1a locks, unlocks, exits] |
// |
// 2. runs, check "3-ran" and "got it" flags are TRUE **** |
// 2. check "3-ended" flag is false |
// 2. sleeps for a while so that... |
// |
// [2a locks, unlocks, exits] |
// |
// 3. runs, set "3-ended" flag, |
// 3. check "3-ran" and "got it" flags |
// 3. exit |
// |
// [3a locks, unlocks, exits] |
// |
// 2. awakens, checks all flags true, |
// 2. check that all "extra" threads that we started have indeed run |
// 2. end of test. |
// |
// |
// |
// |
// NO-INHERIT |
// ---------- |
// thread 1 is waiting on the mutex |
// |
// [1a lock-fail] |
// |
// 2. runs, checks that "3-ran" and "got it" flags are FALSE **** |
// 2. check "3-ended" flag is false |
// 2. sleeps for a while so that... |
// |
// [2a. lock-fail] |
// |
// 3. runs, set a flag to say "3-ran", |
// 3. check "got it" is false, |
// 3. then unlock mutex, |
// |
// 1. runs, set a flag to say "got it", |
// 1. check "3-ended" flag is false |
// 1. unlock mutex, |
// 1. check "3-ended" flag is still false |
// 1. exit. |
// |
// [1a locks, unlocks, exits] |
// [2a locks, unlocks, exits] |
// |
// 3. runs, set "3-ended" flag, |
// 3. check "3-ran" and "got it" flags |
// 3. exit |
// |
// [3a locks, unlocks, exits] |
// |
// 2. awakens, checks all flags true, |
// 2. check that all "extra" threads that we started have indeed run |
// 2. end of test. |
// |
// |
// (the end) |
// |
// |
// ------------------------------------------------------------------------ |
|
// EOF mutex3.c |
/kmutex4.c
0,0 → 1,525
//========================================================================== |
// |
// kmutex4.c |
// |
// Mutex test 4 - dynamic priority inheritance protocol |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): hmt |
// Contributors: hmt |
// Date: 2000-01-06, 2001-08-10, 2001-08-21 |
// Description: Tests mutex priority inheritance. This is an extension of |
// kmutex3.c, to test the new "set the protocol at run-time" |
// extensions. |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/hal.h> |
#include <pkgconf/kernel.h> |
|
#include <cyg/infra/testcase.h> |
|
#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
#include <cyg/infra/diag.h> // diag_printf |
|
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
externC void |
cyg_hal_invoke_constructors(); |
#endif |
|
// ------------------------------------------------------------------------ |
// |
// These checks should be enough; any other scheduler which has priorities |
// should manifest as having no priority inheritance, but otherwise fine, |
// so the test should work correctly. |
|
#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK) && \ |
(CYGNUM_KERNEL_SCHED_PRIORITIES > 20) && \ |
defined(CYGFUN_KERNEL_API_C) && \ |
!defined(CYGPKG_KERNEL_SMP_SUPPORT) && \ |
defined(CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC) \ |
|
#include <cyg/kernel/kapi.h> |
|
#include <cyg/infra/cyg_ass.h> |
#include <cyg/infra/cyg_trac.h> |
#include <cyg/infra/diag.h> // diag_printf |
|
// ------------------------------------------------------------------------ |
|
#define nVERBOSE |
|
// ------------------------------------------------------------------------ |
// We have dynamic protocol choice, so we can set the protocol to whatever |
// we want. We'll do these combinations: |
// NONE |
// INHERIT |
// CEILING = 4 = higher than any thread === INHERIT in behaviour |
// CEILING = 11 = mixed in with threads === cannot check anything |
// CEILING = 17 = lower than any threads === NONE in behaviour |
|
#define PROTO_NONE (0) |
#define PROTO_INHERIT (1) |
#define PROTO_CEILING_HIGH (2) |
#define PROTO_CEILING_MID (3) |
#define PROTO_CEILING_LOW (4) |
|
int proto; |
|
static char * protnames[] = { |
"none", |
"inherit", |
"high ceiling", |
"medium ceiling", |
"low ceiling", |
}; |
|
// ------------------------------------------------------------------------ |
// Management functions |
// |
// Stolen from testaux.hxx and copied in here because I want to be able to |
// reset the world also. |
// |
// Translated into KAPI also. |
|
#define NTHREADS 7 |
|
#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
static cyg_handle_t thread[NTHREADS] = { 0 }; |
|
typedef cyg_uint64 CYG_ALIGNMENT_TYPE; |
|
static cyg_thread thread_obj[NTHREADS]; |
|
static CYG_ALIGNMENT_TYPE stack[NTHREADS] [ |
(STACKSIZE+sizeof(CYG_ALIGNMENT_TYPE)-1) |
/ sizeof(CYG_ALIGNMENT_TYPE) ]; |
|
static volatile int nthreads = 0; |
|
#undef NULL |
#define NULL (0) |
|
static cyg_handle_t new_thread( cyg_thread_entry_t *entry, |
cyg_addrword_t data, |
cyg_addrword_t priority, |
int do_resume, |
char *name ) |
{ |
int _nthreads = nthreads++; |
|
CYG_ASSERT(_nthreads < NTHREADS, |
"Attempt to create more than NTHREADS threads"); |
|
cyg_thread_create( priority, |
entry, |
data, |
name, |
(void *)(stack[_nthreads]), |
STACKSIZE, |
&thread[_nthreads], |
&thread_obj[_nthreads] ); |
|
if ( do_resume ) |
cyg_thread_resume( thread[_nthreads] ); |
|
return thread[_nthreads]; |
} |
|
|
static void kill_threads( void ) |
{ |
CYG_ASSERT(nthreads <= NTHREADS, |
"More than NTHREADS threads"); |
CYG_ASSERT( cyg_thread_self() == thread[0], |
"kill_threads() not called from thread 0"); |
while ( nthreads > 1 ) { |
nthreads--; |
if ( NULL != thread[nthreads] ) { |
do |
cyg_thread_kill( thread[nthreads] ); |
while ( ! cyg_thread_delete ( thread[nthreads] ) ); |
thread[nthreads] = NULL; |
} |
} |
CYG_ASSERT(nthreads == 1, |
"No threads left"); |
} |
|
// ------------------------------------------------------------------------ |
|
#define DELAYFACTOR 1 // for debugging |
|
// ------------------------------------------------------------------------ |
|
static cyg_mutex_t mutex_obj; |
static cyg_mutex_t *mutex; |
|
// These are for reporting back to the master thread |
volatile int got_it = 0; |
volatile int t3ran = 0; |
volatile int t3ended = 0; |
volatile int extras[4] = {0,0,0,0}; |
|
volatile int go_flag = 0; // but this one controls thread 3 from thread 2 |
|
// ------------------------------------------------------------------------ |
// 0 to 3 of these run generally to interfere with the other processing, |
// to cause multiple prio inheritances, and clashes in any orders. |
|
static void extra_thread( cyg_addrword_t data ) |
{ |
cyg_handle_t self = cyg_thread_self(); |
|
|
#ifdef VERBOSE |
#define xXINFO( z ) \ |
do { z[13] = '0' + data; CYG_TEST_INFO( z ); } while ( 0 ) |
|
static char running[] = "Extra thread Xa running"; |
static char exiting[] = "Extra thread Xa exiting"; |
static char resumed[] = "Extra thread Xa resumed"; |
static char locked[] = "Extra thread Xa locked"; |
static char unlocked[] = "Extra thread Xa unlocked"; |
#else |
#define XINFO( z ) /* nothing */ |
#endif |
|
XINFO( running ); |
|
cyg_thread_suspend( self ); |
|
XINFO( resumed ); |
|
cyg_mutex_lock( mutex ); |
|
XINFO( locked ); |
|
cyg_mutex_unlock( mutex ); |
|
XINFO( unlocked ); |
|
extras[ data ] ++; |
|
XINFO( exiting ); |
|
} |
|
// ------------------------------------------------------------------------ |
|
static void t1( cyg_addrword_t data ) |
{ |
cyg_handle_t self = cyg_thread_self(); |
#ifdef VERBOSE |
CYG_TEST_INFO( "Thread 1 running" ); |
#endif |
cyg_thread_suspend( self ); |
|
cyg_mutex_lock( mutex ); |
|
got_it++; |
|
CYG_TEST_CHECK( 0 == t3ended, "T3 ended prematurely [T1,1]" ); |
|
cyg_mutex_unlock( mutex ); |
|
CYG_TEST_CHECK( 0 == t3ended, "T3 ended prematurely [T1,2]" ); |
|
// That's all. |
#ifdef VERBOSE |
CYG_TEST_INFO( "Thread 1 exit" ); |
#endif |
} |
|
// ------------------------------------------------------------------------ |
|
static void t2( cyg_addrword_t data ) |
{ |
cyg_handle_t self = cyg_thread_self(); |
int i; |
cyg_tick_count_t then, now; |
#ifdef VERBOSE |
CYG_TEST_INFO( "Thread 2 running" ); |
#endif |
CYG_TEST_CHECK( 0 == (data & ~0x77), "Bad T2 arg: extra bits" ); |
CYG_TEST_CHECK( 0 == (data & (data >> 4)), "Bad T2 arg: overlap" ); |
|
cyg_thread_suspend( self ); |
|
// depending on our config argument, optionally restart some of the |
// extra threads to throw noise into the scheduler: |
for ( i = 0; i < 3; i++ ) |
if ( (1 << i) & data ) // bits 0-2 control |
cyg_thread_resume( thread[i+4] ); // extras are thread[4-6] |
|
cyg_thread_delay( DELAYFACTOR * 10 ); // let those threads run |
|
cyg_scheduler_lock(); // do this next lot atomically |
|
go_flag = 1; // unleash thread 3 |
cyg_thread_resume( thread[1] ); // resume thread 1 |
|
// depending on our config argument, optionally restart some of the |
// extra threads to throw noise into the scheduler at this later point: |
for ( i = 4; i < 7; i++ ) |
if ( (1 << i) & data ) // bits 4-6 control |
cyg_thread_resume( thread[i] ); // extras are thread[4-6] |
|
cyg_scheduler_unlock(); // let scheduling proceed |
|
// Need a delay (but not a CPU yield) to allow t3 to awaken and act on |
// the go_flag, otherwise we check these details below too soon. |
// Actually, waiting for the clock to tick a couple of times would be |
// better, so that is what we will do. Must be a busy-wait. |
then = cyg_current_time(); |
do { |
now = cyg_current_time(); |
// Wait longer than the delay in t3 waiting on go_flag |
} while ( now < (then + 3) ); |
|
// Check for whatever result we expect from the protocol selected: |
// This mirrors what is done in configury in kmutex3.c and mutex3.cxx |
if ( PROTO_CEILING_MID == proto ) { |
CYG_TEST_INFO( "Not checking: ceiling mid value" ); |
} |
else if ( PROTO_INHERIT == proto || |
PROTO_CEILING_HIGH == proto ) { |
CYG_TEST_INFO( "Checking priority scheme operating" ); |
CYG_TEST_CHECK( 1 == t3ran, "Thread 3 did not run" ); |
CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" ); |
} |
else { |
CYG_TEST_INFO( "Checking NO priority scheme operating" ); |
CYG_TEST_CHECK( 0 == t3ran, "Thread 3 DID run" ); |
CYG_TEST_CHECK( 0 == got_it, "Thread 1 DID get the mutex" ); |
} |
|
CYG_TEST_CHECK( 0 == t3ended, "Thread 3 ended prematurely [T2,1]" ); |
|
cyg_thread_delay( DELAYFACTOR * 20 ); // let those threads run |
|
CYG_TEST_CHECK( 1 == t3ran, "Thread 3 did not run" ); |
CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" ); |
CYG_TEST_CHECK( 1 == t3ended, "Thread 3 has not ended" ); |
|
for ( i = 0; i < 3; i++ ) |
if ( (1 << i) & (data | data >> 4) ) // bits 0-2 and 4-6 control |
CYG_TEST_CHECK( 1 == extras[i+1], "Extra thread did not run" ); |
else |
CYG_TEST_CHECK( 0 == extras[i+1], "Extra thread ran" ); |
|
CYG_TEST_PASS( "Thread 2 exiting, AOK" ); |
// That's all: restart the control thread. |
cyg_thread_resume( thread[0] ); |
} |
|
// ------------------------------------------------------------------------ |
|
static void t3( cyg_addrword_t data ) |
{ |
#ifdef VERBOSE |
CYG_TEST_INFO( "Thread 3 running" ); |
#endif |
cyg_mutex_lock( mutex ); |
|
cyg_thread_delay( DELAYFACTOR * 5 ); // let thread 3a run |
|
cyg_thread_resume( thread[2] ); // resume thread 2 |
|
while ( 0 == go_flag ) |
cyg_thread_delay(1); // wait until we are told to go |
|
t3ran ++; // record the fact |
|
CYG_TEST_CHECK( 0 == got_it, "Thread 1 claims to have got my mutex" ); |
|
cyg_mutex_unlock( mutex ); |
|
t3ended ++; // record that we came back |
|
CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" ); |
#ifdef VERBOSE |
CYG_TEST_INFO( "Thread 3 exit" ); |
#endif |
} |
|
// ------------------------------------------------------------------------ |
|
static void control_thread( cyg_addrword_t data ) |
{ |
cyg_handle_t self = cyg_thread_self(); |
int i, z; |
|
CYG_TEST_INIT(); |
CYG_TEST_INFO( "Control Thread running" ); |
|
// Go through the 27 possibilities of resuming the extra threads |
// 0: not at all |
// 1: early in the process |
// 2: later on |
// which are represented by bits 0-3 and 4-6 resp in the argument to |
// thread 2 (none set means no resume at all). |
for ( i = 0; i < 27; i++ ) { |
static int xx[] = { 0, 1, 16 }; |
int j = i % 3; |
int k = (i / 3) % 3; |
int l = (i / 9) % 3; |
|
int d = xx[j] | (xx[k]<<1) | (xx[l]<<2) ; |
|
if ( cyg_test_is_simulator && (0 != i && 13 != i && 26 != i) ) |
continue; // 13 is 111 base 3, 26 is 222 base 3 |
|
// Go through all these priority inversion prevention protocols: |
// (if supported in this configuration) |
// PROTO_NONE (0) |
// PROTO_INHERIT (1) |
// PROTO_CEILING_HIGH (2) |
// PROTO_CEILING_MID (3) |
// PROTO_CEILING_LOW (4) |
for ( proto = PROTO_NONE; proto <= PROTO_CEILING_LOW; proto++ ) { |
|
// If no priority inheritance at all, running threads 1a and 2a is |
// OK, but not thread 3a; it blocks the world. |
if ( PROTO_NONE == proto || |
PROTO_CEILING_MID == proto || |
PROTO_CEILING_LOW == proto ) |
if ( l ) // Cannot run thread 3a if no |
continue; // priority inheritance at all. |
|
mutex = &mutex_obj; |
|
switch ( proto ) { |
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_NONE |
case PROTO_NONE: |
cyg_mutex_init( mutex ); |
cyg_mutex_set_protocol( mutex, CYG_MUTEX_NONE ); |
break; |
#endif |
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT |
case PROTO_INHERIT: |
cyg_mutex_init( mutex ); |
cyg_mutex_set_protocol( mutex, CYG_MUTEX_INHERIT ); |
break; |
#endif |
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING |
case PROTO_CEILING_HIGH: |
cyg_mutex_init( mutex ); |
cyg_mutex_set_protocol( mutex, CYG_MUTEX_CEILING ); |
cyg_mutex_set_ceiling( mutex, (cyg_priority_t) 4 ); |
break; |
case PROTO_CEILING_MID: |
cyg_mutex_init( mutex ); |
cyg_mutex_set_protocol( mutex, CYG_MUTEX_CEILING ); |
cyg_mutex_set_ceiling( mutex, (cyg_priority_t) 11 ); |
break; |
case PROTO_CEILING_LOW: |
cyg_mutex_init( mutex ); |
cyg_mutex_set_protocol( mutex, CYG_MUTEX_CEILING ); |
cyg_mutex_set_ceiling( mutex, (cyg_priority_t) 17 ); |
break; |
#endif |
default: |
continue; // Break out of the prio for loop - do nothing |
} |
|
got_it = 0; |
t3ran = 0; |
t3ended = 0; |
for ( z = 0; z < 4; z++ ) extras[z] = 0; |
go_flag = 0; |
|
new_thread( t1, 0, 5, 1, "test 1" ); // Slot 1 |
new_thread( t2, d, 10, 1, "test 2" ); // Slot 2 |
new_thread( t3, 0, 15, 1, "test 3" ); // Slot 3 |
|
new_thread( extra_thread, 1, 8, j, "extra 1" ); // Slot 4 |
new_thread( extra_thread, 2, 12, k, "extra 2" ); // Slot 5 |
new_thread( extra_thread, 3, 17, l, "extra 3" ); // Slot 6 |
|
{ |
static char *a[] = { "inactive", "run early", "run late" }; |
diag_printf( "\n----- %s [%2d] New Cycle: 0x%02x, Threads 1a %s, 2a %s, 3a %s -----\n", |
protnames[proto], i, d, a[j], a[k], a[l] ); |
} |
|
cyg_thread_suspend( self ); |
|
kill_threads(); |
cyg_mutex_destroy( mutex ); |
} |
} |
CYG_TEST_EXIT( "Control Thread exit" ); |
} |
|
// ------------------------------------------------------------------------ |
|
externC void |
cyg_user_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
new_thread( control_thread, 0, 2, 1, "control thread" ); |
} |
|
#else // CYGVAR_KERNEL_COUNTERS_CLOCK &c |
|
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_PASS_FINISH("KMutex4 test requires:\n" |
"CYGFUN_KERNEL_API_C &&\n" |
"CYGVAR_KERNEL_COUNTERS_CLOCK &&\n" |
"(CYGNUM_KERNEL_SCHED_PRIORITIES > 20) &&\n" |
"!defined(CYGPKG_KERNEL_SMP_SUPPORT) &&\n" |
"defined(CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC)\n" |
); |
} |
#endif // CYGVAR_KERNEL_COUNTERS_CLOCK &c |
|
|
// ------------------------------------------------------------------------ |
// Documentation: enclosed is the design of this test. |
// |
// See mutex3.cxx or kmutex3.c |
|
// ------------------------------------------------------------------------ |
// EOF mutex4.c |
/kmbox1.c
0,0 → 1,217
/*========================================================================== |
// |
// kmbox1.cxx |
// |
// Kernel Mbox test 1 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author: dsm |
// Contributors: dsm |
// Date: 1998-06-02 |
// Description: Tests basic mbox functionality. |
//####DESCRIPTIONEND#### |
*/ |
|
#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
#include <cyg/kernel/kapi.h> |
|
#include <cyg/infra/testcase.h> |
|
#ifdef CYGFUN_KERNEL_API_C |
|
#include "testaux.h" |
|
#define NTHREADS 2 |
#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
static cyg_handle_t thread[NTHREADS]; |
|
static cyg_thread thread_obj[NTHREADS]; |
static char stack[NTHREADS][STACKSIZE]; |
|
static cyg_handle_t m0, m1, m2; |
static cyg_mbox mbox0, mbox1, mbox2; |
|
static cyg_atomic q = 0; |
|
#ifndef CYGMTH_MBOX_PUT_CAN_WAIT |
#define cyg_mbox_PUT cyg_mbox_tryput |
#endif |
|
static void entry0( cyg_addrword_t data ) |
{ |
cyg_count8 u,i,j; |
|
CYG_TEST_INFO("Testing put() and tryput() without wakeup"); |
CYG_TEST_CHECK(!cyg_mbox_waiting_to_get(m0), "mbox not initialized properly"); |
CYG_TEST_CHECK(0==cyg_mbox_peek(m0), "mbox not initialized properly"); |
CYG_TEST_CHECK(NULL==cyg_mbox_peek_item(m0), "mbox not initialized properly"); |
cyg_mbox_PUT(m0, (void *)55); |
CYG_TEST_CHECK(1==cyg_mbox_peek(m0), "peek() wrong"); |
CYG_TEST_CHECK(55==(cyg_count8)cyg_mbox_peek_item(m0), "peek_item() wrong"); |
for(u=1; cyg_mbox_tryput(m0, (void*)u); u++) { |
CYG_TEST_CHECK(55==(cyg_count8)cyg_mbox_peek_item(m0), "peek_item() wrong"); |
CYG_TEST_CHECK(u+1==cyg_mbox_peek(m0), "peek() wrong"); |
} |
CYG_TEST_CHECK(u == CYGNUM_KERNEL_SYNCH_MBOX_QUEUE_SIZE, "mbox not configured size"); |
|
// m0 now contains ( 55 1 2 .. u-1 ) |
CYG_TEST_CHECK(u==cyg_mbox_peek(m0), "peek() wrong"); |
CYG_TEST_CHECK(55==(cyg_count8)cyg_mbox_peek_item(m0), "peek_item() wrong"); |
|
CYG_TEST_INFO("Testing get(), tryget()"); |
|
i = (cyg_count8)cyg_mbox_tryget(m0); |
CYG_TEST_CHECK( 55 == i, "Got wrong message" ); |
for(j=1; j<u;j++) { |
CYG_TEST_CHECK( j == (cyg_count8)cyg_mbox_peek_item(m0), "peek_item()" ); |
CYG_TEST_CHECK( cyg_mbox_peek(m0) == u - j, "peek() wrong" ); |
i = (cyg_count8)cyg_mbox_get(m0); |
CYG_TEST_CHECK( j == i, "Got wrong message" ); |
} |
|
CYG_TEST_CHECK( NULL == cyg_mbox_peek_item(m0), "peek_item()" ); |
CYG_TEST_CHECK( 0 == cyg_mbox_peek(m0), "peek()"); |
|
// m0 now empty |
|
CYG_TEST_CHECK(!cyg_mbox_waiting_to_put(m0), "waiting_to_put()"); |
CYG_TEST_CHECK(!cyg_mbox_waiting_to_get(m0), "waiting_to_get()"); |
|
CYG_TEST_INFO("Testing get(), blocking"); |
|
CYG_TEST_CHECK(0==q++, "bad synchronization"); |
cyg_mbox_PUT(m1, (void*)99); // wakes t1 |
i = (cyg_count8)cyg_mbox_get(m0); // sent by t1 |
CYG_TEST_CHECK(3==i, "Recieved wrong message"); |
CYG_TEST_CHECK(2==q++, "bad synchronization"); |
|
#ifdef CYGFUN_KERNEL_THREADS_TIMER |
CYG_TEST_CHECK(NULL==cyg_mbox_timed_get(m0, cyg_current_time()+10), |
"unexpectedly found message"); |
CYG_TEST_CHECK(3==q++, "bad synchronization"); |
// Allow t1 to run as this get times out |
// t1 must not be waiting... |
CYG_TEST_CHECK(cyg_mbox_waiting_to_get(m0), "waiting_to_get()"); |
|
cyg_mbox_PUT(m0, (void*)7); // wake t1 from timed get |
#ifdef CYGMTH_MBOX_PUT_CAN_WAIT |
q=10; |
while(cyg_mbox_tryput(m0, (void*)6)) // fill m0's queue |
; |
// m0 now contains ( 6 ... 6 ) |
CYG_TEST_CHECK(10==q++, "bad synchronization"); |
cyg_mbox_put(m1, (void*)4); // wake t1 |
CYG_TEST_CHECK(!cyg_mbox_timed_put(m0, (void*)8, cyg_current_time()+10), |
"timed put() unexpectedly worked"); |
CYG_TEST_CHECK(12==q++, "bad synchronization"); |
// m0 still contains ( 6 ... 6 ) |
cyg_mbox_put(m0, (void*)9); |
CYG_TEST_CHECK(13==q++, "bad synchronization"); |
#endif |
#endif |
i=(cyg_count8)cyg_mbox_get(m2); |
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
static void entry1( cyg_addrword_t data ) |
{ |
cyg_count8 i; |
i = (cyg_count8)cyg_mbox_get(m1); |
CYG_TEST_CHECK(1==q++, "bad synchronization"); |
cyg_mbox_PUT(m0, (void *)3); // wake t0 |
|
#if defined(CYGFUN_KERNEL_THREADS_TIMER) |
CYG_TEST_INFO("Testing timed functions"); |
CYG_TEST_CHECK(7==(cyg_count8)cyg_mbox_timed_get(m0,cyg_current_time()+20), |
"timed get()"); |
CYG_TEST_CHECK(4==q++, "bad synchronization"); |
#ifdef CYGMTH_MBOX_PUT_CAN_WAIT |
CYG_TEST_CHECK(4==(cyg_count8)cyg_mbox_get(m1)); |
|
CYG_TEST_CHECK(11==q++, "bad synchronization"); |
thread[0]->delay(20); // allow t0 to reach put on m1 |
CYG_TEST_CHECK(14==q++, "bad synchronization"); |
CYG_TEST_CHECK(cyg_mbox_waiting_to_put(m0), "waiting_to_put()"); |
do { |
// after first get m0 contains ( 6 .. 6 9 ) |
i=(cyg_count8)cyg_mbox_tryget(m0); |
} while(6==i); |
CYG_TEST_CHECK(9==i,"put gone awry"); |
#endif |
#endif |
CYG_TEST_PASS_FINISH("Kernel C API Mbox 1 OK"); |
} |
|
void kmbox1_main( void ) |
{ |
CYG_TEST_INIT(); |
|
cyg_thread_create(4, entry0 , (cyg_addrword_t)0, "kmbox1-0", |
(void *)stack[0], STACKSIZE, &thread[0], &thread_obj[0]); |
cyg_thread_resume(thread[0]); |
|
cyg_thread_create(4, entry1 , (cyg_addrword_t)1, "kmbox1-1", |
(void *)stack[1], STACKSIZE, &thread[1], &thread_obj[1]); |
cyg_thread_resume(thread[1]); |
|
cyg_mbox_create( &m0, &mbox0 ); |
cyg_mbox_create( &m1, &mbox1 ); |
cyg_mbox_create( &m2, &mbox2 ); |
|
cyg_scheduler_start(); |
|
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
externC void |
cyg_start( void ) |
{ |
kmbox1_main(); |
} |
#else /* def CYGFUN_KERNEL_API_C */ |
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA("Kernel C API layer disabled"); |
} |
#endif /* def CYGFUN_KERNEL_API_C */ |
|
/* EOF kmbox1.c */ |
/mutex0.cxx
0,0 → 1,96
//========================================================================== |
// |
// mutex0.cxx |
// |
// Mutex and condition variable test 0 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-02-24 |
// Description: Limited to checking constructors/destructors |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/mutex.hxx> |
|
#include <cyg/infra/testcase.h> |
|
#include "testaux.hxx" |
|
static Cyg_Mutex mutex0; |
|
static Cyg_Condition_Variable cvar0( mutex0 ); |
|
static bool flash( void ) |
{ |
Cyg_Mutex m0; |
|
CYG_ASSERTCLASSO(m0, "error"); |
|
Cyg_Condition_Variable cv0( m0 ); |
|
CYG_ASSERTCLASSO(cv0, "error"); |
|
return true; |
} |
|
void mutex0_main( void ) |
{ |
CYG_TEST_INIT(); |
|
CHECK(flash()); |
CHECK(flash()); |
|
CYG_ASSERTCLASSO(mutex0, "error"); |
CYG_ASSERTCLASSO(cvar0, "error"); |
|
CYG_TEST_PASS_FINISH("Mutex 0 OK"); |
|
} |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
mutex0_main(); |
} |
// EOF mutex0.cxx |
/klock.c
0,0 → 1,318
/*================================================================= |
// |
// klock.c |
// |
// Kernel lock test |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-03-18 |
// Description: Tests some basic thread functions. |
//####DESCRIPTIONEND#### |
*/ |
//========================================================================== |
|
#include <cyg/kernel/kapi.h> |
|
#include <cyg/infra/testcase.h> |
|
//========================================================================== |
|
#ifdef CYGFUN_KERNEL_API_C |
|
#if (CYGINT_KERNEL_SCHEDULER_UNIQUE_PRIORITIES == 0) |
|
//========================================================================== |
|
#include "testaux.h" |
|
#include <cyg/hal/hal_arch.h> // for CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
//========================================================================== |
|
#ifdef CYGNUM_HAL_STACK_SIZE_TYPICAL |
#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL |
#else |
#define STACKSIZE 2000 |
#endif |
|
//========================================================================== |
|
static char stack[2][STACKSIZE]; |
|
static cyg_thread thread[2]; |
|
static cyg_handle_t pt0,pt1; |
|
static cyg_mutex_t mx; |
static cyg_cond_t cv; |
static cyg_sem_t sem; |
static cyg_flag_t fl; |
static cyg_mbox mbox; |
static cyg_handle_t mbh; |
|
volatile static int thread0_state = 0; |
volatile static int thread1_state = 0; |
|
//========================================================================== |
|
static void entry0( cyg_addrword_t data ) |
{ |
CHECK( 222 == (int)data ); |
|
// Do everything with the scheduler locked. |
cyg_scheduler_lock(); |
|
// -------------------------------------------------- |
// Mutex test |
|
cyg_mutex_lock( &mx ); |
thread0_state = 1; |
|
// Get thread 2 running. |
cyg_thread_resume(pt1); |
thread0_state = 2; |
|
#ifdef CYGMFN_KERNEL_SYNCH_CONDVAR_TIMED_WAIT |
cyg_cond_wait( &cv ); |
thread0_state = 3; |
|
while( thread1_state < 2 ) cyg_thread_yield(); |
|
cyg_cond_broadcast( &cv ); |
thread0_state = 4; |
#endif |
|
cyg_mutex_unlock( &mx ); |
thread0_state = 5; |
|
|
// -------------------------------------------------- |
// Semaphore test |
|
cyg_semaphore_wait( &sem ); |
thread0_state = 6; |
|
cyg_semaphore_post( &sem ); |
thread0_state = 7; |
|
while( thread1_state < 7 ) cyg_thread_yield(); |
|
// -------------------------------------------------- |
// Flags test |
|
cyg_flag_wait( &fl, 1, CYG_FLAG_WAITMODE_OR|CYG_FLAG_WAITMODE_CLR); |
thread0_state = 8; |
|
cyg_flag_setbits( &fl, 2 ); |
thread0_state = 9; |
|
// -------------------------------------------------- |
// Message box test |
|
#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT |
{ |
void *mbret; |
|
mbret = cyg_mbox_get( mbh ); |
CYG_TEST_CHECK( mbret == (void *)0xAAAAAAAA , "bad result from cyg_mbox_timed_get()"); |
thread0_state = 10; |
|
cyg_mbox_put( mbh, (void *)0xBBBBBBBB ); |
thread0_state = 11; |
} |
#endif |
// -------------------------------------------------- |
|
thread0_state = 999; |
|
cyg_thread_yield(); |
cyg_thread_yield(); |
cyg_thread_yield(); |
|
CYG_TEST_CHECK( thread0_state == 999, "thread 0 not in exit state"); |
CYG_TEST_CHECK( thread1_state == 999, "thread 1 not in exit state"); |
CYG_TEST_PASS_FINISH("Kernel lock test OK"); |
} |
|
//========================================================================== |
|
static void entry1( cyg_addrword_t data ) |
{ |
cyg_bool res; |
|
CHECK( 333 == (int)data ); |
|
// Do everything with the scheduler locked. |
cyg_scheduler_lock(); |
|
// -------------------------------------------------- |
// Mutex test |
#ifdef CYGMFN_KERNEL_SYNCH_CONDVAR_TIMED_WAIT |
cyg_mutex_lock( &mx ); |
thread1_state = 1; |
|
while( thread0_state < 2 ) cyg_thread_yield(); |
|
cyg_cond_signal( &cv ); |
thread1_state = 2; |
|
res = cyg_cond_timed_wait( &cv, cyg_current_time()+10 ); |
CYG_TEST_CHECK( res , "FALSE result from cyg_cond_timed_wait()" ); |
thread1_state = 3; |
|
cyg_mutex_unlock( &mx ); |
thread1_state = 4; |
#endif |
|
// -------------------------------------------------- |
// Semaphore test |
|
while( thread0_state < 5 ) cyg_thread_yield(); |
|
cyg_semaphore_post( &sem ); |
thread1_state = 5; |
|
while( thread0_state < 6 ) cyg_thread_yield(); |
thread1_state = 6; |
|
#ifdef CYGFUN_KERNEL_THREADS_TIMER |
res = cyg_semaphore_timed_wait( &sem, cyg_current_time()+10 ); |
#else |
res = cyg_semaphore_wait( &sem ); |
#endif |
CYG_TEST_CHECK( res , "FALSE result from cyg_semaphore[_timed]_wait()" ); |
thread1_state = 7; |
|
// -------------------------------------------------- |
// Flags test |
|
cyg_flag_setbits( &fl, 1 ); |
thread1_state = 8; |
|
#ifdef CYGFUN_KERNEL_THREADS_TIMER |
cyg_flag_timed_wait( &fl, 2, CYG_FLAG_WAITMODE_OR|CYG_FLAG_WAITMODE_CLR, |
cyg_current_time()+10 ); |
#else |
cyg_flag_wait( &fl, 2, CYG_FLAG_WAITMODE_OR|CYG_FLAG_WAITMODE_CLR ); |
#endif |
thread1_state = 9; |
|
// -------------------------------------------------- |
// Message box test |
#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT |
{ |
void *mbret; |
#ifdef CYGFUN_KERNEL_THREADS_TIMER |
cyg_mbox_timed_put( mbh, (void *)0xAAAAAAAA, cyg_current_time()+10 ); |
#else |
cyg_mbox_put( mbh, (void *)0xAAAAAAAA ); |
#endif |
thread1_state = 10; |
|
#ifdef CYGFUN_KERNEL_THREADS_TIMER |
mbret = cyg_mbox_timed_get( mbh, cyg_current_time()+10); |
#else |
mbret = cyg_mbox_get( mbh ); |
#endif |
CYG_TEST_CHECK( mbret == (void *)0xBBBBBBBB , "bad result from cyg_mbox[_timed]_get()"); |
thread1_state = 9; |
} |
#endif |
// -------------------------------------------------- |
|
thread1_state = 999; |
cyg_thread_exit(); |
} |
|
//========================================================================== |
|
void kthread1_main( void ) |
{ |
CYG_TEST_INIT(); |
|
cyg_thread_create(4, entry0, (cyg_addrword_t)222, "kthread1-0", |
(void *)stack[0], STACKSIZE, &pt0, &thread[0] ); |
cyg_thread_create(4, entry1, (cyg_addrword_t)333, "kthread1-1", |
(void *)stack[1], STACKSIZE, &pt1, &thread[1] ); |
|
// Init all the objects |
|
cyg_mutex_init( &mx ); |
cyg_cond_init( &cv, &mx ); |
cyg_semaphore_init( &sem, 0 ); |
cyg_flag_init( &fl ); |
cyg_mbox_create( &mbh, &mbox ); |
|
cyg_thread_resume(pt0); |
|
cyg_scheduler_start(); |
|
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
//========================================================================== |
|
externC void |
cyg_start( void ) |
{ |
kthread1_main(); |
} |
|
//========================================================================== |
|
#else /* CYGINT_KERNEL_SCHEDULER_UNIQUE_PRIORITIES == 0 */ |
# define NA_MSG "Schedule has unique priorities" |
#endif |
|
#else /* def CYGFUN_KERNEL_API_C */ |
# define NA_MSG "Kernel C API layer disabled" |
#endif |
|
#ifdef NA_MSG |
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA(NA_MSG); |
} |
#endif |
|
//========================================================================== |
/* EOF klock.c */ |
/mutex1.cxx
0,0 → 1,162
//========================================================================== |
// |
// mutex1.cxx |
// |
// Mutex test 1 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-02-24 |
// Description: Tests basic mutex functionality. |
// Omissions: Timed wait. |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/sched.hxx> // Cyg_Scheduler::start() |
#include <cyg/kernel/thread.hxx> // Cyg_Thread |
|
#include <cyg/kernel/mutex.hxx> |
|
#include <cyg/infra/testcase.h> |
|
#include <cyg/kernel/sched.inl> |
#include <cyg/kernel/thread.inl> |
|
|
#define NTHREADS 3 |
#include "testaux.hxx" |
|
static Cyg_Mutex m0, m1; |
static Cyg_Condition_Variable cvar0( m0 ), cvar1( m0 ), cvar2( m1 ); |
|
static cyg_ucount8 m0d=0, m1d=0; |
|
static void finish( cyg_ucount8 t ) |
{ |
m1.lock(); { |
m1d |= 1<<t; |
if( 0x7 == m1d ) |
CYG_TEST_PASS_FINISH("Mutex 1 OK"); |
cvar2.wait(); |
} |
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
static void entry0( CYG_ADDRWORD data ) |
{ |
m0.lock(); { |
CHECK( ! m0.trylock() ); |
m1.lock(); { |
CHECK( ! m0.trylock() ); |
} m1.unlock(); |
} m0.unlock(); |
|
m0.lock(); { |
while ( 0 == m0d ) |
cvar0.wait(); |
CHECK( 1 == m0d++ ); |
cvar0.signal(); |
while ( 4 != m0d ) |
cvar1.wait(); |
CHECK( 4 == m0d ); |
} m0.unlock(); |
|
finish( data ); |
} |
|
static void entry1( CYG_ADDRWORD data ) |
{ |
m0.lock(); { |
CHECK( m1.trylock() ); { |
} m1.unlock(); |
} m0.unlock(); |
|
m0.lock(); { |
CHECK( 0 == m0d++ ); |
cvar0.broadcast(); |
} m0.unlock(); |
|
m0.lock(); { |
while( 1 == m0d ) |
cvar0.wait(); |
CHECK( 2 == m0d++ ); |
cvar0.signal(); |
while (3 == m0d ) |
cvar1.wait(); |
} m0.unlock(); |
|
finish( data ); // At most 1 finish inside m0 lock |
} |
|
static void entry2( CYG_ADDRWORD data ) |
{ |
m0.lock(); { |
while( 3 != m0d ) { |
cvar0.wait(); |
} |
CHECK( 3 == m0d++ ); |
cvar1.broadcast(); |
} m0.unlock(); |
|
finish( data ); |
} |
|
void mutex1_main( void ) |
{ |
CYG_TEST_INIT(); |
|
new_thread(entry0, 0); |
new_thread(entry1, 1); |
new_thread(entry2, 2); |
|
Cyg_Scheduler::start(); |
|
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
mutex1_main(); |
} |
// EOF mutex1.cxx |
/kflag0.c
0,0 → 1,99
/*========================================================================== |
// |
// kflag0.cxx |
// |
// Kernel C API Flag test 0 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: hmt |
// Date: 1998-10-19 |
// Description: Limited to checking constructors/destructors |
//####DESCRIPTIONEND#### |
*/ |
|
#include <cyg/kernel/kapi.h> |
|
#include <cyg/infra/testcase.h> |
|
#ifdef CYGFUN_KERNEL_API_C |
|
#include "testaux.h" |
|
cyg_flag_t f0, f1, f2; |
|
static bool flash( void ) |
{ |
cyg_flag_init( &f0 ); |
cyg_flag_init( &f1 ); |
cyg_flag_init( &f2 ); |
|
cyg_flag_destroy( &f0 ); |
cyg_flag_destroy( &f1 ); |
cyg_flag_destroy( &f2 ); |
|
return true; |
} |
|
void kflag0_main( void ) |
{ |
CYG_TEST_INIT(); |
|
CHECK(flash()); |
CHECK(flash()); |
|
CYG_TEST_PASS_FINISH("Kernel C API Flag 0 OK"); |
|
} |
|
externC void |
cyg_start( void ) |
{ |
kflag0_main(); |
} |
|
#else /* def CYGFUN_KERNEL_API_C */ |
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA("Kernel C API layer disabled"); |
} |
#endif /* def CYGFUN_KERNEL_API_C */ |
|
// EOF kflag0.cxx |
/mutex2.cxx
0,0 → 1,273
//========================================================================== |
// |
// mutex1.cxx |
// |
// Mutex test 1 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): nickg |
// Contributors: nickg |
// Date: 1999-02-19 |
// Description: Tests mutex release functionality |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/sched.hxx> // Cyg_Scheduler::start() |
#include <cyg/kernel/thread.hxx> // Cyg_Thread |
|
#include <cyg/kernel/mutex.hxx> |
|
#include <cyg/infra/testcase.h> |
|
#include <cyg/kernel/sched.inl> |
#include <cyg/kernel/thread.inl> |
|
// ------------------------------------------------------------------------ |
|
#if !defined(CYGPKG_KERNEL_SMP_SUPPORT) |
|
// ------------------------------------------------------------------------ |
|
#define NTHREADS 4 |
#include "testaux.hxx" |
#include "testaux.h" |
|
// ------------------------------------------------------------------------ |
|
static Cyg_Mutex m0, m1; |
static Cyg_Condition_Variable cvar0( m0 ), cvar1( m0 ), cvar2( m1 ); |
|
volatile int thread_state[NTHREADS]; |
|
// ------------------------------------------------------------------------ |
// This thread is meant to get hung up trying to re-acquire m0 |
// after waiting on the cv. |
|
static void entry0( CYG_ADDRWORD data ) |
{ |
CYG_TEST_INFO( "thread0: lock mutex 0"); |
|
m0.lock(); |
|
CYG_TEST_INFO( "thread0: wait cvar 0"); |
|
thread_state[data] = 1; |
|
cvar0.wait(); |
|
thread_state[data] = 2; |
|
CYG_TEST_INFO( "thread0: woke from cvar 0"); |
|
CYG_TEST_INFO( "thread0: unlock mutex 0"); |
|
m0.unlock(); |
|
thread_state[data] = 3; |
|
CYG_TEST_INFO( "thread0: exit"); |
|
thread[data]->exit(); |
} |
|
// ------------------------------------------------------------------------ |
// This thread is meant to claim and keep m0. |
|
static void entry1( CYG_ADDRWORD data ) |
{ |
CYG_TEST_INFO( "thread1: lock mutex 0"); |
|
m0.lock(); |
|
CYG_TEST_INFO( "thread1: lock mutex 1"); |
|
thread_state[data] = 1; |
|
m1.lock(); |
|
thread_state[data] = 2; |
|
CYG_TEST_INFO( "thread1: wait cvar 2"); |
|
cvar2.wait(); |
|
thread_state[data] = 3; |
|
CYG_TEST_INFO( "thread1: woke from cvar 2"); |
|
CYG_TEST_INFO( "thread1: unlock mutex 1"); |
|
m1.unlock(); |
|
thread_state[data] = 4; |
|
CYG_TEST_INFO( "thread1: unlock m0"); |
|
m0.unlock(); |
|
thread_state[data] = 5; |
|
CYG_TEST_INFO( "thread1: exit"); |
|
thread[data]->exit(); |
} |
|
// ------------------------------------------------------------------------ |
// This thread is meant to get hung trying to acquire m0, and then get |
// released out of it by thread3. |
|
static void entry2( CYG_ADDRWORD data ) |
{ |
CYG_TEST_INFO( "thread2: lock mutex 0"); |
|
thread_state[data] = 1; |
|
if( m0.lock() ) |
{ |
thread_state[data] = 2; |
|
CYG_TEST_INFO( "thread2: lock mutex 0 - returned TRUE"); |
CYG_TEST_FAIL_FINISH(" m0.lock() returned TRUE" ); |
} |
else |
{ |
thread_state[data] = 3; |
CYG_TEST_INFO( "thread2: lock mutex 0 - returned FALSE"); |
} |
|
CYG_TEST_INFO( "thread2: exit"); |
|
thread[data]->exit(); |
} |
|
// ------------------------------------------------------------------------ |
|
static void entry3( CYG_ADDRWORD data ) |
{ |
|
CHECK( thread_state[0] == 1 ); |
CHECK( thread_state[1] == 2 ); |
CHECK( thread_state[2] == 1 ); |
|
CYG_TEST_INFO( "thread3: signal cvar 0"); |
|
cvar0.signal(); |
|
CHECK( thread_state[0] == 1 ); |
CHECK( thread_state[1] == 2 ); |
CHECK( thread_state[2] == 1 ); |
|
CYG_TEST_INFO( "thread3: release mutex 0"); |
|
m0.release(); |
|
CHECK( thread_state[0] == 1 ); |
CHECK( thread_state[1] == 2 ); |
CHECK( thread_state[2] == 3 ); |
|
CYG_TEST_INFO( "thread3: signal cvar 2"); |
|
cvar2.signal(); |
|
CHECK( thread_state[0] == 3 ); |
CHECK( thread_state[1] == 5 ); |
CHECK( thread_state[2] == 3 ); |
|
CYG_TEST_PASS_FINISH( "mutex2 finished OK"); |
|
CYG_TEST_INFO( "thread3: exit"); |
|
thread[data]->exit(); |
} |
|
// ------------------------------------------------------------------------ |
|
void mutex2_main( void ) |
{ |
CYG_TEST_INIT(); |
|
new_thread(entry0, 0); |
new_thread(entry1, 1); |
new_thread(entry2, 2); |
new_thread(entry3, 3); |
|
// Set priorities from the top to prevent two threads getting |
// the same priority: this causes an ASSERT on some configurations. |
thread[3]->set_priority( 5 ); |
thread[2]->set_priority( 4 ); |
thread[1]->set_priority( 3 ); |
thread[0]->set_priority( 2 ); |
|
Cyg_Scheduler::start(); |
|
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
// ------------------------------------------------------------------------ |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
mutex2_main(); |
} |
|
// ------------------------------------------------------------------------ |
|
#else // CYGPKG_KERNEL_SMP_SUPPORT |
|
// ------------------------------------------------------------------------ |
|
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_PASS_FINISH("Mutex2 test requires:\n" |
"!defined(CYGPKG_KERNEL_SMP_SUPPORT)\n"); |
|
} |
|
// ------------------------------------------------------------------------ |
|
#endif // CYGPKG_KERNEL_SMP_SUPPORT |
|
// ------------------------------------------------------------------------ |
// EOF mutex2.cxx |
/mutex3.cxx
0,0 → 1,630
//========================================================================== |
// |
// mutex3.cxx |
// |
// Mutex test 3 - priority inheritance |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): hmt |
// Contributors: hmt |
// Date: 2000-01-06 |
// Description: Tests mutex priority inheritance |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/hal.h> |
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/sched.hxx> // Cyg_Scheduler::start() |
#include <cyg/kernel/thread.hxx> // Cyg_Thread |
|
#include <cyg/kernel/mutex.hxx> |
|
#include <cyg/infra/testcase.h> |
|
#include <cyg/kernel/sched.inl> |
#include <cyg/kernel/thread.inl> |
|
#include <cyg/infra/diag.h> // diag_printf |
|
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
externC void |
cyg_hal_invoke_constructors(); |
#endif |
|
// ------------------------------------------------------------------------ |
// |
// These checks should be enough; any other scheduler which has priorities |
// should manifest as having no priority inheritance, but otherwise fine, |
// so the test should work correctly. |
|
#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK) && \ |
(CYGNUM_KERNEL_SCHED_PRIORITIES > 20) && \ |
!defined(CYGPKG_KERNEL_SMP_SUPPORT) |
|
// ------------------------------------------------------------------------ |
// Manufacture a simpler feature test macro for priority inheritance than |
// the configuration gives us. We have priority inheritance if it is configured |
// as the only protocol, or if it is the default protocol for dynamic protocol |
// choice. |
// FIXME: If we have dynamic protocol choice, we can also set priority inheritance |
// as the protocol to be used on the mutexes we are interested in. At present we |
// do not do this. |
|
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT |
# ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC |
# ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_INHERIT |
# define PRIORITY_INHERITANCE "dynamic-default-inherit" |
# endif |
# else |
# define PRIORITY_INHERITANCE "static-inherit" |
# endif |
#endif |
|
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING |
# ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC |
# ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_CEILING |
# if CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY <= 5 |
# define PRIORITY_INHERITANCE "dynamic-default-ceiling-high" |
# elif CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY >= 15 |
# define NO_PRIORITY_INHERITANCE "dynamic-default-ceiling-low" |
# else |
# define PRIORITY_UNKNOWN "dynamic-default-ceiling-mid" |
# endif |
# endif |
# else |
# if CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY <= 5 |
# define PRIORITY_INHERITANCE "static-ceiling-high" |
# elif CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY >= 15 |
# define NO_PRIORITY_INHERITANCE "static-ceiling-low" |
# else |
# define PRIORITY_UNKNOWN "static-ceiling-mid" |
# endif |
# endif |
#endif |
|
#ifndef PRIORITY_INHERITANCE |
# ifndef NO_PRIORITY_INHERITANCE |
# define NO_PRIORITY_INHERITANCE "no scheme selected" |
# endif |
#endif |
|
// ------------------------------------------------------------------------ |
// Management functions |
// |
// Stolen from testaux.hxx and copied in here because I want to be able to |
// reset the world also. |
|
#define NTHREADS 7 |
|
static inline void *operator new(size_t size, void *ptr) { return ptr; }; |
|
#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
static Cyg_Thread *thread[NTHREADS] = { 0 }; |
|
typedef CYG_WORD64 CYG_ALIGNMENT_TYPE; |
|
static CYG_ALIGNMENT_TYPE thread_obj[NTHREADS] [ |
(sizeof(Cyg_Thread)+sizeof(CYG_ALIGNMENT_TYPE)-1) |
/ sizeof(CYG_ALIGNMENT_TYPE) ]; |
|
static CYG_ALIGNMENT_TYPE stack[NTHREADS] [ |
(STACKSIZE+sizeof(CYG_ALIGNMENT_TYPE)-1) |
/ sizeof(CYG_ALIGNMENT_TYPE) ]; |
|
static volatile int nthreads = 0; |
|
static Cyg_Thread *new_thread( cyg_thread_entry *entry, |
CYG_ADDRWORD data, |
CYG_ADDRWORD priority, |
int do_resume ) |
{ |
int _nthreads = nthreads++; |
|
CYG_ASSERT(_nthreads < NTHREADS, |
"Attempt to create more than NTHREADS threads"); |
|
thread[_nthreads] = new( (void *)&thread_obj[_nthreads] ) |
Cyg_Thread(priority, |
entry, data, |
NULL, // no name |
(CYG_ADDRESS)stack[_nthreads], STACKSIZE ); |
|
if ( do_resume ) |
thread[_nthreads]->resume(); |
|
return thread[_nthreads]; |
} |
|
|
static void kill_threads( void ) |
{ |
CYG_ASSERT(nthreads <= NTHREADS, |
"More than NTHREADS threads"); |
CYG_ASSERT( Cyg_Thread::self() == thread[0], |
"kill_threads() not called from thread 0"); |
while ( nthreads > 1 ) { |
nthreads--; |
if ( NULL != thread[nthreads] ) { |
thread[nthreads]->kill(); |
thread[nthreads]->~Cyg_Thread(); |
thread[nthreads] = NULL; |
} |
} |
CYG_ASSERT(nthreads == 1, |
"No threads left"); |
} |
|
// ------------------------------------------------------------------------ |
|
#define DELAYFACTOR 1 // for debugging |
|
// ------------------------------------------------------------------------ |
|
static Cyg_Mutex mutex; |
|
// These are for reporting back to the master thread |
volatile int got_it = 0; |
volatile int t3ran = 0; |
volatile int t3ended = 0; |
volatile int extras[4] = {0,0,0,0}; |
|
volatile int go_flag = 0; // but this one controls thread 3 from thread 2 |
|
// ------------------------------------------------------------------------ |
// 0 to 3 of these run generally to interfere with the other processing, |
// to cause multiple prio inheritances, and clashes in any orders. |
|
static void extra_thread( CYG_ADDRWORD data ) |
{ |
#define XINFO( z ) \ |
do { z[13] = '0' + data; CYG_TEST_INFO( z ); } while ( 0 ) |
|
static char running[] = "Extra thread Xa running"; |
static char exiting[] = "Extra thread Xa exiting"; |
static char resumed[] = "Extra thread Xa resumed"; |
static char locked[] = "Extra thread Xa locked"; |
static char unlocked[] = "Extra thread Xa unlocked"; |
|
XINFO( running ); |
|
Cyg_Thread *self = Cyg_Thread::self(); |
|
self->suspend(); |
|
XINFO( resumed ); |
|
mutex.lock(); |
|
XINFO( locked ); |
|
mutex.unlock(); |
|
XINFO( unlocked ); |
|
extras[ data ] ++; |
|
XINFO( exiting ); |
|
} |
|
// ------------------------------------------------------------------------ |
|
static void t1( CYG_ADDRWORD data ) |
{ |
Cyg_Thread *self = Cyg_Thread::self(); |
|
CYG_TEST_INFO( "Thread 1 running" ); |
|
self->suspend(); |
|
mutex.lock(); |
|
got_it++; |
|
CYG_TEST_CHECK( 0 == t3ended, "T3 ended prematurely [T1,1]" ); |
|
mutex.unlock(); |
|
CYG_TEST_CHECK( 0 == t3ended, "T3 ended prematurely [T1,2]" ); |
|
// That's all. |
|
CYG_TEST_INFO( "Thread 1 exit" ); |
} |
|
// ------------------------------------------------------------------------ |
|
static void t2( CYG_ADDRWORD data ) |
{ |
Cyg_Thread *self = Cyg_Thread::self(); |
int i; |
cyg_tick_count then, now; |
|
|
CYG_TEST_INFO( "Thread 2 running" ); |
|
CYG_TEST_CHECK( 0 == (data & ~0x77), "Bad T2 arg: extra bits" ); |
CYG_TEST_CHECK( 0 == (data & (data >> 4)), "Bad T2 arg: overlap" ); |
|
self->suspend(); |
|
// depending on our config argument, optionally restart some of the |
// extra threads to throw noise into the scheduler: |
for ( i = 0; i < 3; i++ ) |
if ( (1 << i) & data ) // bits 0-2 control |
thread[i+4]->resume(); // made sure extras are thread[4-6] |
|
self->delay( DELAYFACTOR * 10 ); // let those threads run |
|
Cyg_Scheduler::lock(); // do this next lot atomically |
|
go_flag = 1; // unleash thread 3 |
thread[1]->resume(); // resume thread 1 |
|
// depending on our config argument, optionally restart some of the |
// extra threads to throw noise into the scheduler at this later point: |
for ( i = 4; i < 7; i++ ) |
if ( (1 << i) & data ) // bits 4-6 control |
thread[i]->resume(); // made sure extras are thread[4-6] |
|
Cyg_Scheduler::unlock(); // let scheduling proceed |
|
// Need a delay (but not a CPU yield) to allow t3 to awaken and act on |
// the go_flag, otherwise we check these details below too soon. |
// Actually, waiting for the clock to tick a couple of times would be |
// better, so that is what we will do. Must be a busy-wait. |
then = Cyg_Clock::real_time_clock->current_value(); |
do { |
now = Cyg_Clock::real_time_clock->current_value(); |
// Wait longer than the delay in t3 waiting on go_flag |
} while ( now < (then + 3) ); |
|
#ifdef PRIORITY_UNKNOWN |
CYG_TEST_INFO( "Not checking: " PRIORITY_UNKNOWN ); |
#else |
#ifdef PRIORITY_INHERITANCE |
CYG_TEST_INFO( "Checking priority scheme: " PRIORITY_INHERITANCE ); |
CYG_TEST_CHECK( 1 == t3ran, "Thread 3 did not run" ); |
CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" ); |
#else |
CYG_TEST_INFO( "Checking NO priority scheme: " NO_PRIORITY_INHERITANCE ); |
CYG_TEST_CHECK( 0 == t3ran, "Thread 3 DID run" ); |
CYG_TEST_CHECK( 0 == got_it, "Thread 1 DID get the mutex" ); |
#endif |
#endif |
|
CYG_TEST_CHECK( 0 == t3ended, "Thread 3 ended prematurely [T2,1]" ); |
|
self->delay( DELAYFACTOR * 20 ); // let those threads run |
|
CYG_TEST_CHECK( 1 == t3ran, "Thread 3 did not run" ); |
CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" ); |
CYG_TEST_CHECK( 1 == t3ended, "Thread 3 has not ended" ); |
|
for ( i = 0; i < 3; i++ ) |
if ( (1 << i) & (data | data >> 4) ) // bits 0-2 and 4-6 control |
CYG_TEST_CHECK( 1 == extras[i+1], "Extra thread did not run" ); |
else |
CYG_TEST_CHECK( 0 == extras[i+1], "Extra thread ran" ); |
|
CYG_TEST_PASS( "Thread 2 exiting, AOK" ); |
// That's all: restart the control thread. |
thread[0]->resume(); |
} |
|
// ------------------------------------------------------------------------ |
|
static void t3( CYG_ADDRWORD data ) |
{ |
Cyg_Thread *self = Cyg_Thread::self(); |
|
CYG_TEST_INFO( "Thread 3 running" ); |
|
mutex.lock(); |
|
self->delay( DELAYFACTOR * 5 ); // let thread 3a run |
|
thread[2]->resume(); // resume thread 2 |
|
while ( 0 == go_flag ) |
self->delay(1); // wait until we are told to go |
|
t3ran ++; // record the fact |
|
CYG_TEST_CHECK( 0 == got_it, "Thread 1 claims to have got my mutex" ); |
|
mutex.unlock(); |
|
t3ended ++; // record that we came back |
|
CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" ); |
|
CYG_TEST_INFO( "Thread 3 exit" ); |
} |
|
// ------------------------------------------------------------------------ |
|
static void control_thread( CYG_ADDRWORD data ) |
{ |
Cyg_Thread *self = Cyg_Thread::self(); |
int i; |
|
CYG_TEST_INIT(); |
CYG_TEST_INFO( "Control Thread running" ); |
|
// Go through the 27 possibilitied of resuming the extra threads |
// 0: not at all |
// 1: early in the process |
// 2: later on |
// which are represented by bits 0-3 and 4-6 resp in the argument to |
// thread 2 (none set means no resume at all). |
for ( i = 0; i < 27; i++ ) { |
static int xx[] = { 0, 1, 16 }; |
int j = i % 3; |
int k = (i / 3) % 3; |
int l = (i / 9) % 3; |
|
int d = xx[j] | (xx[k]<<1) | (xx[l]<<2) ; |
|
if ( cyg_test_is_simulator && (0 != i && 13 != i && 26 != i) ) |
continue; // 13 is 111 base 3, 26 is 222 base 3 |
|
#ifdef PRIORITY_INHERITANCE |
// If the simple scheme plus relay enhancement, or any other |
// *complete* scheme, we can run all three ancillary threads no |
// problem, so no special action here. |
|
#else |
// If no priority inheritance at all, running threads 1a and 2a is |
// OK, but not thread 3a; it blocks the world. |
if ( l ) // Cannot run thread 3a if no |
break; // priority inheritance at all. |
#endif |
|
mutex = Cyg_Mutex(); // Reinitialize this |
|
got_it = 0; |
t3ran = 0; |
t3ended = 0; |
for ( int z = 0; z < 4; z++ ) extras[z] = 0; |
go_flag = 0; |
|
new_thread( t1, 0, 5, 1 ); // Slot 1 |
new_thread( t2, d, 10, 1 ); // Slot 2 |
new_thread( t3, 0, 15, 1 ); // Slot 3 |
|
new_thread( extra_thread, 1, 8, j ); // Slot 4 |
new_thread( extra_thread, 2, 12, k ); // Slot 5 |
new_thread( extra_thread, 3, 17, l ); // Slot 6 |
|
{ |
static char *a[] = { "inactive", "run early", "run late" }; |
diag_printf( "\n----- [%2d] New Cycle: 0x%02x, Threads 1a %s, 2a %s, 3a %s -----\n", |
i, d, a[j], a[k], a[l] ); |
} |
|
self->suspend(); |
|
kill_threads(); |
mutex.~Cyg_Mutex(); |
} |
CYG_TEST_EXIT( "Control Thread exit" ); |
} |
|
// ------------------------------------------------------------------------ |
|
externC void |
cyg_user_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
new_thread( control_thread, 0, 2, 1 ); |
} |
|
#else // CYGVAR_KERNEL_COUNTERS_CLOCK &c |
|
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_PASS_FINISH("Mutex3 test requires:\n" |
"CYGVAR_KERNEL_COUNTERS_CLOCK &&\n" |
"(CYGNUM_KERNEL_SCHED_PRIORITIES > 20) &&\n" |
"!defined(CYGPKG_KERNEL_SMP_SUPPORT)\n"); |
} |
#endif // CYGVAR_KERNEL_COUNTERS_CLOCK &c |
|
|
// ------------------------------------------------------------------------ |
// Documentation: enclosed is the design of this test. |
// |
// It has been carefully constructed so that it does NOT use other kernel |
// facilities (aside from delay-task) to test that priority inheritance is |
// working, or not, as intended by the configuration. |
// |
// These notes describe the flow of control in one run of the test with the |
// ancillary tasks optionally interspersed. The details of how those extra |
// tasks are or are not allowed to run are not described. |
// |
// |
// |
// The only change in the test that depends on whether there is inheritance or |
// not is the check in thread 2 on "3-ran" and "got it" flags marked **** |
// |
// |
// volatile &c booleans: |
// "got it" = FALSE |
// "3-ran" = FALSE |
// "3-ended" = FALSE |
// "extras"[3] = FALSE |
// |
// thread 1. prio 5, self-suspend. |
// |
// thread 1a, prio 8, self-suspend. |
// |
// thread 2. prio 10, self-suspend. |
// |
// thread 2a, prio 12, self-suspend. |
// |
// thread 3. prio 15, runs, lock mutex, resume(2) |
// |
// thread 3a, prio 17, self-suspend. |
// |
// 2. runs, |
// 2. resume(3a) +++OPTIONAL |
// 2. resume(2a) +++OPTIONAL |
// 2. resume(1a) +++OPTIONAL |
// [1a lock-fail] thread 3->prio := 8 |
// |
// [3. runs maybe, does the looping thing] |
// |
// 2. sleep a while... |
// |
// [2a lock-fail] thread 3->prio := 12 |
// |
// [3. runs maybe, does the looping thing] |
// |
// [3a lock-fail] thread 3->prio unchanged |
// |
// [3. runs maybe, does the looping thing] |
// |
// 2. lock scheduler |
// 2. set "go-flag" |
// 2. resume(1) |
// 2. resume(1a) +++OPTIONAL |
// 2. resume(2a) +++OPTIONAL |
// 2. resume(3a) +++OPTIONAL |
// 2. unlock scheduler |
// |
// 1. runs, lock mutex - thread 3 has it locked |
// |
// 2. busy-waits a bit for thread 3 to come out of its delay() loop. |
// This must be a *busy*wait so that 3 can only run via the |
// inherited raised priority. |
// |
// [xa. all do the same: lock mutex, ] |
// [xa. unlock mutex ] |
// [xa. set a flag "extras"[x] to say we are done. ] |
// [xa. exit ] |
// |
// |
// |
// INHERIT |
// ------- |
// |
// thread 3->prio := 5 |
// |
// 3. runs, |
// 3. set a flag to say "3-ran", |
// 3. loop with a sleep(1) until "go-flag" is set. |
// 3. check "got it" is false, |
// 3. then unlock mutex, |
// |
// thread 3->prio := 15 |
// |
// 1. runs, set a flag to say "got it", |
// 1. check "3-ended" flag is false |
// 1. unlock mutex, |
// 1. check "3-ended" flag is still false |
// 1. exit. |
// |
// [1a locks, unlocks, exits] |
// |
// 2. runs, check "3-ran" and "got it" flags are TRUE **** |
// 2. check "3-ended" flag is false |
// 2. sleeps for a while so that... |
// |
// [2a locks, unlocks, exits] |
// |
// 3. runs, set "3-ended" flag, |
// 3. check "3-ran" and "got it" flags |
// 3. exit |
// |
// [3a locks, unlocks, exits] |
// |
// 2. awakens, checks all flags true, |
// 2. check that all "extra" threads that we started have indeed run |
// 2. end of test. |
// |
// |
// |
// |
// NO-INHERIT |
// ---------- |
// thread 1 is waiting on the mutex |
// |
// [1a lock-fail] |
// |
// 2. runs, checks that "3-ran" and "got it" flags are FALSE **** |
// 2. check "3-ended" flag is false |
// 2. sleeps for a while so that... |
// |
// [2a. lock-fail] |
// |
// 3. runs, set a flag to say "3-ran", |
// 3. check "got it" is false, |
// 3. then unlock mutex, |
// |
// 1. runs, set a flag to say "got it", |
// 1. check "3-ended" flag is false |
// 1. unlock mutex, |
// 1. check "3-ended" flag is still false |
// 1. exit. |
// |
// [1a locks, unlocks, exits] |
// [2a locks, unlocks, exits] |
// |
// 3. runs, set "3-ended" flag, |
// 3. check "3-ran" and "got it" flags |
// 3. exit |
// |
// [3a locks, unlocks, exits] |
// |
// 2. awakens, checks all flags true, |
// 2. check that all "extra" threads that we started have indeed run |
// 2. end of test. |
// |
// |
// (the end) |
// |
// |
// ------------------------------------------------------------------------ |
|
// EOF mutex3.cxx |
/kflag1.c
0,0 → 1,244
/*========================================================================== |
// |
// kflag1.cxx |
// |
// Kernel C API Flag test 1 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author: dsm |
// Contributors: hmt |
// Date: 1998-10-19 |
// Description: Tests basic flag functionality. |
//####DESCRIPTIONEND#### |
*/ |
|
#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
#include <cyg/kernel/kapi.h> |
|
#include <cyg/infra/testcase.h> |
|
#ifdef CYGFUN_KERNEL_API_C |
|
#include "testaux.h" |
|
|
#define NTHREADS 3 |
#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
static cyg_handle_t thread[NTHREADS]; |
|
static cyg_thread thread_obj[NTHREADS]; |
static char stack[NTHREADS][STACKSIZE]; |
|
static cyg_flag_t f0, f1; |
#ifdef CYGFUN_KERNEL_THREADS_TIMER |
static cyg_flag_t f2; |
#endif |
|
static volatile cyg_ucount8 q = 0; |
#define FIRST_THREAD_WAIT_TIME 5 |
#define SECOND_THREAD_WAIT_TIME 10 |
#define THIRD_THREAD_WAIT_TIME 20 |
|
static void entry0( cyg_addrword_t data ) |
{ |
CYG_TEST_INFO("Testing cyg_flag_setbits() and cyg_flag_maskbits()"); |
CYG_TEST_CHECK(0==cyg_flag_peek( &f0 ), "flag not initialized properly"); |
cyg_flag_setbits( &f0, 0x1); |
CYG_TEST_CHECK(1==cyg_flag_peek( &f0 ), "setbits"); |
cyg_flag_setbits( &f0, 0x3); |
CYG_TEST_CHECK(3==cyg_flag_peek( &f0 ), "setbits"); |
cyg_flag_maskbits( &f0, ~0x5); |
CYG_TEST_CHECK(2==cyg_flag_peek( &f0 ), "maskbits"); |
cyg_flag_setbits( &f0, ~0 ); |
CYG_TEST_CHECK(~0u==cyg_flag_peek( &f0 ), "setbits all set"); |
cyg_flag_maskbits( &f0, 0 ); |
CYG_TEST_CHECK(0==cyg_flag_peek( &f0 ), "maskbits all clear"); |
CYG_TEST_CHECK(0==q++, "bad synchronization"); |
|
CYG_TEST_INFO("Testing cyg_flag_wait()"); |
cyg_flag_setbits( &f1, 0x4); |
CYG_TEST_CHECK(0x4==cyg_flag_peek( &f1 ), "setbits"); |
CYG_TEST_CHECK(1==q++, "bad synchronization"); |
cyg_flag_setbits( &f1, 0x18); // wake t1 |
cyg_flag_wait( &f1, 0x11, CYG_FLAG_WAITMODE_AND | CYG_FLAG_WAITMODE_CLR); |
CYG_TEST_CHECK(0==cyg_flag_peek( &f1 ), "flag value wrong"); |
CYG_TEST_CHECK(3==q++, "bad synchronization"); |
cyg_flag_setbits( &f0, 0x2); // wake t1 |
cyg_flag_wait( &f1, 0x10, CYG_FLAG_WAITMODE_AND ); |
cyg_flag_setbits( &f0, 0x1); // wake t1 |
|
cyg_flag_wait( &f1, 0x11, CYG_FLAG_WAITMODE_AND | CYG_FLAG_WAITMODE_CLR); |
|
#ifdef CYGFUN_KERNEL_THREADS_TIMER |
cyg_flag_wait( &f2, 0x2, CYG_FLAG_WAITMODE_OR); |
CYG_TEST_CHECK(20==q,"bad synchronization"); |
cyg_flag_timed_wait( &f2, 0x10, CYG_FLAG_WAITMODE_AND, |
cyg_current_time()+THIRD_THREAD_WAIT_TIME); |
CYG_TEST_CHECK(21==q++,"bad synchronization"); |
#endif |
cyg_flag_wait( &f0, 1, CYG_FLAG_WAITMODE_OR); |
|
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
static void entry1( cyg_addrword_t data ) |
{ |
cyg_flag_wait( &f1, 0xc, CYG_FLAG_WAITMODE_AND); |
CYG_TEST_CHECK(2==q++, "bad synchronization"); |
CYG_TEST_CHECK(0x1c==cyg_flag_peek( &f1 ), "flag value wrong"); |
cyg_flag_setbits( &f1, 0x1); // wake t0 |
cyg_flag_wait( &f0, 0x3, CYG_FLAG_WAITMODE_OR); |
CYG_TEST_CHECK(4==q++, "bad synchronization"); |
CYG_TEST_CHECK(2==cyg_flag_peek( &f0 ), "flag value wrong"); |
|
cyg_flag_setbits( &f1, 0xf0); // wake t0,t2 |
cyg_flag_wait( &f0, 0x5, CYG_FLAG_WAITMODE_AND | CYG_FLAG_WAITMODE_CLR); |
CYG_TEST_CHECK(0==cyg_flag_peek( &f0 ), "flag value wrong"); |
CYG_TEST_CHECK(0xf0==cyg_flag_peek( &f1 ), "flag value wrong"); |
CYG_TEST_CHECK(5==q++, "bad synchronization"); |
cyg_flag_maskbits( &f1, 0 ); |
CYG_TEST_CHECK(0==cyg_flag_peek( &f1 ), "flag value wrong"); |
|
CYG_TEST_INFO("Testing cyg_flag_poll()"); |
cyg_flag_setbits( &f0, 0x55); |
CYG_TEST_CHECK(0x55==cyg_flag_peek( &f0 ), "flag value wrong"); |
CYG_TEST_CHECK(0x55==cyg_flag_poll( &f0, 0x3, CYG_FLAG_WAITMODE_OR),"bad poll() return"); |
CYG_TEST_CHECK(0==cyg_flag_poll( &f0, 0xf, CYG_FLAG_WAITMODE_AND),"poll()"); |
CYG_TEST_CHECK(0==cyg_flag_poll( &f0, 0xa, CYG_FLAG_WAITMODE_OR),"poll()"); |
CYG_TEST_CHECK(0x55==cyg_flag_peek( &f0 ), "flag value wrong"); |
CYG_TEST_CHECK(0x55==cyg_flag_poll( &f0, 0xf, CYG_FLAG_WAITMODE_OR | CYG_FLAG_WAITMODE_CLR),"poll"); |
CYG_TEST_CHECK(0x0==cyg_flag_peek( &f0 ), "flag value wrong"); |
cyg_flag_setbits( &f0, 0x50); |
CYG_TEST_CHECK(0x50==cyg_flag_poll( &f0, 0x10, CYG_FLAG_WAITMODE_AND | CYG_FLAG_WAITMODE_CLR),"poll"); |
CYG_TEST_CHECK(0x0==cyg_flag_peek( &f0 ), "flag value wrong"); |
|
CYG_TEST_INFO("Testing cyg_flag_waiting()"); |
cyg_flag_maskbits( &f0, 0 ); |
CYG_TEST_CHECK(!cyg_flag_waiting( &f0 ), "waiting()"); |
|
#ifdef CYGFUN_KERNEL_THREADS_TIMER |
cyg_thread_delay( 10 ); // allow other threads to reach wait on f1 |
CYG_TEST_CHECK(cyg_flag_waiting( &f1 ), "waiting() not true"); |
cyg_flag_setbits( &f1, ~0 ); // wake one of t0,t2 |
CYG_TEST_CHECK(cyg_flag_waiting( &f1 ),"waiting() not true"); |
#else |
cyg_flag_setbits( &f1, 0x11); // wake one of t0,t2 |
#endif |
cyg_flag_setbits( &f1, 0x11); // wake other of t0,t2 |
CYG_TEST_CHECK(!cyg_flag_waiting( &f1 ),"waiting not false"); |
CYG_TEST_CHECK(0x0==cyg_flag_peek( &f1 ), "flag value wrong"); |
|
#ifdef CYGFUN_KERNEL_THREADS_TIMER |
CYG_TEST_INFO("Testing cyg_flag_timed_wait()"); |
q=20; |
cyg_flag_setbits( &f2, 0x2); // synchronize with t0,t2 |
CYG_TEST_CHECK(20==q,"bad synchronization"); |
cyg_flag_timed_wait( &f2, 0x20, CYG_FLAG_WAITMODE_AND, |
cyg_current_time()+SECOND_THREAD_WAIT_TIME); |
CYG_TEST_CHECK(22==q++,"bad synchronization"); |
#endif |
|
CYG_TEST_PASS_FINISH("Kernel C API Flag 1 OK"); |
} |
|
static void entry2( cyg_addrword_t data ) |
{ |
cyg_flag_wait( &f1, 0x60, CYG_FLAG_WAITMODE_OR); |
cyg_flag_setbits( &f0, 0x4); |
|
cyg_flag_wait( &f1, 0x11, CYG_FLAG_WAITMODE_AND | CYG_FLAG_WAITMODE_CLR); |
#ifdef CYGFUN_KERNEL_THREADS_TIMER |
cyg_flag_wait( &f2, 0x2, CYG_FLAG_WAITMODE_OR); |
CYG_TEST_CHECK(20==q,"bad synchronization"); |
CYG_TEST_CHECK(0==cyg_flag_timed_wait( &f2, 0x40, CYG_FLAG_WAITMODE_AND, |
cyg_current_time()+FIRST_THREAD_WAIT_TIME), |
"timed wait() wrong"); |
CYG_TEST_CHECK(20==q++,"bad synchronization"); |
// Now wake t0 before it times out |
cyg_flag_setbits( &f2, 0x10); |
#endif |
cyg_flag_wait( &f0, 1, CYG_FLAG_WAITMODE_OR); |
|
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
void kflag1_main( void ) |
{ |
CYG_TEST_INIT(); |
|
cyg_flag_init( &f0 ); |
cyg_flag_init( &f1 ); |
#ifdef CYGFUN_KERNEL_THREADS_TIMER |
cyg_flag_init( &f2 ); |
#endif |
|
cyg_thread_create( 1, entry0 , (cyg_addrword_t)0, "kflag1-0", |
(void *)stack[0], STACKSIZE, &thread[0], &thread_obj[0]); |
cyg_thread_resume(thread[0]); |
|
cyg_thread_create( 1, entry1 , (cyg_addrword_t)1, "kflag1-1", |
(void *)stack[1], STACKSIZE, &thread[1], &thread_obj[1]); |
cyg_thread_resume(thread[1]); |
|
cyg_thread_create( 1, entry2 , (cyg_addrword_t)2, "kflag1-2", |
(void *)stack[2], STACKSIZE, &thread[2], &thread_obj[2]); |
cyg_thread_resume(thread[2]); |
|
cyg_scheduler_start(); |
|
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
externC void |
cyg_start( void ) |
{ |
kflag1_main(); |
} |
|
#else /* def CYGFUN_KERNEL_API_C */ |
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA("Kernel C API layer disabled"); |
} |
#endif /* def CYGFUN_KERNEL_API_C */ |
|
// EOF flag1.cxx |
/fptest.c
0,0 → 1,354
//========================================================================== |
// |
// fptest.cxx |
// |
// Basic FPU test |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 2003 Nick Garnett |
// |
// 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// 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@calivar.com |
// Contributors: nickg@calivar.com |
// Date: 2003-01-27 |
// Description: Simple FPU test. This is not very sophisticated as far |
// as checking FPU performance or accuracy. It is more |
// concerned with checking that several threads doing FP |
// operations do not interfere with eachother's use of the |
// FPU. |
// |
//####DESCRIPTIONEND#### |
//========================================================================== |
|
#include <pkgconf/kernel.h> |
#include <pkgconf/hal.h> |
|
#include <cyg/hal/hal_arch.h> |
|
#include <cyg/kernel/kapi.h> |
|
#include <cyg/infra/testcase.h> |
#include <cyg/infra/diag.h> |
|
//#include <cyg/kernel/test/stackmon.h> |
//#include CYGHWR_MEMORY_LAYOUT_H |
|
//========================================================================== |
|
#if defined(CYGFUN_KERNEL_API_C) && \ |
defined(CYGSEM_KERNEL_SCHED_MLQUEUE) && \ |
(CYGNUM_KERNEL_SCHED_PRIORITIES > 12) |
|
//========================================================================== |
// Base priority for all threads. |
|
#define BASE_PRI 5 |
|
//========================================================================== |
// Runtime |
// |
// This is the number of ticks that the program will run for. 3000 |
// ticks is equal to 30 seconds in the default configuration. For |
// simulators we reduce the run time to 3 simulated seconds. |
|
#define RUN_TICKS 3000 |
#define RUN_TICKS_SIM 300 |
|
//========================================================================== |
// Thread parameters |
|
#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_MINIMUM) |
|
static cyg_uint8 stacks[3][STACK_SIZE]; |
static cyg_handle_t thread[3]; |
static cyg_thread thread_struct[3]; |
|
//========================================================================== |
// Alarm parameters. |
|
static cyg_alarm alarm_struct; |
static cyg_handle_t alarm; |
|
static cyg_count8 cur_thread = 0; |
static cyg_count32 alarm_ticks = 0; |
static cyg_count32 run_ticks = RUN_TICKS; |
|
//========================================================================== |
|
static int errors = 0; |
|
//========================================================================== |
// Random number generator. Ripped out of the C library. |
|
static int rand( unsigned int *seed ) |
{ |
// This is the code supplied in Knuth Vol 2 section 3.6 p.185 bottom |
|
#define RAND_MAX 0x7fffffff |
#define MM 2147483647 // a Mersenne prime |
#define AA 48271 // this does well in the spectral test |
#define QQ 44488 // (long)(MM/AA) |
#define RR 3399 // MM % AA; it is important that RR<QQ |
|
*seed = AA*(*seed % QQ) - RR*(unsigned int)(*seed/QQ); |
if (*seed < 0) |
*seed += MM; |
|
return (int)( *seed & RAND_MAX ); |
} |
|
//========================================================================== |
// Test calculation. |
// |
// Generates an array of random FP values and then repeatedly applies |
// a calculation to them and checks that the same result is reached |
// each time. The calculation, in the macro CALC, is intended to make |
// maximum use of the FPU registers. However, the i386 compiler |
// doesn't let this expression get very complex before it starts |
// spilling values out to memory. |
|
static void do_test( double *values, |
int count, |
int loops, |
int test, |
const char *name) |
{ |
unsigned int i, j; |
// volatiles necessary to force |
// values to 64 bits for comparison |
volatile double sum = 1.0; |
volatile double last_sum; |
unsigned int seed; |
|
#define V(__i) (values[(__i)%count]) |
#define CALC ((V(i-1)*V(i+1))*(V(i-2)*V(i+2))*(V(i-3)*sum)) |
|
seed = ((unsigned int)&i)*count; |
|
// Set up an array of values... |
for( i = 0; i < count; i++ ) |
values[i] = (double)rand( &seed )/(double)0x7fffffff; |
|
// Now calculate something from them... |
for( i = 0; i < count; i++ ) |
sum += CALC; |
last_sum = sum; |
|
// Now recalculate the sum in a loop and look for errors |
for( j = 0; j < loops ; j++ ) |
{ |
sum = 1.0; |
for( i = 0; i < count; i++ ) |
sum += CALC; |
|
if( sum != last_sum ) |
{ |
errors++; |
diag_printf("%s: Sum mismatch! %d sum=[%08x:%08x] last_sum=[%08x:%08x]\n", |
name,j, |
((cyg_uint32 *)&sum)[0],((cyg_uint32 *)&sum)[1], |
((cyg_uint32 *)&last_sum)[0],((cyg_uint32 *)&last_sum)[1] |
); |
} |
|
#if 0 |
if( ((j*count)%1000000) == 0 ) |
diag_printf("INFO:<%s: %2d calculations done>\n",name,j*count); |
#endif |
} |
|
} |
|
//========================================================================== |
// Alarm handler |
// |
// This is called every tick. It lowers the priority of the currently |
// running thread and raises the priority of the next. Thus we |
// implement a form of timelslicing between the threads at one tick |
// granularity. |
|
static void alarm_fn(cyg_handle_t alarm, cyg_addrword_t data) |
{ |
alarm_ticks++; |
|
if( alarm_ticks >= run_ticks ) |
{ |
if( errors ) |
CYG_TEST_FAIL("Errors detected"); |
else |
CYG_TEST_PASS("OK"); |
|
CYG_TEST_FINISH("FP Test done"); |
} |
else |
{ |
cyg_thread_set_priority( thread[cur_thread], BASE_PRI ); |
|
cur_thread = (cur_thread+1)%3; |
|
cyg_thread_set_priority( thread[cur_thread], BASE_PRI-1 ); |
} |
} |
|
|
//========================================================================== |
|
#define FP1_COUNT 1000 |
|
static double fpt1_values[FP1_COUNT]; |
|
void fptest1( CYG_ADDRWORD id ) |
{ |
while(1) |
do_test( fpt1_values, FP1_COUNT, 2000000000, id, "fptest1" ); |
} |
|
//========================================================================== |
|
#define FP2_COUNT 10000 |
|
static double fpt2_values[FP2_COUNT]; |
|
void fptest2( CYG_ADDRWORD id ) |
{ |
while(1) |
do_test( fpt2_values, FP2_COUNT, 2000000000, id, "fptest2" ); |
} |
|
//========================================================================== |
|
#define FP3_COUNT 100 |
|
static double fpt3_values[FP3_COUNT]; |
|
void fptest3( CYG_ADDRWORD id ) |
{ |
while(1) |
do_test( fpt3_values, FP3_COUNT, 2000000000, id, "fptest3" ); |
} |
|
//========================================================================== |
|
void fptest_main( void ) |
{ |
|
CYG_TEST_INIT(); |
|
if( cyg_test_is_simulator ) |
{ |
run_ticks = RUN_TICKS_SIM; |
} |
|
CYG_TEST_INFO("Run fptest in cyg_start"); |
do_test( fpt3_values, FP3_COUNT, 1000, 0, "start" ); |
CYG_TEST_INFO( "cyg_start run done"); |
|
cyg_thread_create( BASE_PRI-1, |
fptest1, |
0, |
"fptest1", |
&stacks[0][0], |
STACK_SIZE, |
&thread[0], |
&thread_struct[0]); |
|
cyg_thread_resume( thread[0] ); |
|
cyg_thread_create( BASE_PRI, |
fptest2, |
1, |
"fptest2", |
&stacks[1][0], |
STACK_SIZE, |
&thread[1], |
&thread_struct[1]); |
|
cyg_thread_resume( thread[1] ); |
|
cyg_thread_create( BASE_PRI, |
fptest3, |
2, |
"fptest3", |
&stacks[2][0], |
STACK_SIZE, |
&thread[2], |
&thread_struct[2]); |
|
cyg_thread_resume( thread[2] ); |
|
cyg_alarm_create( cyg_real_time_clock(), |
alarm_fn, |
0, |
&alarm, |
&alarm_struct ); |
|
cyg_alarm_initialize( alarm, cyg_current_time()+1, 1 ); |
|
cyg_scheduler_start(); |
|
} |
|
//========================================================================== |
|
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
externC void |
cyg_hal_invoke_constructors(); |
#endif |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
fptest_main(); |
} |
|
//========================================================================== |
|
#else // CYGFUN_KERNEL_API_C... |
|
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA("FP test requires:\n" |
"CYGFUN_KERNEL_API_C && \n" |
"CYGSEM_KERNEL_SCHED_MLQUEUE && \n" |
"(CYGNUM_KERNEL_SCHED_PRIORITIES > 12)\n"); |
} |
|
#endif // CYGFUN_KERNEL_API_C, etc. |
|
//========================================================================== |
// EOF fptest.cxx |
/thread0.cxx
0,0 → 1,114
//========================================================================== |
// |
// thread0.cxx |
// |
// Thread test 0 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-02-11 |
// Description: Limited to checking constructors/destructors |
// Omissions: |
// Thread constructors with 2 or 3 args are not supported at time |
// of writing test. |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/thread.hxx> |
|
#include <cyg/infra/testcase.h> |
|
#include <cyg/kernel/thread.inl> |
|
#include "testaux.hxx" |
|
#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
static char stack[STACKSIZE]; |
|
static cyg_thread_entry entry; |
|
static void entry( CYG_ADDRWORD data ) |
{ |
} |
|
static int *p; |
|
static bool flash( void ) |
{ |
#if 0 // no facility to allocate stack exists yet. |
Cyg_Thread t0( entry, 0x111 ); |
|
CYG_ASSERTCLASS(&t0, "error"); |
|
Cyg_Thread t1( entry, (CYG_ADDRWORD)&t0, STACKSIZE ); |
|
CYG_ASSERTCLASS(&t1, "error"); |
#endif |
Cyg_Thread t2( CYG_SCHED_DEFAULT_INFO, |
entry, (CYG_ADDRWORD)p, |
"thread t2", |
(CYG_ADDRESS)stack, STACKSIZE ); |
|
CYG_ASSERTCLASS(&t2, "error"); |
|
return true; |
} |
|
void thread0_main( void ) |
{ |
CYG_TEST_INIT(); |
|
CHECK(flash()); |
CHECK(flash()); |
|
CYG_TEST_PASS_FINISH("Thread 0 OK"); |
|
} |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
thread0_main(); |
} |
// EOF thread0.cxx |
/kintr0.c
0,0 → 1,230
/*================================================================= |
// |
// kintr0.c |
// |
// Kernel C API Intr test 0 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm, jlarmour |
// Date: 1999-02-16 |
// Description: Very basic test of interrupt objects |
// Options: |
// CYGIMP_KERNEL_INTERRUPTS_DSRS_TABLE |
// CYGIMP_KERNEL_INTERRUPTS_DSRS_TABLE_MAX |
// CYGIMP_KERNEL_INTERRUPTS_DSRS_LIST |
//####DESCRIPTIONEND#### |
*/ |
|
#include <cyg/kernel/kapi.h> |
#include <cyg/hal/hal_intr.h> |
|
#include <cyg/infra/testcase.h> |
|
#ifdef CYGFUN_KERNEL_API_C |
|
#include "testaux.h" |
|
static cyg_interrupt intr_obj[2]; |
|
static cyg_handle_t intr0, intr1; |
|
|
static cyg_ISR_t isr0, isr1; |
static cyg_DSR_t dsr0, dsr1; |
|
static cyg_uint32 isr0(cyg_vector_t vector, cyg_addrword_t data) |
{ |
CYG_UNUSED_PARAM(cyg_addrword_t, data); |
|
cyg_interrupt_acknowledge(vector); |
return 0; |
} |
|
static void dsr0(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) |
{ |
CYG_UNUSED_PARAM(cyg_vector_t, vector); |
CYG_UNUSED_PARAM(cyg_ucount32, count); |
CYG_UNUSED_PARAM(cyg_addrword_t, data); |
} |
|
static cyg_uint32 isr1(cyg_vector_t vector, cyg_addrword_t data) |
{ |
CYG_UNUSED_PARAM(cyg_vector_t, vector); |
CYG_UNUSED_PARAM(cyg_addrword_t, data); |
return 0; |
} |
|
static void dsr1(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) |
{ |
CYG_UNUSED_PARAM(cyg_vector_t, vector); |
CYG_UNUSED_PARAM(cyg_ucount32, count); |
CYG_UNUSED_PARAM(cyg_addrword_t, data); |
} |
|
static bool flash( void ) |
{ |
cyg_handle_t handle; |
cyg_interrupt intr; |
|
cyg_interrupt_create(CYGNUM_HAL_ISR_MIN, 0, (cyg_addrword_t)333, |
isr0, dsr0, &handle, &intr ); |
cyg_interrupt_delete(handle); |
|
return true; |
} |
|
/* IMPORTANT: The calling convention for VSRs is target dependent. It is |
* unlikely that a plain C or C++ routine would function correctly on any |
* particular platform, even if it could correctly access the system |
* resources necessary to handle the event that caused it to be called. |
* VSRs usually must be written in assembly language. |
* |
* This is just a test program. The routine vsr0() below is defined simply |
* to define an address that will be in executable memory. If an event |
* causes this VSR to be called, all bets are off. If it is accidentally |
* installed in the vector for the realtime clock, the system will likely |
* freeze. |
*/ |
|
static cyg_VSR_t vsr0; |
|
static void vsr0() |
{ |
} |
|
void kintr0_main( void ) |
{ |
cyg_vector_t v = (CYGNUM_HAL_VSR_MIN + 11) % CYGNUM_HAL_VSR_COUNT; |
cyg_vector_t v1; |
cyg_vector_t lvl1 = CYGNUM_HAL_ISR_MIN + (1 % CYGNUM_HAL_ISR_COUNT); |
cyg_vector_t lvl2 = CYGNUM_HAL_ISR_MIN + (15 % CYGNUM_HAL_ISR_COUNT); |
int in_use; |
|
cyg_VSR_t *old_vsr, *new_vsr; |
|
CYG_TEST_INIT(); |
|
#ifdef CYGPKG_HAL_MIPS_TX39 |
// This can be removed when PR 17831 is fixed |
if ( cyg_test_is_simulator ) |
v1 = 12 % CYGNUM_HAL_ISR_COUNT; |
else /* NOTE TRAILING ELSE... */ |
#endif |
v1 = CYGNUM_HAL_ISR_MIN + ( 6 % CYGNUM_HAL_ISR_COUNT); |
|
CHECK(flash()); |
CHECK(flash()); |
|
// Make sure the chosen levels are not already in use. |
HAL_INTERRUPT_IN_USE( lvl1, in_use ); |
intr0 = 0; |
if (!in_use) |
cyg_interrupt_create(lvl1, 1, (cyg_addrword_t)777, isr0, dsr0, |
&intr0, &intr_obj[0]); |
|
HAL_INTERRUPT_IN_USE( lvl2, in_use ); |
intr1 = 0; |
if (!in_use && lvl1 != lvl2) |
cyg_interrupt_create(lvl2, 1, 888, isr1, dsr1, &intr1, &intr_obj[1]); |
|
// Check these functions at least exist |
|
cyg_interrupt_disable(); |
cyg_interrupt_enable(); |
|
if (intr0) |
cyg_interrupt_attach(intr0); |
if (intr1) |
cyg_interrupt_attach(intr1); |
if (intr0) |
cyg_interrupt_detach(intr0); |
if (intr1) |
cyg_interrupt_detach(intr1); |
|
// If this attaching interrupt replaces the previous interrupt |
// instead of adding to it we could be in a big mess if the |
// vector is being used by something important. |
|
cyg_interrupt_get_vsr( v, &old_vsr ); |
cyg_interrupt_set_vsr( v, vsr0 ); |
cyg_interrupt_get_vsr( v, &new_vsr ); |
CHECK( vsr0 == new_vsr ); |
|
new_vsr = NULL; |
cyg_interrupt_get_vsr( v, &new_vsr ); |
cyg_interrupt_set_vsr( v, old_vsr ); |
CHECK( new_vsr == vsr0 ); |
|
cyg_interrupt_set_vsr( v, new_vsr ); |
new_vsr = NULL; |
cyg_interrupt_get_vsr( v, &new_vsr ); |
CHECK( vsr0 == new_vsr ); |
|
cyg_interrupt_set_vsr( v, old_vsr ); |
CHECK( vsr0 == new_vsr ); |
new_vsr = NULL; |
cyg_interrupt_get_vsr( v, &new_vsr ); |
CHECK( old_vsr == new_vsr ); |
|
CHECK( NULL != vsr0 ); |
|
cyg_interrupt_mask(v1); |
cyg_interrupt_unmask(v1); |
|
cyg_interrupt_configure(v1, true, true); |
|
CYG_TEST_PASS_FINISH("Kernel C API Intr 0 OK"); |
} |
|
externC void |
cyg_start( void ) |
{ |
kintr0_main(); |
} |
|
#else /* def CYGFUN_KERNEL_API_C */ |
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA("Kernel C API layer disabled"); |
} |
#endif /* def CYGFUN_KERNEL_API_C */ |
|
/* EOF kintr0.c */ |
/thread1.cxx
0,0 → 1,172
//========================================================================== |
// |
// thread1.cxx |
// |
// Thread test 1 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-02-11 |
// Description: Tests some basic thread functions. |
// Omissions: Cyg_ThreadTimer |
// Cyg_Thread |
// exit -- not necessarily called |
// yield |
// set_priority |
// get_priority |
// get/set_sleep_reason |
// get/set_wake_reason |
// set/clear_timer |
// Cyg_ThreadQueue |
// |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/sched.hxx> |
#include <cyg/kernel/thread.hxx> |
|
#include <cyg/infra/testcase.h> |
|
#ifdef CYGFUN_KERNEL_THREADS_TIMER |
|
#include <cyg/kernel/sched.inl> |
#include <cyg/kernel/thread.inl> |
|
#include "testaux.hxx" |
|
#ifdef CYGNUM_HAL_STACK_SIZE_TYPICAL |
#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL |
#else |
#define STACKSIZE 2000 |
#endif |
|
static char stack[2][STACKSIZE]; |
|
static char thread[2][sizeof(Cyg_Thread)]; |
|
static Cyg_Thread *pt0,*pt1; |
static cyg_uint16 uid0,uid1; |
|
|
static void entry0( CYG_ADDRWORD data ) |
{ |
CHECK( 222 == data ); |
|
uid0 = pt0->get_unique_id(); |
|
pt1->suspend(); |
pt1->resume(); |
|
do { |
pt0->delay(1); |
} while( Cyg_Thread::RUNNING == pt1->get_state() ); |
|
CHECK( Cyg_Thread::SLEEPING == pt1->get_state() ); |
|
pt1->wake(); |
|
CHECK( uid0 != uid1 ); |
|
CYG_TEST_PASS_FINISH("Thread 1 OK"); |
} |
|
static void entry1( CYG_ADDRWORD data ) |
{ |
CHECK( 333 == data ); |
|
uid1 = pt1->get_unique_id(); |
|
Cyg_Thread *self = Cyg_Thread::self(); |
|
CHECK( self == pt1 ); |
|
pt1->sleep(); |
pt1->suspend(); |
|
Cyg_Thread::exit(); // no guarantee this will be called |
} |
|
void thread1_main( void ) |
{ |
CYG_TEST_INIT(); |
|
pt0 = new((void *)&thread[0]) |
Cyg_Thread(CYG_SCHED_DEFAULT_INFO, |
entry0, 222, |
"thread 0", |
(CYG_ADDRESS)stack[0], STACKSIZE ); |
pt1 = new((void *)&thread[1]) |
Cyg_Thread(CYG_SCHED_DEFAULT_INFO, |
entry1, 333, |
"thread 1", |
(CYG_ADDRESS)stack[1], STACKSIZE ); |
|
CYG_ASSERTCLASS( pt0, "error" ); |
CYG_ASSERTCLASS( pt1, "error" ); |
|
pt0->resume(); |
pt1->resume(); |
|
Cyg_Scheduler::start(); |
|
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
thread1_main(); |
} |
|
#else // ifdef CYGFUN_KERNEL_THREADS_TIMER |
|
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA("Kernel threads timer disabled"); |
} |
|
#endif // ifdef CYGFUN_KERNEL_THREADS_TIMER |
|
// EOF thread1.cxx |
/thread2.cxx
0,0 → 1,236
//========================================================================== |
// |
// thread2.cxx |
// |
// Thread test 2 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-02-19 |
// Description: |
// tests scheduler & threads & priorities |
// + create multiple threads with various priorities |
// + check highest priority running thread is always running |
// + check next highest runs when highest suspended |
// + check several threads of equal priority share time |
// (only !CYGINT_KERNEL_SCHEDULER_UNIQUE_PRIORITIES) |
// + check other threads are starved |
// + check setting priority dynamically causes a thread to |
// become/stay current/non-current |
// Omissions: |
// check yield |
// check can set threads with min and max priority |
// Options: |
// CYGINT_KERNEL_SCHEDULER_UNIQUE_PRIORITIES |
// CYGIMP_THREAD_PRIORITY |
// CYGNUM_KERNEL_SCHED_PRIORITIES |
// CYGSEM_KERNEL_SCHED_BITMAP |
// CYGSEM_KERNEL_SCHED_MLQUEUE |
//####DESCRIPTIONEND#### |
//========================================================================== |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/thread.hxx> |
#include <cyg/kernel/thread.inl> |
#include <cyg/kernel/sched.hxx> |
#include <cyg/kernel/mutex.hxx> |
#include <cyg/kernel/sema.hxx> |
|
#include <cyg/infra/testcase.h> |
|
#include <cyg/kernel/sched.inl> |
|
// ------------------------------------------------------------------------ |
|
#if defined(CYGIMP_THREAD_PRIORITY) && \ |
!defined(CYGPKG_KERNEL_SMP_SUPPORT) |
|
// ------------------------------------------------------------------------ |
|
static Cyg_Counting_Semaphore s0, s1, s2; |
|
static volatile cyg_ucount8 q = 0; |
|
static Cyg_Thread *thread0, *thread1, *thread2; |
|
#define NTHREADS 3 |
#include "testaux.hxx" |
|
// ------------------------------------------------------------------------ |
|
static void entry0( CYG_ADDRWORD data ) |
{ |
CHECK( 0 == q++ ); |
s0.wait(); |
CHECK( 3 == q++ ); |
s1.post(); |
CHECK( 4 == q++ ); |
s0.wait(); |
s0.wait(); |
CYG_TEST_PASS_FINISH("Thread 2 OK"); |
} |
|
// ------------------------------------------------------------------------ |
|
static void entry1( CYG_ADDRWORD data ) |
{ |
CHECK( 1 == q++ ); |
s1.wait(); |
CHECK( 5 == q++ ); |
thread0->set_priority(9); |
s0.post(); |
CHECK( 6 == q++ ); |
thread2->set_priority(3); |
CHECK( 8 == q++ ); |
s2.post(); |
CHECK( 12 == q++ ); |
CHECK( 9 == thread0->get_priority() ); |
CHECK( 6 == thread1->get_priority() ); |
CHECK( 7 == thread2->get_priority() ); |
q = 100; |
#if !(CYGINT_KERNEL_SCHEDULER_UNIQUE_PRIORITIES) \ |
&& defined(CYGSEM_KERNEL_SCHED_TIMESLICE) |
thread2->set_priority(6); |
CHECK( 6 == thread1->get_priority() ); |
CHECK( 6 == thread2->get_priority() ); |
|
while ( 100 == q ) |
; |
CHECK( 101 == q++ ); |
s1.wait(); |
CHECK( 103 == q++ ); |
#endif |
s0.post(); |
s1.wait(); |
} |
|
// ------------------------------------------------------------------------ |
|
static void entry2( CYG_ADDRWORD data ) |
{ |
CHECK( 2 == q++ ); |
s0.post(); |
CHECK( 7 == q++ ); |
s2.wait(); |
CHECK( 9 == q++ ); |
thread1->set_priority(6); |
CHECK( 10 == q++ ); |
thread2->set_priority(2); |
CHECK( 11 == q++ ); |
thread2->set_priority(7); |
|
#if !(CYGINT_KERNEL_SCHEDULER_UNIQUE_PRIORITIES) \ |
&& defined(CYGSEM_KERNEL_SCHED_TIMESLICE) |
CHECK( 6 == thread1->get_priority() ); |
CHECK( 6 == thread2->get_priority() ); |
|
CHECK( 100 == q++ ); |
while ( 101 == q ) |
; |
CHECK( 102 == q++ ); |
s1.post(); |
#endif |
s0.post(); |
s2.wait(); |
} |
|
|
// ------------------------------------------------------------------------ |
|
void thread2_main( void ) |
{ |
CYG_TEST_INIT(); |
|
thread0 = new_thread( entry0, 0 ); |
thread1 = new_thread( entry1, 1 ); |
thread2 = new_thread( entry2, 2 ); |
|
thread0->resume(); |
thread1->resume(); |
thread2->resume(); |
|
thread0->set_priority(5); |
thread1->set_priority(6); |
thread2->set_priority(7); |
|
if( 9 >= CYG_THREAD_MIN_PRIORITY ) |
CYG_TEST_FAIL_FINISH("Test requires priorities up to 9"); |
|
if( 2 <= CYG_THREAD_MAX_PRIORITY ) |
CYG_TEST_FAIL_FINISH("Test requires priorities as low as 2"); |
|
Cyg_Scheduler::start(); |
|
CYG_TEST_FAIL_FINISH("Unresolved"); |
} |
|
// ------------------------------------------------------------------------ |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
thread2_main(); |
} |
// ------------------------------------------------------------------------ |
|
|
#else // CYGPKG_KERNEL_SMP_SUPPORT etc |
|
// ------------------------------------------------------------------------ |
|
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_PASS_FINISH("Thread2 test requires:\n" |
"defined(CYGIMP_THREAD_PRIORITY) &&\n" |
"!defined(CYGPKG_KERNEL_SMP_SUPPORT)\n"); |
|
} |
|
// ------------------------------------------------------------------------ |
|
#endif // CYGPKG_KERNEL_SMP_SUPPORT etc |
|
// ------------------------------------------------------------------------ |
// EOF thread2.cxx |
/kill.cxx
0,0 → 1,199
//========================================================================== |
// |
// kill.cxx |
// |
// Thread kill test |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): nickg |
// Contributors: nickg |
// Date: 1998-04-24 |
// Description: Tests the functionality of thread kill() and |
// reinitalize(). |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/thread.hxx> |
#include <cyg/kernel/thread.inl> |
#include <cyg/kernel/sched.hxx> |
#include <cyg/kernel/mutex.hxx> |
#include <cyg/kernel/sema.hxx> |
|
#include <cyg/infra/testcase.h> |
|
#ifdef CYGFUN_KERNEL_THREADS_TIMER |
|
#include <cyg/kernel/sched.inl> |
|
#define NTHREADS 3 |
|
#include "testaux.hxx" |
|
// In general, this delay has to be long enough to account for slow targets |
// and potential problems on e.g. the linux synthetic target to avoid |
// potential problems due to timing inaccuracy and scheduling of Linux |
// tasks. It is decreased further below for simulators. |
int delay_ticks = 5; |
|
|
static Cyg_Binary_Semaphore s0, s1; |
|
volatile cyg_atomic thread0_state; |
volatile cyg_atomic thread1_state; |
volatile cyg_atomic thread2_state; |
|
static void entry0( CYG_ADDRWORD data ) |
{ |
Cyg_Thread *self = Cyg_Thread::self(); |
|
thread0_state = 1; |
|
s0.wait(); |
|
thread0_state = 2; |
|
CYG_TEST_FAIL_FINISH("Thread not killed"); |
|
self->exit(); |
} |
|
|
static void entry1( CYG_ADDRWORD data ) |
{ |
Cyg_Thread *self = Cyg_Thread::self(); |
|
thread1_state = 1; |
|
self->delay(delay_ticks); |
|
if( thread2_state != 1 ) |
CYG_TEST_FAIL_FINISH("Thread2 in wrong state"); |
|
thread1_state = 2; |
|
thread[0]->kill(); |
|
thread1_state = 3; |
|
thread[2]->kill(); |
|
thread1_state = 4; |
|
self->delay(delay_ticks); |
|
thread1_state = 5; |
thread2_state = 0; |
|
thread[2]->reinitialize(); |
thread[2]->resume(); |
|
self->delay(delay_ticks); |
|
if( thread2_state != 1 ) |
CYG_TEST_FAIL_FINISH("Thread2 in wrong state"); |
|
thread1_state = 6; |
|
self->delay(delay_ticks); |
|
if( thread2_state != 2 ) |
CYG_TEST_FAIL_FINISH("Thread2 in wrong state"); |
|
thread[2]->kill(); |
|
thread1_state = 7; |
|
CYG_TEST_PASS_FINISH("Kill OK"); |
|
Cyg_Thread::self()->exit(); |
} |
|
static void entry2( CYG_ADDRWORD data ) |
{ |
thread2_state = 1; |
|
while( thread1_state != 6 ) continue; |
|
thread2_state = 2; |
|
for(;;) continue; |
|
} |
|
void release_main(void) |
{ |
CYG_TEST_INIT(); |
|
if (cyg_test_is_simulator) |
delay_ticks = 2; |
|
new_thread( entry0, 0); |
new_thread( entry1, 1); |
new_thread( entry2, 2); |
|
thread[0]->set_priority(5); |
thread[1]->set_priority(6); |
thread[2]->set_priority(7); |
|
Cyg_Scheduler::start(); |
|
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
release_main(); |
} |
|
#else // ifdef CYGFUN_KERNEL_THREADS_TIMER |
|
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA("Kernel threads timer disabled"); |
} |
|
#endif // ifdef CYGFUN_KERNEL_THREADS_TIMER |
|
// EOF kill.cxx |
/tcdiag.cxx
0,0 → 1,97
//========================================================================== |
// |
// tcdiag.cxx |
// |
// Kernel diag test harness. |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-03-17 |
// Description: Test harness implementation that uses the kernel's |
// diag channel. This is intended for manual testing |
// of the kernel. |
//####DESCRIPTIONEND#### |
|
#include <testcase.h> |
#include <diag.h> |
|
bool cyg_test_is_simulator=false; // infrastructure changes as necessary |
|
void cyg_test_init() |
{ |
diag_init(); |
} |
|
void cyg_test_output(int status, char *msg, int line, char *file) |
{ |
char *st; |
|
switch (status) { |
case 0: |
st = "FAIL:"; |
break; |
case 1: |
st = "PASS:"; |
break; |
case 2: |
st = "EXIT:"; |
break; |
case 3: |
st = "INFO:"; |
break; |
} |
|
diag_write_string(st); |
diag_write_char('<'); |
diag_write_string(msg); |
diag_write_string("> Line: "); |
diag_write_dec(line); |
diag_write_string(", File: "); |
diag_write_string(file); |
diag_write_char('\n'); |
|
} |
|
// This is an appropriate function to set a breakpoint on |
void cyg_test_exit() |
{ |
for(;;) |
; |
} |
// EOF tcdiag.cxx |
/bin_sem0.cxx
0,0 → 1,89
//========================================================================== |
// |
// bin_sem0.cxx |
// |
// Binary semaphore test 0 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-02-24 |
// Description: Limited to checking constructors/destructors |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/sema.hxx> |
|
#include <cyg/infra/testcase.h> |
|
#include "testaux.hxx" |
|
static Cyg_Binary_Semaphore sema0, sema1(false), sema2(true); |
|
|
static bool flash( void ) |
{ |
Cyg_Binary_Semaphore s0; |
|
Cyg_Binary_Semaphore s1(true); |
|
Cyg_Binary_Semaphore s2(false); |
|
return true; |
} |
|
void bin_sem0_main( void ) |
{ |
CYG_TEST_INIT(); |
|
CHECK(flash()); |
CHECK(flash()); |
|
CYG_TEST_PASS_FINISH("Binary Semaphore 0 OK"); |
} |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
bin_sem0_main(); |
} |
// EOF bin_sem0.cxx |
/bin_sem1.cxx
0,0 → 1,130
//========================================================================== |
// |
// bin_sem1.cxx |
// |
// Binary semaphore test 1 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-02-24 |
// Description: Tests basic binary semaphore functionality. |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/sched.hxx> // Cyg_Scheduler::start() |
#include <cyg/kernel/thread.hxx> // Cyg_Thread |
#include <cyg/kernel/thread.inl> |
|
#include <cyg/kernel/sema.hxx> |
|
#include <cyg/infra/testcase.h> |
|
#include <cyg/kernel/sched.inl> |
|
#define NTHREADS 2 |
|
#include "testaux.hxx" |
|
static Cyg_Binary_Semaphore s0(true), s1(false), s2; |
|
static volatile cyg_ucount8 q = 0; |
|
static void entry0( CYG_ADDRWORD data ) |
{ |
s0.wait(); |
CHECK( 0 == q++ ); |
s1.post(); |
s0.wait(); |
CHECK( 2 == q++ ); |
CHECK( ! s0.posted() ); |
CHECK( ! s0.trywait() ); |
s0.post(); |
CHECK( 3 == q++ ); |
CHECK( s0.posted() ); |
s1.post(); |
CHECK( ! s2.posted() ); |
s2.wait(); |
CHECK( 5 == q++ ); |
CYG_TEST_PASS_FINISH("Binary Semaphore 1 OK"); |
} |
|
static void entry1( CYG_ADDRWORD data ) |
{ |
CHECK( s1.posted() ); |
s1.wait(); |
CHECK( 1 == q++ ); |
CHECK( ! s0.posted() ); |
s0.post(); |
s1.wait(); |
CHECK( 4 == q++ ); |
CHECK( s0.posted() ); |
CHECK( s0.trywait() ); |
CHECK( ! s0.posted() ); |
s2.post(); |
s0.wait(); |
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
void bin_sem1_main( void ) |
{ |
CYG_TEST_INIT(); |
|
new_thread( entry0, 0); |
new_thread( entry1, 1); |
|
#ifdef CYGIMP_THREAD_PRIORITY |
thread[0]->set_priority( 4 ); |
thread[1]->set_priority( 5 ); // make sure the threads execute as intended |
#endif |
|
Cyg_Scheduler::start(); |
|
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
bin_sem1_main(); |
} |
// EOF bin_sem1.cxx |
/bin_sem2.cxx
0,0 → 1,224
//========================================================================== |
// |
// bin_sem2.cxx |
// |
// Binary semaphore test 2 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): nickg,dsm |
// Contributors: dsm |
// Date: 1998-03-10 |
// Description: |
// Dining philosophers test. Based on philo.cxx |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/sched.hxx> |
#include <cyg/kernel/thread.hxx> |
#include <cyg/kernel/thread.inl> |
#include <cyg/kernel/mutex.hxx> |
|
#include <cyg/kernel/sema.hxx> |
|
#include <cyg/infra/testcase.h> |
|
#include <cyg/kernel/sched.inl> |
|
static cyg_ucount16 PHILO_LOOPS = 1000; |
|
#define PHILOSOPHERS 15 |
#define NTHREADS PHILOSOPHERS |
#include "testaux.hxx" |
|
static Cyg_Binary_Semaphore chopstick[PHILOSOPHERS]; |
|
static char pstate[PHILOSOPHERS+1]; // state of each philosopher |
|
static cyg_ucount16 state_changes = 0; |
// state_changes keep track of number of changes to pstate so |
// we can exit after we've seen enough. |
|
|
static Cyg_Mutex pstate_mutex; |
static Cyg_Mutex cycle_mutex; |
|
static inline int left(cyg_count8 i) |
{ |
return (0 == i) ? PHILOSOPHERS-1 : i-1 ; |
} |
static inline int right(cyg_count8 i) |
{ |
return (PHILOSOPHERS == i+1) ? 0 : i+1 ; |
} |
|
void change_state(int id, char newstate) |
{ |
if (PHILO_LOOPS == state_changes++) |
CYG_TEST_PASS_FINISH("Binary Semaphore 2 OK"); |
|
|
pstate_mutex.lock(); { |
pstate[id] = newstate; |
bool all_hungry = true; // until proved otherwise |
for(cyg_ucount8 i=0; i < PHILOSOPHERS; i++) { |
if('E' == pstate[i]) { |
CHECK('E' != pstate[left(i)]); |
CHECK('E' != pstate[right(i)]); |
} |
if('H' != pstate[i]) { |
all_hungry = false; |
} |
} |
// Theoretically it is possible for all the philosophers to be |
// hungry but not waiting on semaphores. But in practice this |
// means something is wrong. |
CHECK(false == all_hungry); |
} pstate_mutex.unlock(); |
} |
|
char get_state(int id) |
{ |
pstate_mutex.lock(); |
|
char s = pstate[id]; |
|
pstate_mutex.unlock(); |
|
return s; |
} |
|
// ------------------------------------------------------------------------- |
// Thread to behave like a philosopher |
|
void Philosopher( CYG_ADDRESS id ) |
{ |
Cyg_Thread *self = Cyg_Thread::self(); |
Cyg_Binary_Semaphore *first_stick = &chopstick[id]; |
Cyg_Binary_Semaphore *second_stick = &chopstick[(id+1)%PHILOSOPHERS]; |
|
CHECK( id >= 0 && id < PHILOSOPHERS); |
|
// Deadlock avoidance. The easiest way to make the philosophers |
// behave is to make each pick up the lowest numbered stick |
// first. This is how it works out anyway for all the philosophers |
// except the last, who must have his sticks swapped. |
|
if( id == PHILOSOPHERS-1 ) |
{ |
Cyg_Binary_Semaphore *t = first_stick; |
first_stick = second_stick; |
second_stick = t; |
} |
|
|
// The following variable is shared by all philosophers. |
// It is incremented unprotected, but this does not matter |
// since it is only present to introduce a little variability |
// into the think and eat times. |
|
static int cycle = 0; |
|
for(;;) |
{ |
// Think for a bit |
|
self->delay((id+cycle++)%12); // Cogito ergo sum... |
|
// I am now hungry, try to get the chopsticks |
change_state(id,'H'); |
|
// Get the sticks |
first_stick->wait(); |
second_stick->wait(); |
|
// Got them, now eat |
change_state(id,'E'); |
|
// Check that the world is as I think it is... |
CYG_TEST_CHECK( !first_stick->posted(), |
"Not got first stick"); |
CYG_TEST_CHECK( !second_stick->posted(), |
"Not got second stick"); |
CYG_TEST_CHECK( get_state(left(id)) != 'E', |
"Left neighbour also eating!!"); |
CYG_TEST_CHECK( get_state(right(id)) != 'E', |
"Right neighbour also eating!!"); |
|
self->delay((id+cycle++)%6); // munch munch |
|
// Finished eating, put down sticks. |
|
change_state(id,'T'); |
|
// put sticks back on table |
first_stick->post(); |
second_stick->post(); |
} |
} |
|
// ------------------------------------------------------------------------- |
|
void bin_sem2_main( void ) |
{ |
CYG_TEST_INIT(); |
|
if (cyg_test_is_simulator) |
PHILO_LOOPS = 100; |
|
for( int i = 0; i < PHILOSOPHERS; i++ ) |
{ |
pstate[i] = 'T'; // starting state |
new_thread(Philosopher, i); |
|
// make the matching chopstick present |
chopstick[i].post(); |
} |
|
Cyg_Scheduler::scheduler.start(); |
} |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
bin_sem2_main(); |
} |
// EOF bin_sem2.cxx |
/dhrystone.c
0,0 → 1,1176
//============================================================================= |
//####UNSUPPORTEDBEGIN#### |
// |
// ------------------------------------------- |
// This source file has been contributed to eCos/Red Hat. It may have been |
// changed slightly to provide an interface consistent with those of other |
// files. |
// |
// The functionality and contents of this file is supplied "AS IS" |
// without any form of support and will not necessarily be kept up |
// to date by Red Hat. |
// |
// The style of programming used in this file may not comply with the |
// eCos programming guidelines. Please do not use as a base for other |
// files. |
// |
// All inquiries about this file, or the functionality provided by it, |
// should be directed to the 'ecos-discuss' mailing list (see |
// http://sourceware.cygnus.com/ecos/intouch.html for details). |
// |
// ------------------------------------------- |
// |
//####UNSUPPORTEDEND#### |
//============================================================================= |
// Originally three different files, dhry.h, dhry21a.c and dhry21b.c |
// Merged into one file and changed a little to avoid compilation warnings. |
// The files were found at: |
// FTP ftp.nosc.mil/pub/aburto/dhrystone |
//============================================================================= |
|
#include <pkgconf/system.h> |
#include <pkgconf/infra.h> |
#include <pkgconf/kernel.h> |
#include <cyg/infra/cyg_type.h> |
#include <cyg/infra/testcase.h> |
|
#if !defined(CYGPKG_ISOINFRA) |
# define NA_MSG "Requires CYGPKG_ISOINFRA" |
#else |
# include <pkgconf/isoinfra.h> |
|
# if !defined(CYGFUN_KERNEL_API_C) \ |
|| !defined(CYGINT_ISO_STDIO_FORMATTED_IO) \ |
|| CYGINT_ISO_MALLOC == 0 \ |
|| !defined(CYGINT_ISO_STRING_STRFUNCS) |
|
# define NA_MSG "Requires CYGFUN_KERNEL_API_C && CYGINT_ISO_STDIO_FORMATTED_IO && CYGINT_ISO_MALLOC && CYGINT_ISO_STRING_STRFUNCS" |
|
# elif !defined(__OPTIMIZE__) \ |
|| defined(CYGPKG_INFRA_DEBUG) \ |
|| defined(CYGPKG_KERNEL_INSTRUMENT) |
# define NA_MSG "Only runs with optimized code, no tracing and no asserts" |
# elif defined(CYGDBG_INFRA_DIAG_USE_DEVICE) |
# define NA_MSG "Must use HAL diag output to avoid background DSR activity" |
# endif |
#endif |
|
#ifndef NA_MSG |
|
#include <cyg/hal/hal_cache.h> |
#include <cyg/kernel/kapi.h> |
#include <stdlib.h> |
#include <string.h> |
|
// Time in seconds. |
double |
dtime(void) |
{ |
return (double) cyg_current_time() / 100; |
} |
|
// Number of loops to run. |
#if defined(CYGPRI_KERNEL_TESTS_DHRYSTONE_PASSES) |
# define PASSES CYGPRI_KERNEL_TESTS_DHRYSTONE_PASSES |
#else |
# define PASSES 400000 |
#endif |
|
// Used in the code below to mark changes to the code. |
#define __ECOS__ |
|
#undef true |
#undef false |
|
|
/* |
************************************************************************* |
* |
* "DHRYSTONE" Benchmark Program |
* ----------------------------- |
* |
* Version: C, Version 2.1 |
* |
* File: dhry.h (part 1 of 3) |
* |
* Date: May 25, 1988 |
* |
* Author: Reinhold P. Weicker |
* Siemens Nixdorf Inf. Syst. |
* STM OS 32 |
* Otto-Hahn-Ring 6 |
* W-8000 Muenchen 83 |
* Germany |
* Phone: [+49]-89-636-42436 |
* (8-17 Central European Time) |
* UUCP: weicker@ztivax.uucp@unido.uucp |
* Internet: weicker@ztivax.siemens.com |
* |
* Original Version (in Ada) published in |
* "Communications of the ACM" vol. 27., no. 10 (Oct. 1984), |
* pp. 1013 - 1030, together with the statistics |
* on which the distribution of statements etc. is based. |
* |
* In this C version, the following C library functions are |
* used: |
* - strcpy, strcmp (inside the measurement loop) |
* - printf, scanf (outside the measurement loop) |
* |
* Collection of Results: |
* Reinhold Weicker (address see above) and |
* |
* Rick Richardson |
* PC Research. Inc. |
* 94 Apple Orchard Drive |
* Tinton Falls, NJ 07724 |
* Phone: (201) 834-1378 (9-17 EST) |
* UUCP: ...!uunet!pcrat!rick |
* |
* Please send results to Rick Richardson and/or Reinhold Weicker. |
* Complete information should be given on hardware and software |
* used. Hardware information includes: Machine type, CPU, type and |
* size of caches; for microprocessors: clock frequency, memory speed |
* (number of wait states). Software information includes: Compiler |
* (and runtime library) manufacturer and version, compilation |
* switches, OS version. The Operating System version may give an |
* indication about the compiler; Dhrystone itself performs no OS |
* calls in the measurement loop. |
* |
* The complete output generated by the program should be mailed |
* such that at least some checks for correctness can be made. |
* |
************************************************************************* |
* |
* History: This version C/2.1 has been made for two reasons: |
* |
* 1) There is an obvious need for a common C version of |
* Dhrystone, since C is at present the most popular system |
* programming language for the class of processors |
* (microcomputers, minicomputers) where Dhrystone is used |
* most. There should be, as far as possible, only one C |
* version of Dhrystone such that results can be compared |
* without restrictions. In the past, the C versions |
* distributed by Rick Richardson (Version 1.1) and by |
* Reinhold Weicker had small (though not significant) |
* differences. |
* |
* 2) As far as it is possible without changes to the |
* Dhrystone statistics, optimizing compilers should be |
* prevented from removing significant statements. |
* |
* This C version has been developed in cooperation with |
* Rick Richardson (Tinton Falls, NJ), it incorporates many |
* ideas from the "Version 1.1" distributed previously by |
* him over the UNIX network Usenet. |
* I also thank Chaim Benedelac (National Semiconductor), |
* David Ditzel (SUN), Earl Killian and John Mashey (MIPS), |
* Alan Smith and Rafael Saavedra-Barrera (UC at Berkeley) |
* for their help with comments on earlier versions of the |
* benchmark. |
* |
* Changes: In the initialization part, this version follows mostly |
* Rick Richardson's version distributed via Usenet, not the |
* version distributed earlier via floppy disk by Reinhold |
* Weicker. As a concession to older compilers, names have |
* been made unique within the first 8 characters. Inside the |
* measurement loop, this version follows the version |
* previously distributed by Reinhold Weicker. |
* |
* At several places in the benchmark, code has been added, |
* but within the measurement loop only in branches that |
* are not executed. The intention is that optimizing |
* compilers should be prevented from moving code out of the |
* measurement loop, or from removing code altogether. Since |
* the statements that are executed within the measurement |
* loop have NOT been changed, the numbers defining the |
* "Dhrystone distribution" (distribution of statements, |
* operand types and locality) still hold. Except for |
* sophisticated optimizing compilers, execution times for |
* this version should be the same as for previous versions. |
* |
* Since it has proven difficult to subtract the time for the |
* measurement loop overhead in a correct way, the loop check |
* has been made a part of the benchmark. This does have |
* an impact - though a very minor one - on the distribution |
* statistics which have been updated for this version. |
* |
* All changes within the measurement loop are described |
* and discussed in the companion paper "Rationale for |
* Dhrystone version 2". |
* |
* Because of the self-imposed limitation that the order and |
* distribution of the executed statements should not be |
* changed, there are still cases where optimizing compilers |
* may not generate code for some statements. To a certain |
* degree, this is unavoidable for small synthetic |
* benchmarks. Users of the benchmark are advised to check |
* code listings whether code is generated for all statements |
* of Dhrystone. |
* |
* Version 2.1 is identical to version 2.0 distributed via |
* the UNIX network Usenet in March 1988 except that it |
* corrects some minor deficiencies that were found by users |
* of version 2.0. The only change within the measurement |
* loop is that a non-executed "else" part was added to the |
* "if" statement in Func_3, and a non-executed "else" part |
* removed from Proc_3. |
* |
************************************************************************* |
* |
* Defines: The following "Defines" are possible: |
* -DROPT (default: Not defined) |
* As an approximation to what an average C |
* programmer might do, the "register" storage class |
* is applied (if enabled by -DROPT) |
* - for local variables, if they are used |
* (dynamically) five or more times |
* - for parameters if they are used (dynamically) |
* six or more times |
* Note that an optimal "register" strategy is |
* compiler-dependent, and that "register" |
* declarations do not necessarily lead to faster |
* execution. |
* -DNOSTRUCTASSIGN (default: Not defined) |
* Define if the C compiler does not support |
* assignment of structures. |
* -DNOENUMS (default: Not defined) |
* Define if the C compiler does not support |
* enumeration types. |
* |
************************************************************************* |
* |
* Compilation model and measurement (IMPORTANT): |
* |
* This C version of Dhrystone consists of three files: |
* - dhry.h (this file, containing global definitions and comments) |
* - dhry_1.c (containing the code corresponding to Ada package Pack_1) |
* - dhry_2.c (containing the code corresponding to Ada package Pack_2) |
* |
* The following "ground rules" apply for measurements: |
* - Separate compilation |
* - No procedure merging |
* - Otherwise, compiler optimizations are allowed but should be |
* indicated |
* - Default results are those without register declarations |
* See the companion paper "Rationale for Dhrystone Version 2" for a more |
* detailed discussion of these ground rules. |
* |
* For 16-Bit processors (e.g. 80186, 80286), times for all compilation |
* models ("small", "medium", "large" etc.) should be given if possible, |
* together with a definition of these models for the compiler system |
* used. |
* |
************************************************************************* |
* |
* Dhrystone (C version) statistics: |
* |
* [Comment from the first distribution, updated for version 2. |
* Note that because of language differences, the numbers are slightly |
* different from the Ada version.] |
* |
* The following program contains statements of a high level programming |
* language (here: C) in a distribution considered representative: |
* |
* assignments 52 (51.0 %) |
* control statements 33 (32.4 %) |
* procedure, function calls 17 (16.7 %) |
* |
* 103 statements are dynamically executed. The program is balanced with |
* respect to the three aspects: |
* |
* - statement type |
* - operand type |
* - operand locality |
* operand global, local, parameter, or constant. |
* |
* The combination of these three aspects is balanced only approximately. |
* |
* 1. Statement Type: |
* ----------------- number |
* |
* V1 = V2 9 |
* (incl. V1 = F(..) |
* V = Constant 12 |
* Assignment, 7 |
* with array element |
* Assignment, 6 |
* with record component |
* -- |
* 34 34 |
* |
* X = Y +|-|"&&"|"|" Z 5 |
* X = Y +|-|"==" Constant 6 |
* X = X +|- 1 3 |
* X = Y *|/ Z 2 |
* X = Expression, 1 |
* two operators |
* X = Expression, 1 |
* three operators |
* -- |
* 18 18 |
* |
* if .... 14 |
* with "else" 7 |
* without "else" 7 |
* executed 3 |
* not executed 4 |
* for ... 7 | counted every time |
* while ... 4 | the loop condition |
* do ... while 1 | is evaluated |
* switch ... 1 |
* break 1 |
* declaration with 1 |
* initialization |
* -- |
* 34 34 |
* |
* P (...) procedure call 11 |
* user procedure 10 |
* library procedure 1 |
* X = F (...) |
* function call 6 |
* user function 5 |
* library function 1 |
* -- |
* 17 17 |
* --- |
* 103 |
* |
* The average number of parameters in procedure or function calls |
* is 1.82 (not counting the function values as implicit parameters). |
* |
* |
* 2. Operators |
* ------------ |
* number approximate |
* percentage |
* |
* Arithmetic 32 50.8 |
* |
* + 21 33.3 |
* - 7 11.1 |
* * 3 4.8 |
* / (int div) 1 1.6 |
* |
* Comparison 27 42.8 |
* |
* == 9 14.3 |
* /= 4 6.3 |
* > 1 1.6 |
* < 3 4.8 |
* >= 1 1.6 |
* <= 9 14.3 |
* |
* Logic 4 6.3 |
* |
* && (AND-THEN) 1 1.6 |
* | (OR) 1 1.6 |
* ! (NOT) 2 3.2 |
* |
* -- ----- |
* 63 100.1 |
* |
* |
* 3. Operand Type (counted once per operand reference): |
* --------------- |
* number approximate |
* percentage |
* |
* Integer 175 72.3 % |
* Character 45 18.6 % |
* Pointer 12 5.0 % |
* String30 6 2.5 % |
* Array 2 0.8 % |
* Record 2 0.8 % |
* --- ------- |
* 242 100.0 % |
* |
* When there is an access path leading to the final operand (e.g. a |
* record component), only the final data type on the access path is |
* counted. |
* |
* |
* 4. Operand Locality: |
* ------------------- |
* number approximate |
* percentage |
* |
* local variable 114 47.1 % |
* global variable 22 9.1 % |
* parameter 45 18.6 % |
* value 23 9.5 % |
* reference 22 9.1 % |
* function result 6 2.5 % |
* constant 55 22.7 % |
* --- ------- |
* 242 100.0 % |
* |
* |
* The program does not compute anything meaningful, but it is |
* syntactically and semantically correct. All variables have a value |
* assigned to them before they are used as a source operand. |
* |
* There has been no explicit effort to account for the effects of a |
* cache, or to balance the use of long or short displacements for code |
* or data. |
* |
************************************************************************* |
*/ |
|
/* Compiler and system dependent definitions: */ |
|
#define Mic_secs_Per_Second 1000000.0 |
/* Berkeley UNIX C returns process times in seconds/HZ */ |
|
#ifdef NOSTRUCTASSIGN |
#define structassign(d, s) memcpy(&(d), &(s), sizeof(d)) |
#else |
#define structassign(d, s) d = s |
#endif |
|
#ifdef NOENUM |
#define Ident_1 0 |
#define Ident_2 1 |
#define Ident_3 2 |
#define Ident_4 3 |
#define Ident_5 4 |
typedef int Enumeration; |
#else |
typedef enum {Ident_1, Ident_2, Ident_3, Ident_4, Ident_5} |
Enumeration; |
#endif |
/* for boolean and enumeration types in Ada, Pascal */ |
|
/* General definitions: */ |
|
#include <stdio.h> |
/* for strcpy, strcmp */ |
|
#define Null 0 |
/* Value of a Null pointer */ |
#define true 1 |
#define false 0 |
|
typedef int One_Thirty; |
typedef int One_Fifty; |
typedef char Capital_Letter; |
typedef int Boolean; |
typedef char Str_30 [31]; |
typedef int Arr_1_Dim [50]; |
typedef int Arr_2_Dim [50] [50]; |
|
typedef struct record |
{ |
struct record *Ptr_Comp; |
Enumeration Discr; |
union { |
struct { |
Enumeration Enum_Comp; |
int Int_Comp; |
char Str_Comp [31]; |
} var_1; |
struct { |
Enumeration E_Comp_2; |
char Str_2_Comp [31]; |
} var_2; |
struct { |
char Ch_1_Comp; |
char Ch_2_Comp; |
} var_3; |
} variant; |
} Rec_Type, *Rec_Pointer; |
|
#ifdef __ECOS__ |
|
#ifndef ROPT |
#define REG |
/* REG becomes defined as empty */ |
/* i.e. no register variables */ |
#else |
#define REG register |
#endif |
|
Boolean Func_2 (Str_30 Str_1_Par_Ref, Str_30 Str_2_Par_Ref); |
Boolean Func_3 (Enumeration Enum_Par_Val); |
|
void Proc_1 (REG Rec_Pointer Ptr_Val_Par); |
void Proc_2 (One_Fifty* Int_Par_Ref); |
void Proc_3 (Rec_Pointer *Ptr_Ref_Par); |
void Proc_4 (void); |
void Proc_5 (void); |
void Proc_6 (Enumeration Enum_Val_Par, Enumeration* Enum_Ref_Par); |
void Proc_7 (One_Fifty Int_1_Par_Val, One_Fifty Int_2_Par_Val, |
One_Fifty* Int_Par_Ref); |
void Proc_8 (Arr_1_Dim Arr_1_Par_Ref, Arr_2_Dim Arr_2_Par_Ref, |
int Int_1_Par_Val, int Int_2_Par_Val); |
Enumeration Func_1 (Capital_Letter Ch_1_Par_Val, Capital_Letter Ch_2_Par_Val); |
|
#endif // __ECOS__ |
|
/* |
************************************************************************* |
* |
* "DHRYSTONE" Benchmark Program |
* ----------------------------- |
* |
* Version: C, Version 2.1 |
* |
* File: dhry_1.c (part 2 of 3) |
* |
* Date: May 25, 1988 |
* |
* Author: Reinhold P. Weicker |
* |
************************************************************************* |
*/ |
|
#include <stdio.h> |
#ifndef __ECOS__ |
#include "dhry.h" |
#endif // __ECOS__ |
|
/* Global Variables: */ |
|
Rec_Pointer Ptr_Glob, |
Next_Ptr_Glob; |
int Int_Glob; |
Boolean Bool_Glob; |
char Ch_1_Glob, |
Ch_2_Glob; |
int Arr_1_Glob [50]; |
int Arr_2_Glob [50] [50]; |
|
char Reg_Define[] = "Register option selected."; |
|
#ifndef __ECOS__ |
extern char *malloc (); |
Enumeration Func_1 (); |
#endif |
/* |
forward declaration necessary since Enumeration may not simply be int |
*/ |
|
#ifndef __ECOS__ |
#ifndef ROPT |
#define REG |
/* REG becomes defined as empty */ |
/* i.e. no register variables */ |
#else |
#define REG register |
#endif |
#endif |
|
/* variables for time measurement: */ |
|
#define Too_Small_Time 2 |
/* Measurements should last at least 2 seconds */ |
|
double Begin_Time, |
End_Time, |
User_Time; |
|
double Microseconds, |
Dhrystones_Per_Second, |
Vax_Mips; |
|
/* end of variables for time measurement */ |
|
|
#ifndef __ECOS__ |
void main () |
#else // __ECOS__ |
int main (void) |
#endif // __ECOS__ |
/*****/ |
|
/* main program, corresponds to procedures */ |
/* Main and Proc_0 in the Ada version */ |
{ |
#ifndef __ECOS__ |
double dtime(); |
#endif // __ECOS__ |
|
One_Fifty Int_1_Loc; |
REG One_Fifty Int_2_Loc; |
One_Fifty Int_3_Loc; |
REG char Ch_Index; |
Enumeration Enum_Loc; |
Str_30 Str_1_Loc; |
Str_30 Str_2_Loc; |
REG int Run_Index; |
REG int Number_Of_Runs; |
|
|
#ifdef __ECOS__ |
|
CYG_TEST_INIT(); |
|
#ifdef CYG_HAL_I386_LINUX |
CYG_TEST_NA("Only runs on hardware..."); |
#else |
if (cyg_test_is_simulator) |
CYG_TEST_NA("Only runs on hardware..."); |
#endif |
|
#else // __ECOS__ |
FILE *Ap; |
|
/* Initializations */ |
|
if ((Ap = fopen("dhry.res","a+")) == NULL) |
{ |
printf("Can not open dhry.res\n\n"); |
exit(1); |
} |
#endif // __ECOS__ |
|
Next_Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type)); |
Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type)); |
|
Ptr_Glob->Ptr_Comp = Next_Ptr_Glob; |
Ptr_Glob->Discr = Ident_1; |
Ptr_Glob->variant.var_1.Enum_Comp = Ident_3; |
Ptr_Glob->variant.var_1.Int_Comp = 40; |
strcpy (Ptr_Glob->variant.var_1.Str_Comp, |
"DHRYSTONE PROGRAM, SOME STRING"); |
strcpy (Str_1_Loc, "DHRYSTONE PROGRAM, 1'ST STRING"); |
|
Arr_2_Glob [8][7] = 10; |
/* Was missing in published program. Without this statement, */ |
/* Arr_2_Glob [8][7] would have an undefined value. */ |
/* Warning: With 16-Bit processors and Number_Of_Runs > 32000, */ |
/* overflow may occur for this array element. */ |
|
printf ("\n"); |
printf ("Dhrystone Benchmark, Version 2.1 (Language: C)\n"); |
printf ("\n"); |
/* |
if (Reg) |
{ |
printf ("Program compiled with 'register' attribute\n"); |
printf ("\n"); |
} |
else |
{ |
printf ("Program compiled without 'register' attribute\n"); |
printf ("\n"); |
} |
*/ |
#ifdef __ECOS__ |
Number_Of_Runs = PASSES; |
#else // __ECOS__ |
printf ("Please give the number of runs through the benchmark: "); |
{ |
int n; |
scanf ("%d", &n); |
Number_Of_Runs = n; |
} |
printf ("\n"); |
#endif // __ECOS__ |
|
printf ("Execution starts, %d runs through Dhrystone\n",Number_Of_Runs); |
|
/***************/ |
/* Start timer */ |
/***************/ |
|
Begin_Time = dtime(); |
|
for (Run_Index = 1; Run_Index <= Number_Of_Runs; ++Run_Index) |
{ |
|
Proc_5(); |
Proc_4(); |
/* Ch_1_Glob == 'A', Ch_2_Glob == 'B', Bool_Glob == true */ |
Int_1_Loc = 2; |
Int_2_Loc = 3; |
strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 2'ND STRING"); |
Enum_Loc = Ident_2; |
Bool_Glob = ! Func_2 (Str_1_Loc, Str_2_Loc); |
/* Bool_Glob == 1 */ |
while (Int_1_Loc < Int_2_Loc) /* loop body executed once */ |
{ |
Int_3_Loc = 5 * Int_1_Loc - Int_2_Loc; |
/* Int_3_Loc == 7 */ |
Proc_7 (Int_1_Loc, Int_2_Loc, &Int_3_Loc); |
/* Int_3_Loc == 7 */ |
Int_1_Loc += 1; |
} /* while */ |
/* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */ |
Proc_8 (Arr_1_Glob, Arr_2_Glob, Int_1_Loc, Int_3_Loc); |
/* Int_Glob == 5 */ |
Proc_1 (Ptr_Glob); |
for (Ch_Index = 'A'; Ch_Index <= Ch_2_Glob; ++Ch_Index) |
/* loop body executed twice */ |
{ |
if (Enum_Loc == Func_1 (Ch_Index, 'C')) |
/* then, not executed */ |
{ |
Proc_6 (Ident_1, &Enum_Loc); |
strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 3'RD STRING"); |
Int_2_Loc = Run_Index; |
Int_Glob = Run_Index; |
} |
} |
/* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */ |
Int_2_Loc = Int_2_Loc * Int_1_Loc; |
Int_1_Loc = Int_2_Loc / Int_3_Loc; |
Int_2_Loc = 7 * (Int_2_Loc - Int_3_Loc) - Int_1_Loc; |
/* Int_1_Loc == 1, Int_2_Loc == 13, Int_3_Loc == 7 */ |
Proc_2 (&Int_1_Loc); |
/* Int_1_Loc == 5 */ |
|
} /* loop "for Run_Index" */ |
|
/**************/ |
/* Stop timer */ |
/**************/ |
|
End_Time = dtime(); |
|
printf ("Execution ends\n"); |
printf ("\n"); |
printf ("Final values of the variables used in the benchmark:\n"); |
printf ("\n"); |
printf ("Int_Glob: %d\n", Int_Glob); |
printf (" should be: %d\n", 5); |
printf ("Bool_Glob: %d\n", Bool_Glob); |
printf (" should be: %d\n", 1); |
printf ("Ch_1_Glob: %c\n", Ch_1_Glob); |
printf (" should be: %c\n", 'A'); |
printf ("Ch_2_Glob: %c\n", Ch_2_Glob); |
printf (" should be: %c\n", 'B'); |
printf ("Arr_1_Glob[8]: %d\n", Arr_1_Glob[8]); |
printf (" should be: %d\n", 7); |
printf ("Arr_2_Glob[8][7]: %d\n", Arr_2_Glob[8][7]); |
printf (" should be: Number_Of_Runs + 10\n"); |
printf ("Ptr_Glob->\n"); |
printf (" Ptr_Comp: %d\n", (int) Ptr_Glob->Ptr_Comp); |
printf (" should be: (implementation-dependent)\n"); |
printf (" Discr: %d\n", Ptr_Glob->Discr); |
printf (" should be: %d\n", 0); |
printf (" Enum_Comp: %d\n", Ptr_Glob->variant.var_1.Enum_Comp); |
printf (" should be: %d\n", 2); |
printf (" Int_Comp: %d\n", Ptr_Glob->variant.var_1.Int_Comp); |
printf (" should be: %d\n", 17); |
printf (" Str_Comp: %s\n", Ptr_Glob->variant.var_1.Str_Comp); |
printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n"); |
printf ("Next_Ptr_Glob->\n"); |
printf (" Ptr_Comp: %d\n", (int) Next_Ptr_Glob->Ptr_Comp); |
printf (" should be: (implementation-dependent), same as above\n"); |
printf (" Discr: %d\n", Next_Ptr_Glob->Discr); |
printf (" should be: %d\n", 0); |
printf (" Enum_Comp: %d\n", Next_Ptr_Glob->variant.var_1.Enum_Comp); |
printf (" should be: %d\n", 1); |
printf (" Int_Comp: %d\n", Next_Ptr_Glob->variant.var_1.Int_Comp); |
printf (" should be: %d\n", 18); |
printf (" Str_Comp: %s\n", Next_Ptr_Glob->variant.var_1.Str_Comp); |
printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n"); |
printf ("Int_1_Loc: %d\n", Int_1_Loc); |
printf (" should be: %d\n", 5); |
printf ("Int_2_Loc: %d\n", Int_2_Loc); |
printf (" should be: %d\n", 13); |
printf ("Int_3_Loc: %d\n", Int_3_Loc); |
printf (" should be: %d\n", 7); |
printf ("Enum_Loc: %d\n", Enum_Loc); |
printf (" should be: %d\n", 1); |
printf ("Str_1_Loc: %s\n", Str_1_Loc); |
printf (" should be: DHRYSTONE PROGRAM, 1'ST STRING\n"); |
printf ("Str_2_Loc: %s\n", Str_2_Loc); |
printf (" should be: DHRYSTONE PROGRAM, 2'ND STRING\n"); |
printf ("\n"); |
|
User_Time = End_Time - Begin_Time; |
|
if (User_Time < Too_Small_Time) |
{ |
printf ("Measured time too small to obtain meaningful results\n"); |
printf ("Please increase number of runs\n"); |
printf ("\n"); |
} |
else |
{ |
Microseconds = User_Time * Mic_secs_Per_Second |
/ (double) Number_Of_Runs; |
Dhrystones_Per_Second = (double) Number_Of_Runs / User_Time; |
Vax_Mips = Dhrystones_Per_Second / 1757.0; |
|
#ifdef ROPT |
printf ("Register option selected? YES\n"); |
#else |
printf ("Register option selected? NO\n"); |
#ifndef __ECOS__ |
strcpy(Reg_Define, "Register option not selected."); |
#endif // __ECOS__ |
#endif |
printf ("Microseconds for one run through Dhrystone: "); |
#ifdef __ECOS__ |
printf ("%7.1f \n", Microseconds); |
printf ("Dhrystones per Second: "); |
printf ("%10.1f \n", Dhrystones_Per_Second); |
printf ("VAX MIPS rating = %10.3f \n",Vax_Mips); |
printf ("\n"); |
#else // __ECOS__ |
printf ("%7.1lf \n", Microseconds); |
printf ("Dhrystones per Second: "); |
printf ("%10.1lf \n", Dhrystones_Per_Second); |
printf ("VAX MIPS rating = %10.3lf \n",Vax_Mips); |
printf ("\n"); |
|
fprintf(Ap,"\n"); |
fprintf(Ap,"Dhrystone Benchmark, Version 2.1 (Language: C)\n"); |
fprintf(Ap,"%s\n",Reg_Define); |
fprintf(Ap,"Microseconds for one loop: %7.1lf\n",Microseconds); |
fprintf(Ap,"Dhrystones per second: %10.1lf\n",Dhrystones_Per_Second); |
fprintf(Ap,"VAX MIPS rating: %10.3lf\n",Vax_Mips); |
fclose(Ap); |
#endif // __ECOS__ |
} |
|
#ifdef __ECOS__ |
CYG_TEST_PASS_FINISH("Dhrystone test"); |
#endif // __ECOS__ |
} |
|
|
#ifdef __ECOS__ |
void |
#endif // __ECOS__ |
Proc_1 (Ptr_Val_Par) |
/******************/ |
|
REG Rec_Pointer Ptr_Val_Par; |
/* executed once */ |
{ |
REG Rec_Pointer Next_Record = Ptr_Val_Par->Ptr_Comp; |
/* == Ptr_Glob_Next */ |
/* Local variable, initialized with Ptr_Val_Par->Ptr_Comp, */ |
/* corresponds to "rename" in Ada, "with" in Pascal */ |
|
structassign (*Ptr_Val_Par->Ptr_Comp, *Ptr_Glob); |
Ptr_Val_Par->variant.var_1.Int_Comp = 5; |
Next_Record->variant.var_1.Int_Comp |
= Ptr_Val_Par->variant.var_1.Int_Comp; |
Next_Record->Ptr_Comp = Ptr_Val_Par->Ptr_Comp; |
Proc_3 (&Next_Record->Ptr_Comp); |
/* Ptr_Val_Par->Ptr_Comp->Ptr_Comp |
== Ptr_Glob->Ptr_Comp */ |
if (Next_Record->Discr == Ident_1) |
/* then, executed */ |
{ |
Next_Record->variant.var_1.Int_Comp = 6; |
Proc_6 (Ptr_Val_Par->variant.var_1.Enum_Comp, |
&Next_Record->variant.var_1.Enum_Comp); |
Next_Record->Ptr_Comp = Ptr_Glob->Ptr_Comp; |
Proc_7 (Next_Record->variant.var_1.Int_Comp, 10, |
&Next_Record->variant.var_1.Int_Comp); |
} |
else /* not executed */ |
structassign (*Ptr_Val_Par, *Ptr_Val_Par->Ptr_Comp); |
} /* Proc_1 */ |
|
|
#ifdef __ECOS__ |
void |
#endif // __ECOS__ |
Proc_2 (Int_Par_Ref) |
/******************/ |
/* executed once */ |
/* *Int_Par_Ref == 1, becomes 4 */ |
|
One_Fifty *Int_Par_Ref; |
{ |
One_Fifty Int_Loc; |
#ifdef __ECOS__ |
Enumeration Enum_Loc = Ident_1; |
#else // __ECOS__ |
Enumeration Enum_Loc; |
#endif // __ECOS__ |
|
Int_Loc = *Int_Par_Ref + 10; |
do /* executed once */ |
if (Ch_1_Glob == 'A') |
/* then, executed */ |
{ |
Int_Loc -= 1; |
*Int_Par_Ref = Int_Loc - Int_Glob; |
Enum_Loc = Ident_1; |
} /* if */ |
while (Enum_Loc != Ident_1); /* true */ |
} /* Proc_2 */ |
|
|
#ifdef __ECOS__ |
void |
#endif // __ECOS__ |
Proc_3 (Ptr_Ref_Par) |
/******************/ |
/* executed once */ |
/* Ptr_Ref_Par becomes Ptr_Glob */ |
|
Rec_Pointer *Ptr_Ref_Par; |
|
{ |
if (Ptr_Glob != Null) |
/* then, executed */ |
*Ptr_Ref_Par = Ptr_Glob->Ptr_Comp; |
Proc_7 (10, Int_Glob, &Ptr_Glob->variant.var_1.Int_Comp); |
} /* Proc_3 */ |
|
|
#ifdef __ECOS__ |
void |
#endif // __ECOS__ |
Proc_4 () /* without parameters */ |
/*******/ |
/* executed once */ |
{ |
Boolean Bool_Loc; |
|
Bool_Loc = Ch_1_Glob == 'A'; |
Bool_Glob = Bool_Loc | Bool_Glob; |
Ch_2_Glob = 'B'; |
} /* Proc_4 */ |
|
|
#ifdef __ECOS__ |
void |
#endif // __ECOS__ |
Proc_5 () /* without parameters */ |
/*******/ |
/* executed once */ |
{ |
Ch_1_Glob = 'A'; |
Bool_Glob = false; |
} /* Proc_5 */ |
|
|
/* Procedure for the assignment of structures, */ |
/* if the C compiler doesn't support this feature */ |
#ifdef NOSTRUCTASSIGN |
memcpy (d, s, l) |
register char *d; |
register char *s; |
register int l; |
{ |
while (l--) *d++ = *s++; |
} |
#endif |
|
/* |
************************************************************************* |
* |
* "DHRYSTONE" Benchmark Program |
* ----------------------------- |
* |
* Version: C, Version 2.1 |
* |
* File: dhry_2.c (part 3 of 3) |
* |
* Date: May 25, 1988 |
* |
* Author: Reinhold P. Weicker |
* |
************************************************************************* |
*/ |
|
#ifndef __ECOS__ |
#include "dhry.h" |
|
#ifndef REG |
#define REG |
/* REG becomes defined as empty */ |
/* i.e. no register variables */ |
#else |
#define REG register |
#endif |
#endif // __ECOS__ |
|
extern int Int_Glob; |
extern char Ch_1_Glob; |
|
#ifdef __ECOS__ |
void |
#endif // __ECOS__ |
Proc_6 (Enum_Val_Par, Enum_Ref_Par) |
/*********************************/ |
/* executed once */ |
/* Enum_Val_Par == Ident_3, Enum_Ref_Par becomes Ident_2 */ |
|
Enumeration Enum_Val_Par; |
Enumeration *Enum_Ref_Par; |
{ |
*Enum_Ref_Par = Enum_Val_Par; |
if (! Func_3 (Enum_Val_Par)) |
/* then, not executed */ |
*Enum_Ref_Par = Ident_4; |
switch (Enum_Val_Par) |
{ |
case Ident_1: |
*Enum_Ref_Par = Ident_1; |
break; |
case Ident_2: |
if (Int_Glob > 100) |
/* then */ |
*Enum_Ref_Par = Ident_1; |
else *Enum_Ref_Par = Ident_4; |
break; |
case Ident_3: /* executed */ |
*Enum_Ref_Par = Ident_2; |
break; |
case Ident_4: break; |
case Ident_5: |
*Enum_Ref_Par = Ident_3; |
break; |
} /* switch */ |
} /* Proc_6 */ |
|
|
#ifdef __ECOS__ |
void |
#endif // __ECOS__ |
Proc_7 (Int_1_Par_Val, Int_2_Par_Val, Int_Par_Ref) |
/**********************************************/ |
/* executed three times */ |
/* first call: Int_1_Par_Val == 2, Int_2_Par_Val == 3, */ |
/* Int_Par_Ref becomes 7 */ |
/* second call: Int_1_Par_Val == 10, Int_2_Par_Val == 5, */ |
/* Int_Par_Ref becomes 17 */ |
/* third call: Int_1_Par_Val == 6, Int_2_Par_Val == 10, */ |
/* Int_Par_Ref becomes 18 */ |
One_Fifty Int_1_Par_Val; |
One_Fifty Int_2_Par_Val; |
One_Fifty *Int_Par_Ref; |
{ |
One_Fifty Int_Loc; |
|
Int_Loc = Int_1_Par_Val + 2; |
*Int_Par_Ref = Int_2_Par_Val + Int_Loc; |
} /* Proc_7 */ |
|
|
#ifdef __ECOS__ |
void |
#endif // __ECOS__ |
Proc_8 (Arr_1_Par_Ref, Arr_2_Par_Ref, Int_1_Par_Val, Int_2_Par_Val) |
/*********************************************************************/ |
/* executed once */ |
/* Int_Par_Val_1 == 3 */ |
/* Int_Par_Val_2 == 7 */ |
Arr_1_Dim Arr_1_Par_Ref; |
Arr_2_Dim Arr_2_Par_Ref; |
int Int_1_Par_Val; |
int Int_2_Par_Val; |
{ |
REG One_Fifty Int_Index; |
REG One_Fifty Int_Loc; |
|
Int_Loc = Int_1_Par_Val + 5; |
Arr_1_Par_Ref [Int_Loc] = Int_2_Par_Val; |
Arr_1_Par_Ref [Int_Loc+1] = Arr_1_Par_Ref [Int_Loc]; |
Arr_1_Par_Ref [Int_Loc+30] = Int_Loc; |
for (Int_Index = Int_Loc; Int_Index <= Int_Loc+1; ++Int_Index) |
Arr_2_Par_Ref [Int_Loc] [Int_Index] = Int_Loc; |
Arr_2_Par_Ref [Int_Loc] [Int_Loc-1] += 1; |
Arr_2_Par_Ref [Int_Loc+20] [Int_Loc] = Arr_1_Par_Ref [Int_Loc]; |
Int_Glob = 5; |
} /* Proc_8 */ |
|
|
Enumeration Func_1 (Ch_1_Par_Val, Ch_2_Par_Val) |
/*************************************************/ |
/* executed three times */ |
/* first call: Ch_1_Par_Val == 'H', Ch_2_Par_Val == 'R' */ |
/* second call: Ch_1_Par_Val == 'A', Ch_2_Par_Val == 'C' */ |
/* third call: Ch_1_Par_Val == 'B', Ch_2_Par_Val == 'C' */ |
|
Capital_Letter Ch_1_Par_Val; |
Capital_Letter Ch_2_Par_Val; |
{ |
Capital_Letter Ch_1_Loc; |
Capital_Letter Ch_2_Loc; |
|
Ch_1_Loc = Ch_1_Par_Val; |
Ch_2_Loc = Ch_1_Loc; |
if (Ch_2_Loc != Ch_2_Par_Val) |
/* then, executed */ |
return (Ident_1); |
else /* not executed */ |
{ |
Ch_1_Glob = Ch_1_Loc; |
return (Ident_2); |
} |
} /* Func_1 */ |
|
|
Boolean Func_2 (Str_1_Par_Ref, Str_2_Par_Ref) |
/*************************************************/ |
/* executed once */ |
/* Str_1_Par_Ref == "DHRYSTONE PROGRAM, 1'ST STRING" */ |
/* Str_2_Par_Ref == "DHRYSTONE PROGRAM, 2'ND STRING" */ |
|
Str_30 Str_1_Par_Ref; |
Str_30 Str_2_Par_Ref; |
{ |
REG One_Thirty Int_Loc; |
#ifdef __ECOS__ |
Capital_Letter Ch_Loc = 'A'; |
#else // __ECOS__ |
Capital_Letter Ch_Loc; |
#endif // __ECOS__ |
|
Int_Loc = 2; |
while (Int_Loc <= 2) /* loop body executed once */ |
if (Func_1 (Str_1_Par_Ref[Int_Loc], |
Str_2_Par_Ref[Int_Loc+1]) == Ident_1) |
/* then, executed */ |
{ |
Ch_Loc = 'A'; |
Int_Loc += 1; |
} /* if, while */ |
if (Ch_Loc >= 'W' && Ch_Loc < 'Z') |
/* then, not executed */ |
Int_Loc = 7; |
if (Ch_Loc == 'R') |
/* then, not executed */ |
return (true); |
else /* executed */ |
{ |
if (strcmp (Str_1_Par_Ref, Str_2_Par_Ref) > 0) |
/* then, not executed */ |
{ |
Int_Loc += 7; |
Int_Glob = Int_Loc; |
return (true); |
} |
else /* executed */ |
return (false); |
} /* if Ch_Loc */ |
} /* Func_2 */ |
|
|
Boolean Func_3 (Enum_Par_Val) |
/***************************/ |
/* executed once */ |
/* Enum_Par_Val == Ident_3 */ |
Enumeration Enum_Par_Val; |
{ |
Enumeration Enum_Loc; |
|
Enum_Loc = Enum_Par_Val; |
if (Enum_Loc == Ident_3) |
/* then, executed */ |
return (true); |
else /* not executed */ |
return (false); |
} /* Func_3 */ |
|
#else /* ifndef NA_MSG */ |
|
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA(NA_MSG); |
} |
#endif |
/testaux.hxx
0,0 → 1,110
#ifndef CYGONCE_KERNEL_TESTS_TESTAUX_HXX |
#define CYGONCE_KERNEL_TESTS_TESTAUX_HXX |
|
//========================================================================== |
// |
// testaux.hxx |
// |
// Auxiliary test header file |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-03-09 |
// Description: |
// Defines some convenience functions to get us going. In |
// particular this file reserves space for NTHREADS threads, |
// which can be created by calls to aux_new_thread() |
// It also defines a CHECK function. |
// |
//####DESCRIPTIONEND#### |
|
|
static inline void *operator new(size_t size, void *ptr) { return ptr; }; |
|
|
#include <pkgconf/hal.h> |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
externC void |
cyg_hal_invoke_constructors(); |
#endif |
|
#ifdef NTHREADS |
|
#ifndef STACKSIZE |
#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL |
#endif |
|
static Cyg_Thread *thread[NTHREADS]; |
|
typedef CYG_WORD64 CYG_ALIGNMENT_TYPE; |
|
static CYG_ALIGNMENT_TYPE thread_obj[NTHREADS] [ |
(sizeof(Cyg_Thread)+sizeof(CYG_ALIGNMENT_TYPE)-1) |
/ sizeof(CYG_ALIGNMENT_TYPE) ]; |
|
static CYG_ALIGNMENT_TYPE stack[NTHREADS] [ |
(STACKSIZE+sizeof(CYG_ALIGNMENT_TYPE)-1) |
/ sizeof(CYG_ALIGNMENT_TYPE) ]; |
|
static volatile int nthreads = 0; |
|
static Cyg_Thread *new_thread(cyg_thread_entry *entry, CYG_ADDRWORD data) |
{ |
int _nthreads = nthreads++; |
|
CYG_ASSERT(_nthreads < NTHREADS, |
"Attempt to create more than NTHREADS threads"); |
|
thread[_nthreads] = new( (void *)&thread_obj[_nthreads] ) |
Cyg_Thread(CYG_SCHED_DEFAULT_INFO, |
entry, data, |
NULL, // no name |
(CYG_ADDRESS)stack[_nthreads], STACKSIZE ); |
|
thread[_nthreads]->resume(); |
|
return thread[_nthreads]; |
} |
#endif // defined(NTHREADS) |
|
#define CHECK(b) CYG_TEST_CHECK(b,#b) |
|
#endif // ifndef CYGONCE_KERNEL_TESTS_TESTAUX_HXX |
|
// End of testaux.hxx |
/ksched1.c
0,0 → 1,103
/*================================================================= |
// |
// ksched1.c |
// |
// Kernel C API Sched test 1 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-03-23 |
// Description: Simply checks the world starts |
//####DESCRIPTIONEND#### |
*/ |
|
#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
#include <cyg/kernel/kapi.h> |
|
#include <cyg/infra/testcase.h> |
|
#ifdef CYGFUN_KERNEL_API_C |
|
#include "testaux.h" |
|
#define NTHREADS 2 |
#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
static cyg_handle_t thread[NTHREADS]; |
|
static cyg_thread thread_obj[NTHREADS]; |
static char stack[NTHREADS][STACKSIZE]; |
|
|
static void entry0( cyg_addrword_t data ) |
{ |
CHECK( 222 == (int)data ); |
CYG_TEST_PASS_FINISH( "Kernel C API Sched 1 OK"); |
} |
|
void ksched1_main(void) |
{ |
CYG_TEST_INIT(); |
|
cyg_thread_create( 4, entry0 , (cyg_addrword_t)222, "ksched1", |
(void *)stack[0], STACKSIZE, &thread[0], &thread_obj[0]); |
cyg_thread_resume(thread[0]); |
|
cyg_scheduler_start(); |
|
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
externC void |
cyg_start( void ) |
{ |
ksched1_main(); |
} |
|
#else /* def CYGFUN_KERNEL_API_C */ |
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA("Kernel C API layer disabled"); |
} |
#endif /* def CYGFUN_KERNEL_API_C */ |
|
/* EOF ksched1.c */ |
/thread_gdb.c
0,0 → 1,413
//========================================================================== |
// |
// 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 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-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 |
|
// ------------------------------------------------------------------------- |
|
#define THREADS 10 |
|
#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 |
/kclock0.c
0,0 → 1,274
/*================================================================= |
// |
// kclock0.c |
// |
// Kernel C API Clock test 0 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-03-20 |
// Description: Tests some basic clock functions. |
//####DESCRIPTIONEND#### |
*/ |
|
#include <cyg/kernel/kapi.h> |
|
#include <cyg/infra/testcase.h> |
|
#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK |
|
#ifdef CYGFUN_KERNEL_API_C |
|
#include "testaux.h" |
|
cyg_alarm_t call_me; |
|
cyg_counter counter0o, counter1o; |
cyg_handle_t counter0, counter1; |
|
cyg_alarm alarmo[3]; |
cyg_handle_t alarm0, alarm1, alarm2; |
|
cyg_resolution_t res, res0, res1; |
|
cyg_clock clock0o; |
cyg_handle_t clock0; |
|
const cyg_uint32 big_number = 3333222111u; |
|
cyg_bool_t flash( void ) |
{ |
cyg_counter_create( &counter0, &counter0o ); |
cyg_counter_create( &counter1, &counter1o ); |
|
cyg_alarm_create( counter0, |
call_me, |
(cyg_addrword_t)12, |
&alarm0, |
&alarmo[0]); |
|
res.dividend = 1; |
res.divisor = 2; |
|
cyg_clock_create( res, &clock0, &clock0o ); |
cyg_clock_delete( clock0 ); |
|
cyg_alarm_delete( alarm0 ); |
|
cyg_counter_delete( counter0 ); |
cyg_counter_delete( counter1 ); |
|
return true; |
} |
|
/* Testing alarms |
// |
// call_me is a function that will be called when an alarm is |
// triggered. It updates a global variable called which is CHECKed |
// explicitly to see if the approriate alarms have been called. |
*/ |
|
cyg_uint16 called = 0x0; |
|
void call_me(cyg_handle_t alarm, cyg_addrword_t data) |
{ |
called ^= (int)data; |
} |
|
void call_me2(cyg_handle_t alarm, cyg_addrword_t data) |
{ |
call_me(alarm, (cyg_addrword_t)((int)data^0x10)); |
} |
|
|
void kclock0_main(void) |
{ |
CYG_TEST_INIT(); |
|
CHECK(flash()); |
CHECK(flash()); |
|
cyg_counter_create( &counter0, &counter0o); |
|
CHECK( 0 == cyg_counter_current_value( counter0 ) ); |
|
cyg_counter_tick(counter0); |
|
CHECK( 1 == cyg_counter_current_value(counter0) ); |
|
cyg_counter_tick(counter0); |
|
CHECK( 2 == cyg_counter_current_value(counter0) ); |
|
cyg_counter_set_value( counter0, 0xffffffff ); |
|
CHECK( 0xffffffff == cyg_counter_current_value(counter0) ); |
|
cyg_counter_tick(counter0); // Overflows 32 bits |
|
CHECK( 0x100000000ULL == cyg_counter_current_value(counter0) ); |
|
cyg_counter_set_value(counter0, 11); |
CHECK( 11 == cyg_counter_current_value(counter0) ); |
|
/* the call_me functions cause the "called" bits to toggle |
// checking the value of called checks the parity of # of calls |
// made by each alarm. |
*/ |
|
cyg_alarm_create(counter0, |
call_me, (cyg_addrword_t)0x1, &alarm0, &alarmo[0]); |
cyg_alarm_create(counter0, |
call_me, (cyg_addrword_t)0x2, &alarm1, &alarmo[1]); |
cyg_alarm_create(counter0, |
call_me2, (cyg_addrword_t)0x4, &alarm2, &alarmo[2]); |
|
CHECK( 0x00 == called ); |
cyg_alarm_initialize(alarm0, 12,3); |
cyg_alarm_initialize(alarm2, 21,2); |
CHECK( 0x00 == called ); |
|
cyg_counter_tick(counter0); /* 12 a0 */ |
CHECK( 0x01 == called ); |
|
cyg_alarm_initialize(alarm1, 13,0); |
cyg_counter_tick(counter0); /* 13 a1 */ |
CHECK( 0x03 == called ); |
|
cyg_alarm_initialize(alarm1, 17,0); |
cyg_counter_tick(counter0); /* 14 */ |
CHECK( 0x03 == called ); |
|
cyg_counter_tick(counter0); /* 15 a0 */ |
CHECK( 0x02 == called ); |
|
cyg_counter_tick(counter0); /* 16 */ |
cyg_counter_tick(counter0); /* 17 a1 */ |
CHECK( 0x00 == called ); |
|
cyg_counter_tick(counter0); /* 18 a0 */ |
CHECK( 0x01 == called ); |
|
cyg_counter_tick(counter0); /* 19 */ |
cyg_counter_tick(counter0); /* 20 */ |
cyg_counter_tick(counter0); /* 21 a0 a2 */ |
CHECK( 0x14 == called ); |
|
cyg_counter_tick(counter0); /* 22 */ |
cyg_counter_tick(counter0); /* 23 a2 */ |
CHECK( 0x00 == called ); |
|
cyg_alarm_disable(alarm2); |
|
cyg_counter_tick(counter0); /* 24 a0 */ |
cyg_counter_tick(counter0); /* 25 */ |
CHECK( 0x01 == called ); |
|
cyg_alarm_enable(alarm2); /* a2 (enabled at 25) */ |
CHECK( 0x15 == called ); |
|
cyg_counter_tick(counter0); /* 26 */ |
CHECK( 0x15 == called ); |
|
cyg_counter_tick(counter0); /* 27 a0 a2 */ |
cyg_counter_tick(counter0); /* 28 */ |
CHECK( 0x00 == called ); |
|
cyg_counter_tick(counter0); /* 29 a2 */ |
cyg_counter_tick(counter0); /* 30 a0 */ |
cyg_counter_tick(counter0); /* 31 a2 */ |
CHECK( 0x01 == called ); |
|
res0.dividend = 100; |
res0.divisor = 3; |
|
cyg_clock_create( res0, &clock0, &clock0o ); |
|
res1 = cyg_clock_get_resolution(clock0); |
CHECK( res0.dividend == res1.dividend ); |
CHECK( res0.divisor == res1.divisor ); |
|
res1.dividend = 12; |
res1.divisor = 25; |
|
cyg_clock_set_resolution(clock0, res1); |
res0 = cyg_clock_get_resolution(clock0); |
CHECK( res0.dividend == res1.dividend ); |
CHECK( res0.divisor == res1.divisor ); |
|
cyg_clock_to_counter(clock0, &counter1); |
|
CHECK( 0 == cyg_counter_current_value( counter1 ) ); |
CHECK( 0 == cyg_current_time() ); |
|
cyg_counter_tick(counter1); |
|
CHECK( 1 == cyg_counter_current_value(counter1) ); |
|
res0 = cyg_clock_get_resolution(cyg_real_time_clock()); |
|
/* Current time should be 0 as interrupts will still be disabled */ |
CHECK( 0 == cyg_current_time() ); |
|
CYG_TEST_PASS_FINISH("Kernel C API Clock 0 OK"); |
} |
|
externC void |
cyg_start( void ) |
{ |
kclock0_main(); |
} |
|
#else // def CYGFUN_KERNEL_API_C |
#define N_A_MSG "Kernel C API layer disabled" |
#endif // def CYGFUN_KERNEL_API_C |
#else // def CYGVAR_KERNEL_COUNTERS_CLOCK |
#define N_A_MSG "Kernel real-time clock disabled" |
#endif // def CYGVAR_KERNEL_COUNTERS_CLOCK |
|
#ifdef N_A_MSG |
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA( N_A_MSG ); |
} |
#endif // N_A_MSG |
|
// EOF kclock0.c |
/kclock1.c
0,0 → 1,153
/*================================================================= |
// |
// kclock1.c |
// |
// Kernel C API Clock test 1 - Real Time Clock |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-03-20 |
// Description: Tests the Kernel Real Time Clock |
// This test creates a thread, starts the scheduler and |
// delays for a time of about 5 seconds. This test should |
// be expected to run for about this length of time. |
// Omissions: |
// Doesn't test alarms attached to RTC. |
// Assumptions: |
// CYGVAR_KERNEL_COUNTERS_CLOCK must be set. |
// Resolution of clock small compared with 5s. |
// Overhead small compared with 5s. |
// Options: |
// CYGIMP_KERNEL_COUNTERS_SINGLE_LIST |
// CYGIMP_KERNEL_COUNTERS_MULTI_LIST |
// CYGVAR_KERNEL_COUNTERS_CLOCK |
// CYGNUM_KERNEL_COUNTERS_MULTI_LIST_SIZE |
//####DESCRIPTIONEND#### |
*/ |
|
#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
#include <cyg/kernel/kapi.h> |
|
#include <cyg/infra/testcase.h> |
|
|
static cyg_uint64 TEST_DELAY; |
|
#ifdef CYGFUN_KERNEL_THREADS_TIMER |
|
#ifdef CYGFUN_KERNEL_API_C |
|
#include "testaux.h" |
|
#define NTHREADS 1 |
#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
static cyg_handle_t thread[NTHREADS]; |
|
static cyg_thread thread_obj[NTHREADS]; |
static char stack[NTHREADS][STACKSIZE]; |
|
static void entry0( cyg_addrword_t data ) |
{ |
cyg_resolution_t res; |
cyg_uint32 ticks; |
cyg_tick_count_t count0, count1; |
cyg_handle_t rtclock, rtcounter; |
|
rtclock = cyg_real_time_clock(); |
cyg_clock_to_counter(rtclock, &rtcounter); |
|
res = cyg_clock_get_resolution (rtclock); |
|
/* RTC takes res.dividend/res.divisor ns/tick */ |
ticks = ((cyg_uint64)TEST_DELAY * res.divisor) / res.dividend; |
|
count0 = cyg_counter_current_value(rtcounter); |
cyg_thread_delay(ticks); |
count1 = cyg_counter_current_value(rtcounter); |
|
CYG_TEST_CHECK(count0+ticks <= count1, |
"real time clock's counter not counting"); |
|
CYG_TEST_CHECK(count1 <= cyg_current_time(),"cyg_current_time()"); |
|
CYG_TEST_PASS_FINISH("Kernel C API Clock 1 OK"); |
} |
|
void kclock1_main( void ) |
{ |
CYG_TEST_INIT(); |
|
if (cyg_test_is_simulator) { |
TEST_DELAY = 100000000ll; |
} else { |
TEST_DELAY = 3000000000ll; |
} |
|
cyg_thread_create(4, entry0 , (cyg_addrword_t)0, "kclock1", |
(void *)stack[0], STACKSIZE, &thread[0], &thread_obj[0]); |
cyg_thread_resume(thread[0]); |
|
cyg_scheduler_start(); |
} |
|
externC void |
cyg_start( void ) |
{ |
kclock1_main(); |
} |
|
#else // def CYGFUN_KERNEL_API_C |
#define N_A_MSG "Kernel C API layer disabled" |
#endif // def CYGFUN_KERNEL_API_C |
#else // def CYGFUN_KERNEL_THREADS_TIMER |
#define N_A_MSG "Kernel threads timer disabled" |
#endif // def CYGFUN_KERNEL_THREADS_TIMER |
|
#ifdef N_A_MSG |
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA( N_A_MSG ); |
} |
#endif // N_A_MSG |
|
// EOF kclock1.c |
/sched1.cxx
0,0 → 1,111
//========================================================================== |
// |
// sched1.cxx |
// |
// Sched test 1 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-02-26 |
// Description: Tests some basic sched functions. |
// Omissions: |
// Doesn't test Cyg_Scheduler::get_thread_switches() very well |
// Cyg_SchedThread |
// inherit_priority |
// disinherit_priority |
// Options: |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/sched.hxx> // Cyg_Scheduler::start() |
#include <cyg/kernel/thread.hxx> // Cyg_Thread |
|
#include <cyg/infra/testcase.h> |
|
#include <cyg/kernel/sched.inl> |
#include <cyg/kernel/thread.inl> |
|
#define NTHREADS 2 |
|
#include "testaux.hxx" |
|
static void entry0( CYG_ADDRWORD data ) |
{ |
CHECK( 0 == Cyg_Scheduler::get_sched_lock() ); |
Cyg_Scheduler::lock(); { |
CHECK( 1 == Cyg_Scheduler::get_sched_lock() ); |
Cyg_Scheduler::lock(); { |
CHECK( 2 == Cyg_Scheduler::get_sched_lock() ); |
} Cyg_Scheduler::unlock(); |
} Cyg_Scheduler::unlock(); |
cyg_ucount32 t0=Cyg_Scheduler::get_thread_switches(); |
cyg_ucount32 t1=Cyg_Scheduler::get_thread_switches(); |
CHECK( t1 >= t0 ); |
CHECK( Cyg_Scheduler::get_current_thread() == |
Cyg_Thread::self() ); |
CYG_TEST_PASS_FINISH( "Sched 1 OK"); |
} |
|
static void entry1( CYG_ADDRWORD data ) |
{ |
Cyg_Thread::self()->sleep(); |
} |
|
void sched1_main(void) |
{ |
CYG_TEST_INIT(); |
|
new_thread(entry0, 222); |
new_thread(entry1, 333); |
|
Cyg_Scheduler::start(); |
|
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
sched1_main(); |
} |
// EOF sched1.cxx |
/except1.cxx
0,0 → 1,271
//================================================================= |
// |
// except1.cxx |
// |
// Exception test 1 |
// |
//================================================================= |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//================================================================= |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm, jlarmour |
// Date: 1999-02-16 |
// Description: Test basic exception functionality |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/infra/testcase.h> |
|
#ifdef CYGPKG_KERNEL_EXCEPTIONS |
|
#include <cyg/kernel/sched.hxx> // Cyg_Scheduler::start() |
#include <cyg/kernel/thread.hxx> // Cyg_Thread |
#include <cyg/kernel/intr.hxx> // cyg_VSR |
|
#include <cyg/hal/hal_intr.h> // exception ranges |
|
#include <cyg/kernel/sched.inl> |
#include <cyg/kernel/thread.inl> |
|
#define NTHREADS 1 |
#include "testaux.hxx" |
|
#ifndef CYGPKG_HAL_ARM_PID |
#define EXCEPTION_DATA_ACCESS |
#endif |
|
static int d0; |
#ifdef EXCEPTION_DATA_ACCESS |
static cyg_exception_handler handler0; |
|
static void handler0(CYG_ADDRWORD data, cyg_code number, CYG_ADDRWORD info) |
{ |
CYG_TEST_INFO("handler 0 called"); |
|
CYG_TEST_CHECK((CYG_ADDRWORD)123 == data, "handler given wrong data"); |
|
// ignore machine specific stuff |
CYG_UNUSED_PARAM(cyg_code, number); |
CYG_UNUSED_PARAM(CYG_ADDRWORD, info); |
|
CYG_TEST_PASS_FINISH("Except 1 OK"); |
} |
#endif |
|
static void handler1(CYG_ADDRWORD data, cyg_code number, CYG_ADDRWORD info) |
{ |
CYG_TEST_INFO("handler 1 called"); |
|
CYG_TEST_CHECK((CYG_ADDRWORD)&d0 == data, "handler given wrong data"); |
|
#ifdef CYGSEM_KERNEL_EXCEPTIONS_DECODE |
CYG_TEST_CHECK(number == CYGNUM_HAL_EXCEPTION_MAX, "handler given wrong number"); |
#else |
CYG_UNUSED_PARAM(cyg_code, number); |
#endif |
|
CYG_TEST_CHECK((CYG_ADDRWORD)99 == info, "handler given wrong info"); |
} |
|
#ifdef EXCEPTION_DATA_ACCESS |
// The following function attempts to cause an exception in various |
// hacky ways. It is machine dependent what exception is generated. |
// It does reads rather than writes hoping not to corrupt anything |
// important. |
static int |
cause_fpe(int num) |
{ |
double a; |
|
a = 1.0/num; // Depending on FPU emulation and/or |
// the FPU architecture, this may |
// cause an exception. |
// (float division by zero) |
|
return ((int)a)/num; // This may cause an exception if |
// the architecture supports it. |
// (integer division by zero). |
} // cause_fpe() |
|
void cause_exception(void) |
{ |
int x; |
unsigned int p=0; |
|
// First try for an address exception (unaligned access exception |
// or SEGV/BUS exceptions) |
do { |
x=*(volatile int *)(p-1); |
p+=0x100000; |
} while(p != 0); |
|
// Next try an integer or floating point divide-by-zero exception. |
cause_fpe(0); |
} |
#endif |
|
static void entry0( CYG_ADDRWORD data ) |
{ |
#ifdef EXCEPTION_DATA_ACCESS |
cyg_code n; |
#endif |
cyg_exception_handler *old_handler, *old_handler1; |
CYG_ADDRWORD old_data, old_data1; |
Cyg_Thread *p=Cyg_Thread::self(); |
|
CYG_UNUSED_PARAM(CYG_ADDRESS, data); |
|
p->register_exception( |
CYGNUM_HAL_EXCEPTION_MAX, |
&handler1, |
(CYG_ADDRWORD)&d0, |
&old_handler, |
&old_data); |
|
p->register_exception( |
CYGNUM_HAL_EXCEPTION_MAX, |
&handler1, |
(CYG_ADDRWORD)&d0, |
&old_handler1, |
&old_data1); |
|
CYG_TEST_CHECK(old_handler1 == &handler1, |
"register exception: old_handler not the one previously registered"); |
CYG_TEST_CHECK(old_data1 == (CYG_ADDRWORD)&d0, |
"register exception: old_data not those previously registered"); |
|
p->deliver_exception(CYGNUM_HAL_EXCEPTION_MAX, (CYG_ADDRWORD)99); |
|
CYG_TEST_INFO("handler 1 returned"); |
|
p->deregister_exception(CYGNUM_HAL_EXCEPTION_MAX); |
p->deregister_exception(CYGNUM_HAL_EXCEPTION_MAX); |
|
#ifdef EXCEPTION_DATA_ACCESS |
|
#if 0 |
#elif defined(CYGPKG_HAL_POWERPC_SIM) |
// The exception generated by the SIM is not recognized by GDB. |
// PR 19945 workaround. |
CYG_TEST_NA("Not applicable to PowerPC SIM"); |
#endif |
|
for(n = CYGNUM_HAL_EXCEPTION_MIN; n <= CYGNUM_HAL_EXCEPTION_MAX; n++) { |
p->register_exception( |
n, |
handler0, |
(CYG_ADDRWORD)123, |
&old_handler1, |
&old_data1); |
} |
|
CYG_TEST_PASS("Attempting to provoke exception"); |
|
cause_exception(); |
|
CYG_TEST_FAIL_FINISH("Couldn't cause exception"); |
#else // EXCEPTION_DATA_ACCESS |
CYG_TEST_NA("Platform does not support data exceptions"); |
#endif |
|
} |
|
#ifdef CYG_HAL_MIPS_TX39_JMR3904 |
|
externC cyg_VSR __default_exception_vsr; |
cyg_VSR *old_vsr; |
|
#endif |
|
void except0_main( void ) |
{ |
// Use CYG_TEST_GDBCMD _before_ CYG_TEST_INIT() |
CYG_TEST_GDBCMD("handle SIGBUS nostop"); |
CYG_TEST_GDBCMD("handle SIGSEGV nostop"); |
CYG_TEST_GDBCMD("handle SIGFPE nostop"); |
|
CYG_TEST_INIT(); |
|
#ifdef HAL_VSR_SET_TO_ECOS_HANDLER |
// Reclaim the VSR off CygMon possibly |
#ifdef CYGNUM_HAL_EXCEPTION_DATA_ACCESS |
HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_DATA_ACCESS, NULL ); |
#endif |
#ifdef CYGNUM_HAL_EXCEPTION_DATA_TLBMISS_ACCESS |
HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_DATA_TLBMISS_ACCESS, NULL ); |
#endif |
#ifdef CYGNUM_HAL_EXCEPTION_DATA_UNALIGNED_ACCESS |
HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_DATA_UNALIGNED_ACCESS, NULL ); |
#endif |
#ifdef CYGNUM_HAL_EXCEPTION_ILLEGAL_INSTRUCTION |
HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_ILLEGAL_INSTRUCTION, NULL ); |
#endif |
#ifdef CYGNUM_HAL_EXCEPTION_DIV_BY_ZERO |
HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_DIV_BY_ZERO, NULL ); |
#endif |
#ifdef CYGNUM_HAL_EXCEPTION_FPU |
HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_FPU, NULL ); |
#endif |
#ifdef CYGNUM_HAL_EXCEPTION_FPU_DIV_BY_ZERO |
HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_FPU_DIV_BY_ZERO, NULL ); |
#endif |
#endif |
|
new_thread(entry0, 0); |
|
Cyg_Scheduler::start(); |
|
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
except0_main(); |
} |
#else // def CYGPKG_KERNEL_EXCEPTIONS |
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA("Exceptions disabled"); |
} |
#endif // def CYGPKG_KERNEL_EXCEPTIONS |
|
// EOF except1.cxx |
/clock0.cxx
0,0 → 1,286
//========================================================================== |
// |
// clock0.cxx |
// |
// Clock test 0 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-02-13 |
// Description: Tests some basic clock functions. |
// Omissions: Doesn't test likely boundary conditions for |
// CYGNUM_KERNEL_COUNTERS_MULTI_LIST_SIZE |
// Real Time Clock Testing is limited |
// Options: |
// CYGIMP_KERNEL_COUNTERS_SINGLE_LIST |
// CYGIMP_KERNEL_COUNTERS_MULTI_LIST |
// CYGVAR_KERNEL_COUNTERS_CLOCK |
// CYGNUM_KERNEL_COUNTERS_MULTI_LIST_SIZE |
// Assumptions: This assumes we have long long support and |
// that counters are 64 bits. |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/clock.hxx> |
|
#include <cyg/infra/testcase.h> |
|
#include <cyg/kernel/clock.inl> |
|
#include "testaux.hxx" |
|
#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK |
|
cyg_alarm_fn call_me; |
|
bool flash( void ) |
{ |
Cyg_Counter counter0 = Cyg_Counter(); |
Cyg_Counter counter1 = Cyg_Counter(723); |
|
CYG_ASSERTCLASSO( counter0, "error" ); |
CYG_ASSERTCLASSO( counter1, "error" ); |
|
Cyg_Alarm alarm0 = Cyg_Alarm(&counter0, call_me, 12); |
|
CYG_ASSERTCLASSO( alarm0, "error" ); |
|
Cyg_Clock::cyg_resolution res = {1,2}; |
|
Cyg_Clock clock0(res); |
|
CYG_ASSERTCLASSO( clock0, "error" ); |
|
return true; |
} |
|
// Testing alarms |
// |
// call_me is a function that will be called when an alarm is |
// triggered. It updates a global variable called which is CHECKed |
// explicitly to see if the approriate alarms have been called. |
|
cyg_uint16 called = 0x0; |
|
void call_me(Cyg_Alarm *alarm, CYG_ADDRWORD data) |
{ |
called ^= data; |
} |
|
void call_me2(Cyg_Alarm *alarm, CYG_ADDRWORD data) |
{ |
call_me(alarm, data^0x10); |
} |
|
|
void clock0_main(void) |
{ |
CYG_TEST_INIT(); |
|
CHECK(flash()); |
CHECK(flash()); |
|
const cyg_uint32 big_number = 3333222111u; |
Cyg_Counter counter0 = Cyg_Counter(); |
|
CHECK( 0 == counter0.current_value() ); |
CHECK( 0 == counter0.current_value_lo() ); |
CHECK( 0 == counter0.current_value_hi() ); |
|
counter0.tick(); |
|
CHECK( 1 == counter0.current_value() ); |
CHECK( 1 == counter0.current_value_lo() ); |
CHECK( 0 == counter0.current_value_hi() ); |
|
counter0.tick(6); |
|
CHECK( 7 == counter0.current_value() ); |
CHECK( 7 == counter0.current_value_lo() ); |
CHECK( 0 == counter0.current_value_hi() ); |
|
counter0.set_value( 0xfffffffc ); |
|
CHECK( 0xfffffffc == counter0.current_value() ); |
CHECK( 0xfffffffc == counter0.current_value_lo() ); |
CHECK( 0 == counter0.current_value_hi() ); |
|
counter0.tick( 0x13 ); // Overflows 32 bits |
|
CHECK( 0x10000000fULL == counter0.current_value() ); |
CHECK( 0xf == counter0.current_value_lo() ); |
CHECK( 0x1 == counter0.current_value_hi() ); |
|
|
Cyg_Counter counter1 = Cyg_Counter(big_number); |
|
CHECK( 0 == counter1.current_value() ); |
CHECK( 0 == counter1.current_value_lo() ); |
CHECK( 0 == counter1.current_value_hi() ); |
|
counter1.tick(2); |
|
CHECK( 2ll*big_number == counter1.current_value() ); |
CHECK( ((2ll*big_number) & 0xffffffff) == |
counter1.current_value_lo() ); |
CHECK( ((2ll*big_number) >> 32) == counter1.current_value_hi() ); |
|
counter1.tick(); |
|
CHECK( 3ll*big_number == counter1.current_value() ); |
CHECK( ((3ll*big_number) & 0xffffffff) == |
counter1.current_value_lo() ); |
CHECK( ((3ll*big_number) >> 32) == counter1.current_value_hi() ); |
|
counter1.tick(); |
|
CHECK( 4ll*big_number == counter1.current_value() ); |
CHECK( ((4ll*big_number) & 0xffffffff) == |
counter1.current_value_lo() ); |
CHECK( ((4ll*big_number) >> 32) == counter1.current_value_hi() ); |
|
counter1.set_value(1222333444555ll); |
CHECK( 1222333444555ll == counter1.current_value() ); |
|
counter0.set_value(11); |
CHECK( 11 == counter0.current_value() ); |
|
// the call_me functions cause the "called" bits to toggle |
// CHECKing the value of called TEST_CHECKs the parity of # of calls |
// made by each alarm. |
|
Cyg_Alarm alarm0 = Cyg_Alarm(&counter0, call_me, 0x1); |
Cyg_Alarm alarm1 = Cyg_Alarm(&counter0, call_me, 0x2); |
Cyg_Alarm alarm2 = Cyg_Alarm(&counter0, call_me2, 0x4); |
|
CHECK( 0x00 == called ); |
alarm0.initialize(12,3); |
alarm2.initialize(21,2); |
CHECK( 0x00 == called ); |
|
counter0.tick(); // 12 a0 |
CHECK( 0x01 == called ); |
|
alarm1.initialize(13,0); |
counter0.tick(); // 13 a1 |
CHECK( 0x03 == called ); |
|
alarm1.initialize(17,0); |
counter0.tick(); // 14 |
CHECK( 0x03 == called ); |
|
counter0.tick(); // 15 a0 |
CHECK( 0x02 == called ); |
|
counter0.tick(2); // 17 a1 |
CHECK( 0x00 == called ); |
|
counter0.tick(); // 18 a0 |
CHECK( 0x01 == called ); |
|
counter0.tick(3); // 21 a0 a2 |
CHECK( 0x14 == called ); |
|
counter0.tick(2); // 23 a2 |
CHECK( 0x00 == called ); |
|
alarm2.disable(); |
|
counter0.tick(2); // 25 a0(24) |
CHECK( 0x01 == called ); |
|
alarm2.enable(); // a2 (enabled at 25) |
CHECK( 0x15 == called ); |
|
counter0.tick(); // 26 |
CHECK( 0x15 == called ); |
|
counter0.tick(2); // 28 a0(27) a2(27) |
CHECK( 0x00 == called ); |
|
counter0.tick(3); // 31 a0(30) a2(29 31) |
CHECK( 0x01 == called ); |
|
Cyg_Clock::cyg_resolution res0; |
|
res0.dividend = 100; |
res0.divisor = 3; |
|
Cyg_Clock::cyg_resolution res1; |
|
Cyg_Clock clock0 = Cyg_Clock(res0); |
|
res1 = clock0.get_resolution(); |
CHECK( res0.dividend == res1.dividend ); |
CHECK( res0.divisor == res1.divisor ); |
|
res1.dividend = 12; |
res1.divisor = 25; |
|
clock0.set_resolution(res1); |
res0 = clock0.get_resolution(); |
CHECK( res0.dividend == res1.dividend ); |
CHECK( res0.divisor == res1.divisor ); |
|
res0 = Cyg_Clock::real_time_clock->get_resolution(); |
|
CYG_TEST_PASS_FINISH("Clock 0 OK"); |
} |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
clock0_main(); |
} |
|
#else // def CYGVAR_KERNEL_COUNTERS_CLOCK |
|
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA( "Kernel real-time clock disabled"); |
} |
|
#endif // def CYGVAR_KERNEL_COUNTERS_CLOCK |
// EOF clock0.cxx |
/philo.cxx
0,0 → 1,241
//========================================================================== |
// |
// philo.cxx |
// |
// A test of the dining philosophers problem |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-02-24 |
// Description: A test of the dining philosophers problem |
//####DESCRIPTIONEND#### |
// |
|
#include <cyg/kernel/kernel.hxx> |
|
#include <cyg/hal/hal_io.h> |
|
// ------------------------------------------------------------------------- |
// Data for the philosophers problem |
|
#define PHILOSOPHERS 15 // number of philosophers |
#define STACKSIZE (2*1024) // size of thread stack |
|
#define NTHREADS PHILOSOPHERS |
#include "testaux.hxx" |
|
// array of chopsticks |
Cyg_Binary_Semaphore chopstick[PHILOSOPHERS]; |
|
|
//cyg_thread_entry Philosopher; |
|
// ------------------------------------------------------------------------- |
// State recording and display |
|
static char pstate[PHILOSOPHERS+1]; // state vector showing what each |
// philosopher is doing |
|
Cyg_Mutex state_mutex; |
|
#ifdef CYG_HAL_MN10300_MN103002 |
static cyg_count8 eaters = 0; |
#endif |
|
void change_state(int id, char newstate) |
{ |
CYG_INSTRUMENT_USER( 1, 0, 0); |
state_mutex.lock(); |
CYG_INSTRUMENT_USER( 2, 0, 0); |
|
#ifdef CYG_HAL_MN10300_MN103002 |
if( pstate[id] == 'E' ) eaters--; |
if( newstate == 'E' ) eaters++; |
// led(eaters); |
#endif |
|
pstate[id] = newstate; |
|
diag_write_string(pstate); |
#if 0 |
diag_write_char(' '); |
diag_write_dec(Cyg_Scheduler::get_thread_switches()); |
#endif |
diag_write_char('\n'); |
|
CYG_INSTRUMENT_USER( 3, 0, 0); |
state_mutex.unlock(); |
CYG_INSTRUMENT_USER( 4, 0, 0); |
|
} |
|
char get_state( int id) |
{ |
state_mutex.lock(); |
|
char s = pstate[id]; |
|
state_mutex.unlock(); |
|
return s; |
} |
|
// ------------------------------------------------------------------------- |
// Thread to behave like a philosopher |
|
void Philosopher( CYG_ADDRESS id ) |
{ |
Cyg_Thread *self = Cyg_Thread::self(); |
Cyg_Binary_Semaphore *first_stick = &chopstick[id]; |
Cyg_Binary_Semaphore *second_stick = &chopstick[(id+1)%PHILOSOPHERS]; |
#ifdef CYGPKG_INFRA_DEBUG |
int left_philo = ((id==0)?PHILOSOPHERS:id)-1; |
int right_philo = (id==PHILOSOPHERS-1)?0:(id+1); |
#endif |
|
CYG_ASSERT( id >= 0 && id < PHILOSOPHERS, "Bad id"); |
|
// Deadlock avoidance. The easiest way to make the philosophers |
// behave is to make each pick up the lowest numbered stick |
// first. This is how it works out anyway for all the philosophers |
// except the last, who must have his sticks swapped. |
|
if( id == PHILOSOPHERS-1 ) |
{ |
Cyg_Binary_Semaphore *t = first_stick; |
first_stick = second_stick; |
second_stick = t; |
} |
|
// The following variable is shared by all philosophers. |
// It is incremented unprotected, but this does not matter |
// since it is only present to introduce a little variability |
// into the think and eat times. |
|
static int cycle = 0; |
|
for(;;) |
{ |
// Think for a bit |
|
self->delay((id+cycle++)%12); // Cogito ergo sum... |
|
// I am now hungry, try to get the chopsticks |
|
change_state(id,'H'); |
|
// Get the first stick |
CYG_INSTRUMENT_USER( 5, 0, 0); |
first_stick->wait(); |
CYG_INSTRUMENT_USER( 6, 0, 0); |
|
// Get the second stick |
CYG_INSTRUMENT_USER( 7, 0, 0); |
second_stick->wait(); |
CYG_INSTRUMENT_USER( 8, 0, 0); |
|
// Got them, now eat |
|
change_state(id,'E'); |
|
// Check that the world is as I think it is... |
CYG_ASSERT( !first_stick->posted(), "Not got first stick"); |
CYG_ASSERT( !second_stick->posted(), "Not got second stick"); |
CYG_ASSERT( get_state(left_philo) != 'E', "Left neighbour also eating!!"); |
CYG_ASSERT( get_state(right_philo) != 'E', "Right neighbour also eating!!"); |
|
self->delay((id+cycle++)%6); // munch munch |
|
// Finished eating, put down sticks. |
|
change_state(id,'T'); |
|
CYG_INSTRUMENT_USER( 9, 0, 0); |
first_stick->post(); |
CYG_INSTRUMENT_USER( 10, 0, 0); |
second_stick->post(); |
CYG_INSTRUMENT_USER( 11, 0, 0); |
|
// Cyg_Scheduler::lock(); |
// Cyg_Scheduler::unlock(); |
CYG_INSTRUMENT_USER( 12, 0, 0); |
|
} |
} |
|
// ------------------------------------------------------------------------- |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
diag_init(); |
|
diag_write_string("Philosophers\n"); |
diag_write_string("Started\n"); |
|
// Zero last element in state so it acts like |
// a string. |
pstate[PHILOSOPHERS] = 0; |
|
#if 1 |
for( int i = 0; i < PHILOSOPHERS; i++ ) |
{ |
change_state(i,'T'); // starting state |
|
// Start the philosopher |
Cyg_Thread *t = new_thread( Philosopher, i ); |
|
// resume it |
t->resume(); |
|
// and make the matching chopstick present |
chopstick[i].post(); |
} |
#endif |
|
// Get the world going |
Cyg_Scheduler::scheduler.start(); |
|
} |
|
// ------------------------------------------------------------------------- |
// EOF philo.cxx |
/clock1.cxx
0,0 → 1,132
//========================================================================== |
// |
// clock1.cxx |
// |
// Clock test 1 - Real Time Clock |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-02-16 |
// Description: Tests the Kernel Real Time Clock |
// This test creates a thread, starts the scheduler and |
// delays for a time of about 5 seconds. This test should |
// be expected to run for about this length of time. |
// Omissions: |
// Doesn't test alarms attached to RTC. |
// Assumptions: |
// CYGVAR_KERNEL_COUNTERS_CLOCK must be set. |
// Resolution of clock small compared with 5s. |
// Overhead small compared with 5s. |
// Options: |
// CYGIMP_KERNEL_COUNTERS_SINGLE_LIST |
// CYGIMP_KERNEL_COUNTERS_MULTI_LIST |
// CYGVAR_KERNEL_COUNTERS_CLOCK |
// CYGNUM_KERNEL_COUNTERS_MULTI_LIST_SIZE |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/clock.hxx> |
#include <cyg/kernel/thread.hxx> |
|
#include <cyg/infra/testcase.h> |
|
#include <cyg/kernel/clock.inl> |
#include <cyg/kernel/thread.inl> |
|
#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK |
|
|
#define NTHREADS 1 |
#include "testaux.hxx" |
|
static cyg_uint32 ticks; // Number of ticks thread[0] will delay for |
|
static cyg_uint64 TEST_DELAY; |
|
static void entry0( CYG_ADDRWORD data ) |
{ |
((Cyg_Thread *)data)->delay(ticks); |
|
CYG_TEST_PASS_FINISH("Clock 1 OK"); |
} |
|
void clock1_main( void ) |
{ |
CYG_TEST_INIT(); |
|
if (cyg_test_is_simulator) { |
TEST_DELAY = 100000000ll; |
} else { |
TEST_DELAY = 3000000000ll; |
} |
|
new_thread(entry0, (CYG_ADDRWORD)&thread_obj[0]); |
|
Cyg_Clock::cyg_resolution res; |
|
res = Cyg_Clock::real_time_clock->get_resolution (); |
|
// RTC takes res.dividend/res.divisor ns/tick |
ticks = ((cyg_uint64)TEST_DELAY * res.divisor) / res.dividend; |
|
Cyg_Scheduler::start(); |
} |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
clock1_main(); |
} |
|
#else // def CYGVAR_KERNEL_COUNTERS_CLOCK |
|
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA( "Kernel real-time clock disabled"); |
} |
|
#endif // def CYGVAR_KERNEL_COUNTERS_CLOCK |
|
// EOF clock1.cxx |
/tm_basic.cxx
0,0 → 1,1868
//========================================================================== |
// |
// tm_basic.cxx |
// |
// Basic timing test / scaffolding |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. |
// Copyright (C) 2002 Gary Thomas |
// |
// 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): gthomas |
// Contributors: gthomas |
// Date: 1998-10-19 |
// Description: Very simple kernel timing test |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/kernel.h> |
#include <pkgconf/hal.h> |
|
#include <cyg/kernel/sched.hxx> |
#include <cyg/kernel/thread.hxx> |
#include <cyg/kernel/thread.inl> |
#include <cyg/kernel/mutex.hxx> |
#include <cyg/kernel/sema.hxx> |
#include <cyg/kernel/flag.hxx> |
#include <cyg/kernel/sched.inl> |
#include <cyg/kernel/clock.hxx> |
#include <cyg/kernel/clock.inl> |
#include <cyg/kernel/kapi.h> |
|
#include <cyg/infra/testcase.h> |
#include <cyg/infra/diag.h> |
|
#include <cyg/kernel/test/stackmon.h> |
#include CYGHWR_MEMORY_LAYOUT_H |
|
// Define this to see the statistics with the first sample datum removed. |
// This can expose the effects of caches on the speed of operations. |
#undef STATS_WITHOUT_FIRST_SAMPLE |
|
#if defined(CYGFUN_KERNEL_API_C) && \ |
defined(CYGSEM_KERNEL_SCHED_MLQUEUE) && \ |
defined(CYGVAR_KERNEL_COUNTERS_CLOCK) && \ |
!defined(CYGDBG_INFRA_DIAG_USE_DEVICE) && \ |
(CYGNUM_KERNEL_SCHED_PRIORITIES > 12) |
|
#define NTHREADS 1 |
#include "testaux.hxx" |
|
// Structure used to keep track of times |
typedef struct fun_times { |
cyg_uint32 start; |
cyg_uint32 end; |
} fun_times; |
|
#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_MINIMUM |
|
#ifdef CYGMEM_REGION_ram_SIZE |
#define CYG_THREAD_OVERHEAD (STACK_SIZE+sizeof(cyg_thread)+(sizeof(fun_times)*2)) |
#define NTEST_THREADS ((CYGMEM_REGION_ram_SIZE/16)/CYG_THREAD_OVERHEAD) |
#define CYG_MUTEX_OVERHEAD (sizeof(cyg_mutex_t)+sizeof(fun_times)) |
#define NMUTEXES ((CYGMEM_REGION_ram_SIZE/16)/CYG_MUTEX_OVERHEAD) |
#define CYG_MBOX_OVERHEAD (sizeof(cyg_mbox)+sizeof(fun_times)) |
#define NMBOXES ((CYGMEM_REGION_ram_SIZE/24)/CYG_MBOX_OVERHEAD) |
#define CYG_SEMAPHORE_OVERHEAD (sizeof(cyg_sem_t)+sizeof(fun_times)) |
#define NSEMAPHORES ((CYGMEM_REGION_ram_SIZE/16)/CYG_SEMAPHORE_OVERHEAD) |
#define CYG_COUNTER_OVERHEAD (sizeof(cyg_counter)+sizeof(fun_times)) |
#define NCOUNTERS ((CYGMEM_REGION_ram_SIZE/24)/CYG_COUNTER_OVERHEAD) |
#define CYG_FLAG_OVERHEAD (sizeof(cyg_flag_t)+sizeof(fun_times)) |
#define NFLAGS ((CYGMEM_REGION_ram_SIZE/24)/CYG_FLAG_OVERHEAD) |
#define CYG_ALARM_OVERHEAD (sizeof(cyg_alarm)+sizeof(fun_times)) |
#define NALARMS ((CYGMEM_REGION_ram_SIZE/16)/CYG_ALARM_OVERHEAD) |
#else |
// Defaults |
#define NTEST_THREADS 16 |
#define NMUTEXES 32 |
#define NMBOXES 32 |
#define NSEMAPHORES 32 |
#define NFLAGS 32 |
#define NCOUNTERS 32 |
#define NALARMS 32 |
#endif |
|
#define NSAMPLES 32 |
#define NTHREAD_SWITCHES 128 |
#define NSCHEDS 128 |
|
#define NSAMPLES_SIM 2 |
#define NTEST_THREADS_SIM 2 |
#define NTHREAD_SWITCHES_SIM 4 |
#define NMUTEXES_SIM 2 |
#define NMBOXES_SIM 2 |
#define NSEMAPHORES_SIM 2 |
#define NSCHEDS_SIM 4 |
#define NFLAGS_SIM 2 |
#define NCOUNTERS_SIM 2 |
#define NALARMS_SIM 2 |
|
static int nsamples; |
static int ntest_threads; |
static int nthread_switches; |
static int nmutexes; |
static int nmboxes; |
static int nsemaphores; |
static int nscheds; |
static int nflags; |
static int ncounters; |
static int nalarms; |
|
static char stacks[NTEST_THREADS][STACK_SIZE]; |
static cyg_thread test_threads[NTEST_THREADS]; |
static cyg_handle_t threads[NTEST_THREADS]; |
static int overhead; |
static cyg_sem_t synchro; |
static fun_times thread_ft[NTEST_THREADS]; |
|
static fun_times test2_ft[NTHREAD_SWITCHES]; |
|
static cyg_mutex_t test_mutexes[NMUTEXES]; |
static fun_times mutex_ft[NMUTEXES]; |
static cyg_thread mutex_test_thread; |
static cyg_handle_t mutex_test_thread_handle; |
|
static cyg_mbox test_mboxes[NMBOXES]; |
static cyg_handle_t test_mbox_handles[NMBOXES]; |
static fun_times mbox_ft[NMBOXES]; |
#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT |
static cyg_thread mbox_test_thread; |
static cyg_handle_t mbox_test_thread_handle; |
#endif |
|
static cyg_sem_t test_semaphores[NSEMAPHORES]; |
static fun_times semaphore_ft[NSEMAPHORES]; |
static cyg_thread semaphore_test_thread; |
static cyg_handle_t semaphore_test_thread_handle; |
|
static fun_times sched_ft[NSCHEDS]; |
|
static cyg_counter test_counters[NCOUNTERS]; |
static cyg_handle_t counters[NCOUNTERS]; |
static fun_times counter_ft[NCOUNTERS]; |
|
static cyg_flag_t test_flags[NFLAGS]; |
static fun_times flag_ft[NFLAGS]; |
|
static cyg_alarm test_alarms[NALARMS]; |
static cyg_handle_t alarms[NALARMS]; |
static fun_times alarm_ft[NALARMS]; |
|
static long rtc_resolution[] = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION; |
static long ns_per_system_clock; |
|
#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY) |
// Data kept by kernel real time clock measuring clock interrupt latency |
extern cyg_tick_count total_clock_latency, total_clock_interrupts; |
extern cyg_int32 min_clock_latency, max_clock_latency; |
extern bool measure_clock_latency; |
#endif |
|
#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY) && defined(HAL_CLOCK_LATENCY) |
extern cyg_tick_count total_clock_dsr_latency, total_clock_dsr_calls; |
extern cyg_int32 min_clock_dsr_latency, max_clock_dsr_latency; |
extern bool measure_clock_latency; |
#endif |
|
void run_sched_tests(void); |
void run_thread_tests(void); |
void run_thread_switch_test(void); |
void run_mutex_tests(void); |
void run_mutex_circuit_test(void); |
void run_mbox_tests(void); |
void run_mbox_circuit_test(void); |
void run_semaphore_tests(void); |
void run_semaphore_circuit_test(void); |
void run_counter_tests(void); |
void run_flag_tests(void); |
void run_alarm_tests(void); |
|
#ifndef max |
#define max(n,m) (m > n ? n : m) |
#endif |
|
// Wait until a clock tick [real time clock] has passed. This should keep it |
// from happening again during a measurement, thus minimizing any fluctuations |
void |
wait_for_tick(void) |
{ |
cyg_tick_count_t tv0, tv1; |
tv0 = cyg_current_time(); |
while (true) { |
tv1 = cyg_current_time(); |
if (tv1 != tv0) break; |
} |
} |
|
// Display a number of ticks as microseconds |
// Note: for improved calculation significance, values are kept in ticks*1000 |
void |
show_ticks_in_us(cyg_uint32 ticks) |
{ |
long long ns; |
ns = (ns_per_system_clock * (long long)ticks) / CYGNUM_KERNEL_COUNTERS_RTC_PERIOD; |
ns += 5; // for rounding to .01us |
diag_printf("%5d.%02d", (int)(ns/1000), (int)((ns%1000)/10)); |
} |
|
// |
// If the kernel is instrumented to measure clock interrupt latency, these |
// measurements can be drastically perturbed by printing via "diag_printf()" |
// since that code may run with interrupts disabled for long periods. |
// |
// In order to get accurate/reasonable latency figures _for the kernel |
// primitive functions beint tested_, the kernel's latency measurements |
// are suspended while the printing actually takes place. |
// |
// The measurements are reenabled after the printing, thus allowing for |
// fair measurements of the kernel primitives, which are not distorted |
// by the printing mechanisms. |
|
#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY) |
void |
disable_clock_latency_measurement(void) |
{ |
wait_for_tick(); |
measure_clock_latency = false; |
} |
|
void |
enable_clock_latency_measurement(void) |
{ |
wait_for_tick(); |
measure_clock_latency = true; |
} |
|
// Ensure that the measurements are reasonable (no startup anomalies) |
void |
reset_clock_latency_measurement(void) |
{ |
disable_clock_latency_measurement(); |
total_clock_latency = 0; |
total_clock_interrupts = 0; |
min_clock_latency = 0x7FFFFFFF; |
max_clock_latency = 0; |
#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY) && defined(HAL_CLOCK_LATENCY) |
total_clock_dsr_latency = 0; |
total_clock_dsr_calls = 0; |
min_clock_dsr_latency = 0x7FFFFFFF; |
max_clock_dsr_latency = 0; |
#endif |
enable_clock_latency_measurement(); |
|
} |
#else |
#define disable_clock_latency_measurement() |
#define enable_clock_latency_measurement() |
#define reset_clock_latency_measurement() |
#endif |
|
void |
show_times_hdr(void) |
{ |
disable_clock_latency_measurement(); |
diag_printf("\n"); |
diag_printf(" Confidence\n"); |
diag_printf(" Ave Min Max Var Ave Min Function\n"); |
diag_printf(" ====== ====== ====== ====== ========== ========\n"); |
enable_clock_latency_measurement(); |
} |
|
void |
show_times_detail(fun_times ft[], int nsamples, char *title, bool ignore_first) |
{ |
int i, delta, min, max, con_ave, con_min, ave_dev; |
int start_sample, total_samples; |
cyg_int32 total, ave; |
|
if (ignore_first) { |
start_sample = 1; |
total_samples = nsamples-1; |
} else { |
start_sample = 0; |
total_samples = nsamples; |
} |
total = 0; |
min = 0x7FFFFFFF; |
max = 0; |
for (i = start_sample; i < nsamples; i++) { |
if (ft[i].end < ft[i].start) { |
// Clock wrapped around (timer tick) |
delta = (ft[i].end+CYGNUM_KERNEL_COUNTERS_RTC_PERIOD) - ft[i].start; |
} else { |
delta = ft[i].end - ft[i].start; |
} |
delta -= overhead; |
if (delta < 0) delta = 0; |
delta *= 1000; |
total += delta; |
if (delta < min) min = delta; |
if (delta > max) max = delta; |
} |
ave = total / total_samples; |
total = 0; |
ave_dev = 0; |
for (i = start_sample; i < nsamples; i++) { |
if (ft[i].end < ft[i].start) { |
// Clock wrapped around (timer tick) |
delta = (ft[i].end+CYGNUM_KERNEL_COUNTERS_RTC_PERIOD) - ft[i].start; |
} else { |
delta = ft[i].end - ft[i].start; |
} |
delta -= overhead; |
if (delta < 0) delta = 0; |
delta *= 1000; |
delta = delta - ave; |
if (delta < 0) delta = -delta; |
ave_dev += delta; |
} |
ave_dev /= total_samples; |
con_ave = 0; |
con_min = 0; |
for (i = start_sample; i < nsamples; i++) { |
if (ft[i].end < ft[i].start) { |
// Clock wrapped around (timer tick) |
delta = (ft[i].end+CYGNUM_KERNEL_COUNTERS_RTC_PERIOD) - ft[i].start; |
} else { |
delta = ft[i].end - ft[i].start; |
} |
delta -= overhead; |
if (delta < 0) delta = 0; |
delta *= 1000; |
if ((delta <= (ave+ave_dev)) && (delta >= (ave-ave_dev))) con_ave++; |
if ((delta <= (min+ave_dev)) && (delta >= (min-ave_dev))) con_min++; |
} |
con_ave = (con_ave * 100) / total_samples; |
con_min = (con_min * 100) / total_samples; |
show_ticks_in_us(ave); |
show_ticks_in_us(min); |
show_ticks_in_us(max); |
show_ticks_in_us(ave_dev); |
disable_clock_latency_measurement(); |
diag_printf(" %3d%% %3d%%", con_ave, con_min); |
diag_printf(" %s\n", title); |
enable_clock_latency_measurement(); |
} |
|
void |
show_times(fun_times ft[], int nsamples, char *title) |
{ |
show_times_detail(ft, nsamples, title, false); |
#ifdef STATS_WITHOUT_FIRST_SAMPLE |
show_times_detail(ft, nsamples, "", true); |
#endif |
} |
|
void |
show_test_parameters(void) |
{ |
disable_clock_latency_measurement(); |
diag_printf("\nTesting parameters:\n"); |
diag_printf(" Clock samples: %5d\n", nsamples); |
diag_printf(" Threads: %5d\n", ntest_threads); |
diag_printf(" Thread switches: %5d\n", nthread_switches); |
diag_printf(" Mutexes: %5d\n", nmutexes); |
diag_printf(" Mailboxes: %5d\n", nmboxes); |
diag_printf(" Semaphores: %5d\n", nsemaphores); |
diag_printf(" Scheduler operations: %5d\n", nscheds); |
diag_printf(" Counters: %5d\n", ncounters); |
diag_printf(" Flags: %5d\n", nflags); |
diag_printf(" Alarms: %5d\n", nalarms); |
diag_printf("\n"); |
enable_clock_latency_measurement(); |
} |
|
void |
end_of_test_group(void) |
{ |
disable_clock_latency_measurement(); |
diag_printf("\n"); |
enable_clock_latency_measurement(); |
} |
|
// Compute a name for a thread |
char * |
thread_name(char *basename, int indx) { |
return "<<NULL>>"; // Not currently used |
} |
|
// test0 - null test, never executed |
void |
test0(cyg_uint32 indx) |
{ |
#ifndef CYGPKG_KERNEL_SMP_SUPPORT |
// In SMP, somw of these threads will execute |
diag_printf("test0.%d executed?\n", indx); |
#endif |
cyg_thread_exit(); |
} |
|
// test1 - empty test, simply exit. Last thread signals parent. |
void |
test1(cyg_uint32 indx) |
{ |
if (indx == (cyg_uint32)(ntest_threads-1)) { |
cyg_semaphore_post(&synchro); // Signal that last thread is dying |
} |
cyg_thread_exit(); |
} |
|
// test2 - measure thread switch times |
void |
test2(cyg_uint32 indx) |
{ |
int i; |
for (i = 0; i < nthread_switches; i++) { |
if (indx == 0) { |
HAL_CLOCK_READ(&test2_ft[i].start); |
} else { |
HAL_CLOCK_READ(&test2_ft[i].end); |
} |
cyg_thread_yield(); |
} |
if (indx == 1) { |
cyg_semaphore_post(&synchro); |
} |
cyg_thread_exit(); |
} |
|
// Full-circuit mutex unlock/lock test |
void |
mutex_test(cyg_uint32 indx) |
{ |
int i; |
cyg_mutex_lock(&test_mutexes[0]); |
for (i = 0; i < nmutexes; i++) { |
cyg_semaphore_wait(&synchro); |
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
HAL_CLOCK_READ(&mutex_ft[i].start); |
cyg_mutex_unlock(&test_mutexes[0]); |
cyg_mutex_lock(&test_mutexes[0]); |
cyg_semaphore_post(&synchro); |
} |
cyg_thread_exit(); |
} |
|
// Full-circuit mbox put/get test |
void |
mbox_test(cyg_uint32 indx) |
{ |
void *item; |
do { |
item = cyg_mbox_get(test_mbox_handles[0]); |
HAL_CLOCK_READ(&mbox_ft[(int)item].end); |
cyg_semaphore_post(&synchro); |
} while ((int)item != (nmboxes-1)); |
cyg_thread_exit(); |
} |
|
// Full-circuit semaphore post/wait test |
void |
semaphore_test(cyg_uint32 indx) |
{ |
int i; |
for (i = 0; i < nsemaphores; i++) { |
cyg_semaphore_wait(&test_semaphores[0]); |
HAL_CLOCK_READ(&semaphore_ft[i].end); |
cyg_semaphore_post(&synchro); |
} |
cyg_thread_exit(); |
} |
|
// |
// This set of tests is used to measure kernel primitives that deal with threads |
// |
void |
run_thread_tests(void) |
{ |
int i; |
cyg_priority_t prio; |
|
// Set my priority higher than any I plan to create |
cyg_thread_set_priority(cyg_thread_self(), 2); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < ntest_threads; i++) { |
HAL_CLOCK_READ(&thread_ft[i].start); |
cyg_thread_create(10, // Priority - just a number |
test0, // entry |
i, // index |
thread_name("thread", i), // Name |
&stacks[i][0], // Stack |
STACK_SIZE, // Size |
&threads[i], // Handle |
&test_threads[i] // Thread data structure |
); |
HAL_CLOCK_READ(&thread_ft[i].end); |
} |
show_times(thread_ft, ntest_threads, "Create thread"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < ntest_threads; i++) { |
HAL_CLOCK_READ(&thread_ft[i].start); |
cyg_thread_yield(); |
HAL_CLOCK_READ(&thread_ft[i].end); |
} |
show_times(thread_ft, ntest_threads, "Yield thread [all suspended]"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < ntest_threads; i++) { |
HAL_CLOCK_READ(&thread_ft[i].start); |
cyg_thread_suspend(threads[i]); |
HAL_CLOCK_READ(&thread_ft[i].end); |
} |
show_times(thread_ft, ntest_threads, "Suspend [suspended] thread"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < ntest_threads; i++) { |
HAL_CLOCK_READ(&thread_ft[i].start); |
cyg_thread_resume(threads[i]); |
HAL_CLOCK_READ(&thread_ft[i].end); |
} |
show_times(thread_ft, ntest_threads, "Resume thread"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < ntest_threads; i++) { |
HAL_CLOCK_READ(&thread_ft[i].start); |
cyg_thread_set_priority(threads[i], 11); |
HAL_CLOCK_READ(&thread_ft[i].end); |
} |
show_times(thread_ft, ntest_threads, "Set priority"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < ntest_threads; i++) { |
HAL_CLOCK_READ(&thread_ft[i].start); |
prio = cyg_thread_get_priority(threads[i]); |
HAL_CLOCK_READ(&thread_ft[i].end); |
} |
show_times(thread_ft, ntest_threads, "Get priority"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < ntest_threads; i++) { |
HAL_CLOCK_READ(&thread_ft[i].start); |
cyg_thread_kill(threads[i]); |
HAL_CLOCK_READ(&thread_ft[i].end); |
} |
show_times(thread_ft, ntest_threads, "Kill [suspended] thread"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < ntest_threads; i++) { |
HAL_CLOCK_READ(&thread_ft[i].start); |
cyg_thread_yield(); |
HAL_CLOCK_READ(&thread_ft[i].end); |
} |
show_times(thread_ft, ntest_threads, "Yield [no other] thread"); |
|
// Set my priority higher than any I plan to create |
cyg_thread_set_priority(cyg_thread_self(), 2); |
|
// Recreate the test set |
for (i = 0; i < ntest_threads; i++) { |
cyg_thread_create(10, // Priority - just a number |
test0, // entry |
i, // index |
thread_name("thread", i), // Name |
&stacks[i][0], // Stack |
STACK_SIZE, // Size |
&threads[i], // Handle |
&test_threads[i] // Thread data structure |
); |
} |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < ntest_threads; i++) { |
HAL_CLOCK_READ(&thread_ft[i].start); |
cyg_thread_resume(threads[i]); |
HAL_CLOCK_READ(&thread_ft[i].end); |
} |
show_times(thread_ft, ntest_threads, "Resume [suspended low prio] thread"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < ntest_threads; i++) { |
HAL_CLOCK_READ(&thread_ft[i].start); |
cyg_thread_resume(threads[i]); |
HAL_CLOCK_READ(&thread_ft[i].end); |
} |
show_times(thread_ft, ntest_threads, "Resume [runnable low prio] thread"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < ntest_threads; i++) { |
HAL_CLOCK_READ(&thread_ft[i].start); |
cyg_thread_suspend(threads[i]); |
HAL_CLOCK_READ(&thread_ft[i].end); |
} |
show_times(thread_ft, ntest_threads, "Suspend [runnable] thread"); |
|
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < ntest_threads; i++) { |
HAL_CLOCK_READ(&thread_ft[i].start); |
cyg_thread_yield(); |
HAL_CLOCK_READ(&thread_ft[i].end); |
} |
show_times(thread_ft, ntest_threads, "Yield [only low prio] thread"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < ntest_threads; i++) { |
HAL_CLOCK_READ(&thread_ft[i].start); |
cyg_thread_suspend(threads[i]); |
HAL_CLOCK_READ(&thread_ft[i].end); |
} |
show_times(thread_ft, ntest_threads, "Suspend [runnable->not runnable]"); |
for (i = 0; i < ntest_threads; i++) { |
cyg_thread_resume(threads[i]); |
} |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < ntest_threads; i++) { |
HAL_CLOCK_READ(&thread_ft[i].start); |
cyg_thread_kill(threads[i]); |
HAL_CLOCK_READ(&thread_ft[i].end); |
} |
show_times(thread_ft, ntest_threads, "Kill [runnable] thread"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < ntest_threads; i++) { |
HAL_CLOCK_READ(&thread_ft[i].start); |
cyg_thread_delete(threads[i]); |
HAL_CLOCK_READ(&thread_ft[i].end); |
} |
show_times(thread_ft, ntest_threads, "Destroy [dead] thread"); |
|
// Recreate the test set |
for (i = 0; i < ntest_threads; i++) { |
cyg_thread_create(10, // Priority - just a number |
test0, // entry |
i, // index |
thread_name("thread", i), // Name |
&stacks[i][0], // Stack |
STACK_SIZE, // Size |
&threads[i], // Handle |
&test_threads[i] // Thread data structure |
); |
cyg_thread_resume(threads[i]); |
} |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < ntest_threads; i++) { |
HAL_CLOCK_READ(&thread_ft[i].start); |
cyg_thread_delete(threads[i]); |
HAL_CLOCK_READ(&thread_ft[i].end); |
} |
show_times(thread_ft, ntest_threads, "Destroy [runnable] thread"); |
|
// Set my priority lower than any I plan to create |
cyg_thread_set_priority(cyg_thread_self(), 3); |
|
// Set up the end-of-threads synchronizer |
cyg_semaphore_init(&synchro, 0); |
|
// Recreate the test set |
for (i = 0; i < ntest_threads; i++) { |
cyg_thread_create(2, // Priority - just a number |
test1, // entry |
i, // index |
thread_name("thread", i), // Name |
&stacks[i][0], // Stack |
STACK_SIZE, // Size |
&threads[i], // Handle |
&test_threads[i] // Thread data structure |
); |
} |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < ntest_threads; i++) { |
HAL_CLOCK_READ(&thread_ft[i].start); |
cyg_thread_resume(threads[i]); |
HAL_CLOCK_READ(&thread_ft[i].end); |
} |
show_times(thread_ft, ntest_threads, "Resume [high priority] thread"); |
cyg_semaphore_wait(&synchro); // Wait for all threads to finish |
// Make sure they are all dead |
for (i = 0; i < ntest_threads; i++) { |
cyg_thread_delete(threads[i]); |
} |
|
run_thread_switch_test(); |
end_of_test_group(); |
} |
|
void |
run_thread_switch_test(void) |
{ |
int i; |
|
// Set up for thread context switch |
for (i = 0; i < 2; i++) { |
cyg_thread_create(10, // Priority - just a number |
test2, // entry |
i, // index |
thread_name("thread", i), // Name |
&stacks[i][0], // Stack |
STACK_SIZE, // Size |
&threads[i], // Handle |
&test_threads[i] // Thread data structure |
); |
cyg_thread_resume(threads[i]); |
} |
// Set up the end-of-threads synchronizer |
cyg_semaphore_init(&synchro, 0); |
cyg_semaphore_wait(&synchro); |
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
show_times(test2_ft, nthread_switches, "Thread switch"); |
// Clean up |
for (i = 0; i < 2; i++) { |
cyg_thread_delete(threads[i]); |
} |
} |
|
void |
run_mutex_tests(void) |
{ |
int i; |
|
// Mutex primitives |
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nmutexes; i++) { |
HAL_CLOCK_READ(&mutex_ft[i].start); |
cyg_mutex_init(&test_mutexes[i]); |
HAL_CLOCK_READ(&mutex_ft[i].end); |
} |
show_times(mutex_ft, nmutexes, "Init mutex"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nmutexes; i++) { |
HAL_CLOCK_READ(&mutex_ft[i].start); |
cyg_mutex_lock(&test_mutexes[i]); |
HAL_CLOCK_READ(&mutex_ft[i].end); |
} |
show_times(mutex_ft, nmutexes, "Lock [unlocked] mutex"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nmutexes; i++) { |
HAL_CLOCK_READ(&mutex_ft[i].start); |
cyg_mutex_unlock(&test_mutexes[i]); |
HAL_CLOCK_READ(&mutex_ft[i].end); |
} |
show_times(mutex_ft, nmutexes, "Unlock [locked] mutex"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nmutexes; i++) { |
HAL_CLOCK_READ(&mutex_ft[i].start); |
cyg_mutex_trylock(&test_mutexes[i]); |
HAL_CLOCK_READ(&mutex_ft[i].end); |
} |
show_times(mutex_ft, nmutexes, "Trylock [unlocked] mutex"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nmutexes; i++) { |
HAL_CLOCK_READ(&mutex_ft[i].start); |
cyg_mutex_trylock(&test_mutexes[i]); |
HAL_CLOCK_READ(&mutex_ft[i].end); |
} |
show_times(mutex_ft, nmutexes, "Trylock [locked] mutex"); |
|
// Must unlock mutices before destroying them. |
for (i = 0; i < nmutexes; i++) { |
cyg_mutex_unlock(&test_mutexes[i]); |
} |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nmutexes; i++) { |
HAL_CLOCK_READ(&mutex_ft[i].start); |
cyg_mutex_destroy(&test_mutexes[i]); |
HAL_CLOCK_READ(&mutex_ft[i].end); |
} |
show_times(mutex_ft, nmutexes, "Destroy mutex"); |
run_mutex_circuit_test(); |
end_of_test_group(); |
} |
|
void |
run_mutex_circuit_test(void) |
{ |
int i; |
// Set my priority lower than any I plan to create |
cyg_thread_set_priority(cyg_thread_self(), 4); |
// Set up for full mutex unlock/lock test |
cyg_mutex_init(&test_mutexes[0]); |
cyg_semaphore_init(&synchro, 0); |
cyg_thread_create(3, // Priority - just a number |
mutex_test, // entry |
0, // index |
thread_name("thread", 0), // Name |
&stacks[0][0], // Stack |
STACK_SIZE, // Size |
&mutex_test_thread_handle, // Handle |
&mutex_test_thread // Thread data structure |
); |
cyg_thread_resume(mutex_test_thread_handle); |
// Need to raise priority so that this thread will block on the "lock" |
cyg_thread_set_priority(cyg_thread_self(), 2); |
for (i = 0; i < nmutexes; i++) { |
cyg_semaphore_post(&synchro); |
cyg_mutex_lock(&test_mutexes[0]); |
HAL_CLOCK_READ(&mutex_ft[i].end); |
cyg_mutex_unlock(&test_mutexes[0]); |
cyg_semaphore_wait(&synchro); |
} |
cyg_thread_delete(mutex_test_thread_handle); |
show_times(mutex_ft, nmutexes, "Unlock/Lock mutex"); |
} |
|
void |
run_mbox_tests(void) |
{ |
int i, cnt; |
void *item; |
// Mailbox primitives |
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nmboxes; i++) { |
HAL_CLOCK_READ(&mbox_ft[i].start); |
cyg_mbox_create(&test_mbox_handles[i], &test_mboxes[i]); |
HAL_CLOCK_READ(&mbox_ft[i].end); |
} |
show_times(mbox_ft, nmboxes, "Create mbox"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nmboxes; i++) { |
HAL_CLOCK_READ(&mbox_ft[i].start); |
cnt = cyg_mbox_peek(test_mbox_handles[i]); |
HAL_CLOCK_READ(&mbox_ft[i].end); |
} |
show_times(mbox_ft, nmboxes, "Peek [empty] mbox"); |
|
#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT |
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nmboxes; i++) { |
HAL_CLOCK_READ(&mbox_ft[i].start); |
cyg_mbox_put(test_mbox_handles[i], (void *)i); |
HAL_CLOCK_READ(&mbox_ft[i].end); |
} |
show_times(mbox_ft, nmboxes, "Put [first] mbox"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nmboxes; i++) { |
HAL_CLOCK_READ(&mbox_ft[i].start); |
cnt = cyg_mbox_peek(test_mbox_handles[i]); |
HAL_CLOCK_READ(&mbox_ft[i].end); |
} |
show_times(mbox_ft, nmboxes, "Peek [1 msg] mbox"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nmboxes; i++) { |
HAL_CLOCK_READ(&mbox_ft[i].start); |
cyg_mbox_put(test_mbox_handles[i], (void *)i); |
HAL_CLOCK_READ(&mbox_ft[i].end); |
} |
show_times(mbox_ft, nmboxes, "Put [second] mbox"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nmboxes; i++) { |
HAL_CLOCK_READ(&mbox_ft[i].start); |
cnt = cyg_mbox_peek(test_mbox_handles[i]); |
HAL_CLOCK_READ(&mbox_ft[i].end); |
} |
show_times(mbox_ft, nmboxes, "Peek [2 msgs] mbox"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nmboxes; i++) { |
HAL_CLOCK_READ(&mbox_ft[i].start); |
item = cyg_mbox_get(test_mbox_handles[i]); |
HAL_CLOCK_READ(&mbox_ft[i].end); |
} |
show_times(mbox_ft, nmboxes, "Get [first] mbox"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nmboxes; i++) { |
HAL_CLOCK_READ(&mbox_ft[i].start); |
item = cyg_mbox_get(test_mbox_handles[i]); |
HAL_CLOCK_READ(&mbox_ft[i].end); |
} |
show_times(mbox_ft, nmboxes, "Get [second] mbox"); |
#endif // ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nmboxes; i++) { |
HAL_CLOCK_READ(&mbox_ft[i].start); |
cyg_mbox_tryput(test_mbox_handles[i], (void *)i); |
HAL_CLOCK_READ(&mbox_ft[i].end); |
} |
show_times(mbox_ft, nmboxes, "Tryput [first] mbox"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nmboxes; i++) { |
HAL_CLOCK_READ(&mbox_ft[i].start); |
item = cyg_mbox_peek_item(test_mbox_handles[i]); |
HAL_CLOCK_READ(&mbox_ft[i].end); |
} |
show_times(mbox_ft, nmboxes, "Peek item [non-empty] mbox"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nmboxes; i++) { |
HAL_CLOCK_READ(&mbox_ft[i].start); |
item = cyg_mbox_tryget(test_mbox_handles[i]); |
HAL_CLOCK_READ(&mbox_ft[i].end); |
} |
show_times(mbox_ft, nmboxes, "Tryget [non-empty] mbox"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nmboxes; i++) { |
HAL_CLOCK_READ(&mbox_ft[i].start); |
item = cyg_mbox_peek_item(test_mbox_handles[i]); |
HAL_CLOCK_READ(&mbox_ft[i].end); |
} |
show_times(mbox_ft, nmboxes, "Peek item [empty] mbox"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nmboxes; i++) { |
HAL_CLOCK_READ(&mbox_ft[i].start); |
item = cyg_mbox_tryget(test_mbox_handles[i]); |
HAL_CLOCK_READ(&mbox_ft[i].end); |
} |
show_times(mbox_ft, nmboxes, "Tryget [empty] mbox"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nmboxes; i++) { |
HAL_CLOCK_READ(&mbox_ft[i].start); |
cyg_mbox_waiting_to_get(test_mbox_handles[i]); |
HAL_CLOCK_READ(&mbox_ft[i].end); |
} |
show_times(mbox_ft, nmboxes, "Waiting to get mbox"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nmboxes; i++) { |
HAL_CLOCK_READ(&mbox_ft[i].start); |
cyg_mbox_waiting_to_put(test_mbox_handles[i]); |
HAL_CLOCK_READ(&mbox_ft[i].end); |
} |
show_times(mbox_ft, nmboxes, "Waiting to put mbox"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nmboxes; i++) { |
HAL_CLOCK_READ(&mbox_ft[i].start); |
cyg_mbox_delete(test_mbox_handles[i]); |
HAL_CLOCK_READ(&mbox_ft[i].end); |
} |
show_times(mbox_ft, nmboxes, "Delete mbox"); |
|
run_mbox_circuit_test(); |
end_of_test_group(); |
} |
|
void |
run_mbox_circuit_test(void) |
{ |
#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT |
int i; |
// Set my priority lower than any I plan to create |
cyg_thread_set_priority(cyg_thread_self(), 3); |
// Set up for full mbox put/get test |
cyg_mbox_create(&test_mbox_handles[0], &test_mboxes[0]); |
cyg_semaphore_init(&synchro, 0); |
cyg_thread_create(2, // Priority - just a number |
mbox_test, // entry |
0, // index |
thread_name("thread", 0), // Name |
&stacks[0][0], // Stack |
STACK_SIZE, // Size |
&mbox_test_thread_handle, // Handle |
&mbox_test_thread // Thread data structure |
); |
cyg_thread_resume(mbox_test_thread_handle); |
for (i = 0; i < nmboxes; i++) { |
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
HAL_CLOCK_READ(&mbox_ft[i].start); |
cyg_mbox_put(test_mbox_handles[0], (void *)i); |
cyg_semaphore_wait(&synchro); |
} |
cyg_thread_delete(mbox_test_thread_handle); |
show_times(mbox_ft, nmboxes, "Put/Get mbox"); |
#endif |
} |
|
void |
run_semaphore_tests(void) |
{ |
int i; |
cyg_count32 sem_val; |
// Semaphore primitives |
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nsemaphores; i++) { |
HAL_CLOCK_READ(&semaphore_ft[i].start); |
cyg_semaphore_init(&test_semaphores[i], 0); |
HAL_CLOCK_READ(&semaphore_ft[i].end); |
} |
show_times(semaphore_ft, nsemaphores, "Init semaphore"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nsemaphores; i++) { |
HAL_CLOCK_READ(&semaphore_ft[i].start); |
cyg_semaphore_post(&test_semaphores[i]); |
HAL_CLOCK_READ(&semaphore_ft[i].end); |
} |
show_times(semaphore_ft, nsemaphores, "Post [0] semaphore"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nsemaphores; i++) { |
HAL_CLOCK_READ(&semaphore_ft[i].start); |
cyg_semaphore_wait(&test_semaphores[i]); |
HAL_CLOCK_READ(&semaphore_ft[i].end); |
} |
show_times(semaphore_ft, nsemaphores, "Wait [1] semaphore"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nsemaphores; i++) { |
HAL_CLOCK_READ(&semaphore_ft[i].start); |
cyg_semaphore_trywait(&test_semaphores[i]); |
HAL_CLOCK_READ(&semaphore_ft[i].end); |
} |
show_times(semaphore_ft, nsemaphores, "Trywait [0] semaphore"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nsemaphores; i++) { |
cyg_semaphore_post(&test_semaphores[i]); |
HAL_CLOCK_READ(&semaphore_ft[i].start); |
cyg_semaphore_trywait(&test_semaphores[i]); |
HAL_CLOCK_READ(&semaphore_ft[i].end); |
} |
show_times(semaphore_ft, nsemaphores, "Trywait [1] semaphore"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nsemaphores; i++) { |
HAL_CLOCK_READ(&semaphore_ft[i].start); |
cyg_semaphore_peek(&test_semaphores[i], &sem_val); |
HAL_CLOCK_READ(&semaphore_ft[i].end); |
} |
show_times(semaphore_ft, nsemaphores, "Peek semaphore"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nsemaphores; i++) { |
HAL_CLOCK_READ(&semaphore_ft[i].start); |
cyg_semaphore_destroy(&test_semaphores[i]); |
HAL_CLOCK_READ(&semaphore_ft[i].end); |
} |
show_times(semaphore_ft, nsemaphores, "Destroy semaphore"); |
|
run_semaphore_circuit_test(); |
end_of_test_group(); |
} |
|
void |
run_semaphore_circuit_test(void) |
{ |
int i; |
// Set my priority lower than any I plan to create |
cyg_thread_set_priority(cyg_thread_self(), 3); |
// Set up for full semaphore post/wait test |
cyg_semaphore_init(&test_semaphores[0], 0); |
cyg_semaphore_init(&synchro, 0); |
cyg_thread_create(2, // Priority - just a number |
semaphore_test, // entry |
0, // index |
thread_name("thread", 0), // Name |
&stacks[0][0], // Stack |
STACK_SIZE, // Size |
&semaphore_test_thread_handle, // Handle |
&semaphore_test_thread // Thread data structure |
); |
cyg_thread_resume(semaphore_test_thread_handle); |
for (i = 0; i < nsemaphores; i++) { |
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
HAL_CLOCK_READ(&semaphore_ft[i].start); |
cyg_semaphore_post(&test_semaphores[0]); |
cyg_semaphore_wait(&synchro); |
} |
cyg_thread_delete(semaphore_test_thread_handle); |
show_times(semaphore_ft, nsemaphores, "Post/Wait semaphore"); |
} |
|
void |
run_counter_tests(void) |
{ |
int i; |
cyg_tick_count_t val=0; |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < ncounters; i++) { |
HAL_CLOCK_READ(&counter_ft[i].start); |
cyg_counter_create(&counters[i], &test_counters[i]); |
HAL_CLOCK_READ(&counter_ft[i].end); |
} |
show_times(counter_ft, ncounters, "Create counter"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < ncounters; i++) { |
HAL_CLOCK_READ(&counter_ft[i].start); |
val = cyg_counter_current_value(counters[i]); |
HAL_CLOCK_READ(&counter_ft[i].end); |
} |
show_times(counter_ft, ncounters, "Get counter value"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < ncounters; i++) { |
HAL_CLOCK_READ(&counter_ft[i].start); |
cyg_counter_set_value(counters[i], val); |
HAL_CLOCK_READ(&counter_ft[i].end); |
} |
show_times(counter_ft, ncounters, "Set counter value"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < ncounters; i++) { |
HAL_CLOCK_READ(&counter_ft[i].start); |
cyg_counter_tick(counters[i]); |
HAL_CLOCK_READ(&counter_ft[i].end); |
} |
show_times(counter_ft, ncounters, "Tick counter"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < ncounters; i++) { |
HAL_CLOCK_READ(&counter_ft[i].start); |
cyg_counter_delete(counters[i]); |
HAL_CLOCK_READ(&counter_ft[i].end); |
} |
show_times(counter_ft, ncounters, "Delete counter"); |
end_of_test_group(); |
} |
|
void |
run_flag_tests(void) |
{ |
int i; |
cyg_flag_value_t val; |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nflags; i++) { |
HAL_CLOCK_READ(&flag_ft[i].start); |
cyg_flag_init(&test_flags[i]); |
HAL_CLOCK_READ(&flag_ft[i].end); |
} |
show_times(flag_ft, nflags, "Init flag"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nflags; i++) { |
HAL_CLOCK_READ(&flag_ft[i].start); |
cyg_flag_destroy(&test_flags[i]); |
HAL_CLOCK_READ(&flag_ft[i].end); |
} |
show_times(flag_ft, nflags, "Destroy flag"); |
|
// Recreate the flags - reused in the remaining tests |
for (i = 0; i < nflags; i++) { |
cyg_flag_init(&test_flags[i]); |
} |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nflags; i++) { |
HAL_CLOCK_READ(&flag_ft[i].start); |
cyg_flag_maskbits(&test_flags[i], 0); |
HAL_CLOCK_READ(&flag_ft[i].end); |
} |
show_times(flag_ft, nflags, "Mask bits in flag"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nflags; i++) { |
HAL_CLOCK_READ(&flag_ft[i].start); |
cyg_flag_setbits(&test_flags[i], 0x11); |
HAL_CLOCK_READ(&flag_ft[i].end); |
} |
show_times(flag_ft, nflags, "Set bits in flag [no waiters]"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nflags; i++) { |
cyg_flag_setbits(&test_flags[i], 0x11); |
HAL_CLOCK_READ(&flag_ft[i].start); |
cyg_flag_wait(&test_flags[i], 0x11, CYG_FLAG_WAITMODE_AND); |
HAL_CLOCK_READ(&flag_ft[i].end); |
} |
show_times(flag_ft, nflags, "Wait for flag [AND]"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nflags; i++) { |
cyg_flag_setbits(&test_flags[i], 0x11); |
HAL_CLOCK_READ(&flag_ft[i].start); |
cyg_flag_wait(&test_flags[i], 0x11, CYG_FLAG_WAITMODE_OR); |
HAL_CLOCK_READ(&flag_ft[i].end); |
} |
show_times(flag_ft, nflags, "Wait for flag [OR]"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nflags; i++) { |
cyg_flag_setbits(&test_flags[i], 0x11); |
HAL_CLOCK_READ(&flag_ft[i].start); |
cyg_flag_wait(&test_flags[i], 0x11, CYG_FLAG_WAITMODE_AND|CYG_FLAG_WAITMODE_CLR); |
HAL_CLOCK_READ(&flag_ft[i].end); |
} |
show_times(flag_ft, nflags, "Wait for flag [AND/CLR]"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nflags; i++) { |
cyg_flag_setbits(&test_flags[i], 0x11); |
HAL_CLOCK_READ(&flag_ft[i].start); |
cyg_flag_wait(&test_flags[i], 0x11, CYG_FLAG_WAITMODE_OR|CYG_FLAG_WAITMODE_CLR); |
HAL_CLOCK_READ(&flag_ft[i].end); |
} |
show_times(flag_ft, nflags, "Wait for flag [OR/CLR]"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nflags; i++) { |
cyg_flag_setbits(&test_flags[i], 0x11); |
HAL_CLOCK_READ(&flag_ft[i].start); |
val = cyg_flag_peek(&test_flags[i]); |
HAL_CLOCK_READ(&flag_ft[i].end); |
} |
show_times(flag_ft, nflags, "Peek on flag"); |
|
// Destroy flags - no longer needed |
for (i = 0; i < nflags; i++) { |
cyg_flag_destroy(&test_flags[i]); |
} |
end_of_test_group(); |
} |
|
// Alarm callback function |
void |
alarm_cb(cyg_handle_t alarm, cyg_addrword_t val) |
{ |
// empty call back |
} |
|
// Callback used to test determinancy |
static volatile int alarm_cnt; |
void |
alarm_cb2(cyg_handle_t alarm, cyg_addrword_t indx) |
{ |
if (alarm_cnt == nscheds) return; |
sched_ft[alarm_cnt].start = 0; |
HAL_CLOCK_READ(&sched_ft[alarm_cnt++].end); |
if (alarm_cnt == nscheds) { |
cyg_semaphore_post(&synchro); |
} |
} |
|
static void |
alarm_cb3(cyg_handle_t alarm, cyg_addrword_t indx) |
{ |
if (alarm_cnt == nscheds) { |
cyg_semaphore_post(&synchro); |
} else { |
sched_ft[alarm_cnt].start = 0; |
cyg_thread_resume((cyg_handle_t)indx); |
} |
} |
|
// Null thread, used to keep scheduler busy |
void |
alarm_test(cyg_uint32 id) |
{ |
while (true) { |
cyg_thread_yield(); |
} |
} |
|
// Thread that suspends itself at the first opportunity |
void |
alarm_test2(cyg_uint32 id) |
{ |
cyg_handle_t me = cyg_thread_self(); |
while (true) { |
HAL_CLOCK_READ(&sched_ft[alarm_cnt++].end); |
cyg_thread_suspend(me); |
} |
} |
|
void |
run_alarm_tests(void) |
{ |
int i; |
cyg_tick_count_t init_val, step_val; |
cyg_handle_t rtc_handle; |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < ncounters; i++) { |
cyg_counter_create(&counters[i], &test_counters[i]); |
} |
for (i = 0; i < nalarms; i++) { |
HAL_CLOCK_READ(&alarm_ft[i].start); |
cyg_alarm_create(counters[0], alarm_cb, 0, &alarms[i], &test_alarms[i]); |
HAL_CLOCK_READ(&alarm_ft[i].end); |
} |
show_times(alarm_ft, nalarms, "Create alarm"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
init_val = 0; step_val = 0; |
for (i = 0; i < nalarms; i++) { |
HAL_CLOCK_READ(&alarm_ft[i].start); |
cyg_alarm_initialize(alarms[i], init_val, step_val); |
HAL_CLOCK_READ(&alarm_ft[i].end); |
} |
show_times(alarm_ft, nalarms, "Initialize alarm"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
init_val = 0; step_val = 0; |
for (i = 0; i < nalarms; i++) { |
HAL_CLOCK_READ(&alarm_ft[i].start); |
cyg_alarm_disable(alarms[i]); |
HAL_CLOCK_READ(&alarm_ft[i].end); |
} |
show_times(alarm_ft, nalarms, "Disable alarm"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
init_val = 0; step_val = 0; |
for (i = 0; i < nalarms; i++) { |
HAL_CLOCK_READ(&alarm_ft[i].start); |
cyg_alarm_enable(alarms[i]); |
HAL_CLOCK_READ(&alarm_ft[i].end); |
} |
show_times(alarm_ft, nalarms, "Enable alarm"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nalarms; i++) { |
HAL_CLOCK_READ(&alarm_ft[i].start); |
cyg_alarm_delete(alarms[i]); |
HAL_CLOCK_READ(&alarm_ft[i].end); |
} |
show_times(alarm_ft, nalarms, "Delete alarm"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
cyg_counter_create(&counters[0], &test_counters[0]); |
cyg_alarm_create(counters[0], alarm_cb, 0, &alarms[0], &test_alarms[0]); |
init_val = 9999; step_val = 9999; |
cyg_alarm_initialize(alarms[0], init_val, step_val); |
cyg_alarm_enable(alarms[0]); |
for (i = 0; i < ncounters; i++) { |
HAL_CLOCK_READ(&counter_ft[i].start); |
cyg_counter_tick(counters[0]); |
HAL_CLOCK_READ(&counter_ft[i].end); |
} |
show_times(counter_ft, ncounters, "Tick counter [1 alarm]"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
cyg_counter_create(&counters[0], &test_counters[0]); |
for (i = 0; i < nalarms; i++) { |
cyg_alarm_create(counters[0], alarm_cb, 0, &alarms[i], &test_alarms[i]); |
init_val = 9999; step_val = 9999; |
cyg_alarm_initialize(alarms[i], init_val, step_val); |
cyg_alarm_enable(alarms[i]); |
} |
for (i = 0; i < ncounters; i++) { |
HAL_CLOCK_READ(&counter_ft[i].start); |
cyg_counter_tick(counters[0]); |
HAL_CLOCK_READ(&counter_ft[i].end); |
} |
show_times(counter_ft, ncounters, "Tick counter [many alarms]"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
cyg_counter_create(&counters[0], &test_counters[0]); |
cyg_alarm_create(counters[0], alarm_cb, 0, &alarms[0], &test_alarms[0]); |
init_val = 1; step_val = 1; |
cyg_alarm_initialize(alarms[0], init_val, step_val); |
cyg_alarm_enable(alarms[0]); |
for (i = 0; i < ncounters; i++) { |
HAL_CLOCK_READ(&counter_ft[i].start); |
cyg_counter_tick(counters[0]); |
HAL_CLOCK_READ(&counter_ft[i].end); |
} |
show_times(counter_ft, ncounters, "Tick & fire counter [1 alarm]"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
cyg_counter_create(&counters[0], &test_counters[0]); |
for (i = 0; i < nalarms; i++) { |
cyg_alarm_create(counters[0], alarm_cb, i, &alarms[i], &test_alarms[i]); |
init_val = 1; step_val = 1; |
cyg_alarm_initialize(alarms[i], init_val, step_val); |
cyg_alarm_enable(alarms[i]); |
} |
for (i = 0; i < nalarms; i++) { |
HAL_CLOCK_READ(&alarm_ft[i].start); |
cyg_counter_tick(counters[0]); |
HAL_CLOCK_READ(&alarm_ft[i].end); |
} |
for (i = 0; i < nalarms; i++) { |
cyg_alarm_delete(alarms[i]); |
} |
show_times(alarm_ft, nalarms, "Tick & fire counters [>1 together]"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
cyg_counter_create(&counters[0], &test_counters[0]); |
for (i = 0; i < nalarms; i++) { |
cyg_alarm_create(counters[0], alarm_cb, i, &alarms[i], &test_alarms[i]); |
init_val = i+1; step_val = nalarms+1; |
cyg_alarm_initialize(alarms[i], init_val, step_val); |
cyg_alarm_enable(alarms[i]); |
} |
for (i = 0; i < nalarms; i++) { |
HAL_CLOCK_READ(&alarm_ft[i].start); |
cyg_counter_tick(counters[0]); |
HAL_CLOCK_READ(&alarm_ft[i].end); |
} |
for (i = 0; i < nalarms; i++) { |
cyg_alarm_delete(alarms[i]); |
} |
show_times(alarm_ft, nalarms, "Tick & fire counters [>1 separately]"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
cyg_clock_to_counter(cyg_real_time_clock(), &rtc_handle); |
cyg_alarm_create(rtc_handle, alarm_cb2, 0, &alarms[0], &test_alarms[0]); |
init_val = 5; step_val = 5; alarm_cnt = 0; |
cyg_alarm_initialize(alarms[0], init_val, step_val); |
cyg_semaphore_init(&synchro, 0); |
cyg_alarm_enable(alarms[0]); |
cyg_semaphore_wait(&synchro); |
cyg_alarm_disable(alarms[0]); |
cyg_alarm_delete(alarms[0]); |
show_times(sched_ft, nscheds, "Alarm latency [0 threads]"); |
|
// Set my priority higher than any I plan to create |
cyg_thread_set_priority(cyg_thread_self(), 2); |
for (i = 0; i < 2; i++) { |
cyg_thread_create(10, // Priority - just a number |
alarm_test, // entry |
i, // index |
thread_name("thread", i), // Name |
&stacks[i][0], // Stack |
STACK_SIZE, // Size |
&threads[i], // Handle |
&test_threads[i] // Thread data structure |
); |
cyg_thread_resume(threads[i]); |
} |
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
cyg_clock_to_counter(cyg_real_time_clock(), &rtc_handle); |
cyg_alarm_create(rtc_handle, alarm_cb2, 0, &alarms[0], &test_alarms[0]); |
init_val = 5; step_val = 5; alarm_cnt = 0; |
cyg_alarm_initialize(alarms[0], init_val, step_val); |
cyg_semaphore_init(&synchro, 0); |
cyg_alarm_enable(alarms[0]); |
cyg_semaphore_wait(&synchro); |
cyg_alarm_disable(alarms[0]); |
cyg_alarm_delete(alarms[0]); |
show_times(sched_ft, nscheds, "Alarm latency [2 threads]"); |
for (i = 0; i < 2; i++) { |
cyg_thread_suspend(threads[i]); |
cyg_thread_delete(threads[i]); |
} |
|
// Set my priority higher than any I plan to create |
cyg_thread_set_priority(cyg_thread_self(), 2); |
for (i = 0; i < ntest_threads; i++) { |
cyg_thread_create(10, // Priority - just a number |
alarm_test, // entry |
i, // index |
thread_name("thread", i), // Name |
&stacks[i][0], // Stack |
STACK_SIZE, // Size |
&threads[i], // Handle |
&test_threads[i] // Thread data structure |
); |
cyg_thread_resume(threads[i]); |
} |
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
cyg_clock_to_counter(cyg_real_time_clock(), &rtc_handle); |
cyg_alarm_create(rtc_handle, alarm_cb2, 0, &alarms[0], &test_alarms[0]); |
init_val = 5; step_val = 5; alarm_cnt = 0; |
cyg_alarm_initialize(alarms[0], init_val, step_val); |
cyg_semaphore_init(&synchro, 0); |
cyg_alarm_enable(alarms[0]); |
cyg_semaphore_wait(&synchro); |
cyg_alarm_disable(alarms[0]); |
cyg_alarm_delete(alarms[0]); |
show_times(sched_ft, nscheds, "Alarm latency [many threads]"); |
for (i = 0; i < ntest_threads; i++) { |
cyg_thread_suspend(threads[i]); |
cyg_thread_delete(threads[i]); |
} |
|
// Set my priority higher than any I plan to create |
cyg_thread_set_priority(cyg_thread_self(), 2); |
cyg_thread_create(10, // Priority - just a number |
alarm_test2, // entry |
i, // index |
thread_name("thread", 0), // Name |
&stacks[0][0], // Stack |
STACK_SIZE, // Size |
&threads[0], // Handle |
&test_threads[0] // Thread data structure |
); |
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
cyg_clock_to_counter(cyg_real_time_clock(), &rtc_handle); |
cyg_alarm_create(rtc_handle, alarm_cb3, threads[0], &alarms[0], |
&test_alarms[0]); |
init_val = 5; step_val = 5; alarm_cnt = 0; |
cyg_alarm_initialize(alarms[0], init_val, step_val); |
cyg_semaphore_init(&synchro, 0); |
cyg_alarm_enable(alarms[0]); |
cyg_semaphore_wait(&synchro); |
cyg_alarm_disable(alarms[0]); |
cyg_alarm_delete(alarms[0]); |
show_times(sched_ft, nscheds, "Alarm -> thread resume latency"); |
cyg_thread_suspend(threads[0]); |
cyg_thread_delete(threads[0]); |
|
end_of_test_group(); |
} |
|
void |
run_sched_tests(void) |
{ |
int i; |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nscheds; i++) { |
HAL_CLOCK_READ(&sched_ft[i].start); |
cyg_scheduler_lock(); |
HAL_CLOCK_READ(&sched_ft[i].end); |
cyg_scheduler_unlock(); |
} |
show_times(sched_ft, nscheds, "Scheduler lock"); |
|
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nscheds; i++) { |
cyg_scheduler_lock(); |
HAL_CLOCK_READ(&sched_ft[i].start); |
cyg_scheduler_unlock(); |
HAL_CLOCK_READ(&sched_ft[i].end); |
} |
show_times(sched_ft, nscheds, "Scheduler unlock [0 threads]"); |
|
// Set my priority higher than any I plan to create |
cyg_thread_set_priority(cyg_thread_self(), 2); |
for (i = 0; i < 1; i++) { |
cyg_thread_create(10, // Priority - just a number |
test0, // entry |
i, // index |
thread_name("thread", i), // Name |
&stacks[i][0], // Stack |
STACK_SIZE, // Size |
&threads[i], // Handle |
&test_threads[i] // Thread data structure |
); |
} |
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nscheds; i++) { |
cyg_scheduler_lock(); |
HAL_CLOCK_READ(&sched_ft[i].start); |
cyg_scheduler_unlock(); |
HAL_CLOCK_READ(&sched_ft[i].end); |
} |
show_times(sched_ft, nscheds, "Scheduler unlock [1 suspended]"); |
for (i = 0; i < 1; i++) { |
cyg_thread_delete(threads[i]); |
} |
|
// Set my priority higher than any I plan to create |
cyg_thread_set_priority(cyg_thread_self(), 2); |
for (i = 0; i < ntest_threads; i++) { |
cyg_thread_create(10, // Priority - just a number |
test0, // entry |
i, // index |
thread_name("thread", i), // Name |
&stacks[i][0], // Stack |
STACK_SIZE, // Size |
&threads[i], // Handle |
&test_threads[i] // Thread data structure |
); |
} |
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nscheds; i++) { |
cyg_scheduler_lock(); |
HAL_CLOCK_READ(&sched_ft[i].start); |
cyg_scheduler_unlock(); |
HAL_CLOCK_READ(&sched_ft[i].end); |
} |
show_times(sched_ft, nscheds, "Scheduler unlock [many suspended]"); |
for (i = 0; i < ntest_threads; i++) { |
cyg_thread_delete(threads[i]); |
} |
|
// Set my priority higher than any I plan to create |
cyg_thread_set_priority(cyg_thread_self(), 2); |
for (i = 0; i < ntest_threads; i++) { |
cyg_thread_create(10, // Priority - just a number |
test0, // entry |
i, // index |
thread_name("thread", i), // Name |
&stacks[i][0], // Stack |
STACK_SIZE, // Size |
&threads[i], // Handle |
&test_threads[i] // Thread data structure |
); |
cyg_thread_resume(threads[i]); |
} |
wait_for_tick(); // Wait until the next clock tick to minimize aberations |
for (i = 0; i < nscheds; i++) { |
cyg_scheduler_lock(); |
HAL_CLOCK_READ(&sched_ft[i].start); |
cyg_scheduler_unlock(); |
HAL_CLOCK_READ(&sched_ft[i].end); |
} |
show_times(sched_ft, nscheds, "Scheduler unlock [many low prio]"); |
for (i = 0; i < ntest_threads; i++) { |
cyg_thread_delete(threads[i]); |
} |
end_of_test_group(); |
} |
|
void |
run_all_tests(CYG_ADDRESS id) |
{ |
int i, j; |
cyg_uint32 tv[nsamples], tv0, tv1; |
cyg_uint32 min_stack, max_stack, total_stack, actual_stack; |
cyg_tick_count_t ticks, tick0, tick1; |
#ifdef CYG_SCHEDULER_LOCK_TIMINGS |
cyg_uint32 lock_ave, lock_max; |
#endif |
#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY) |
cyg_int32 clock_ave; |
#endif |
|
disable_clock_latency_measurement(); |
|
#ifndef CYGPKG_KERNEL_SMP_SUPPORT |
cyg_test_dump_thread_stack_stats( "Startup, main stack", thread[0] ); |
cyg_test_dump_interrupt_stack_stats( "Startup" ); |
cyg_test_dump_idlethread_stack_stats( "Startup" ); |
cyg_test_clear_interrupt_stack(); |
#endif |
|
diag_printf("\neCos Kernel Timings\n"); |
diag_printf("Notes: all times are in microseconds (.000001) unless otherwise stated\n"); |
#ifdef STATS_WITHOUT_FIRST_SAMPLE |
diag_printf(" second line of results have first sample removed\n"); |
#endif |
|
cyg_thread_delay(2); // Make sure the clock is actually running |
|
ns_per_system_clock = 1000000/rtc_resolution[1]; |
|
wait_for_tick(); |
for (i = 0; i < nsamples; i++) { |
HAL_CLOCK_READ(&tv[i]); |
} |
tv0 = 0; |
for (i = 1; i < nsamples; i++) { |
tv0 += tv[i] - tv[i-1]; |
} |
end_of_test_group(); |
|
overhead = tv0 / (nsamples-1); |
diag_printf("Reading the hardware clock takes %d 'ticks' overhead\n", overhead); |
diag_printf("... this value will be factored out of all other measurements\n"); |
|
// Try and measure how long the clock interrupt handling takes |
for (i = 0; i < nsamples; i++) { |
tick0 = cyg_current_time(); |
while (true) { |
tick1 = cyg_current_time(); |
if (tick0 != tick1) break; |
} |
HAL_CLOCK_READ(&tv[i]); |
} |
tv1 = 0; |
for (i = 0; i < nsamples; i++) { |
tv1 += tv[i] * 1000; |
} |
tv1 = tv1 / nsamples; |
tv1 -= overhead; // Adjust out the cost of getting the timer value |
diag_printf("Clock interrupt took"); |
show_ticks_in_us(tv1); |
diag_printf(" microseconds (%d raw clock ticks)\n", tv1/1000); |
enable_clock_latency_measurement(); |
|
ticks = cyg_current_time(); |
|
show_test_parameters(); |
show_times_hdr(); |
|
reset_clock_latency_measurement(); |
|
run_thread_tests(); |
run_sched_tests(); |
run_mutex_tests(); |
run_mbox_tests(); |
run_semaphore_tests(); |
run_counter_tests(); |
run_flag_tests(); |
run_alarm_tests(); |
|
#ifdef CYG_SCHEDULER_LOCK_TIMINGS |
Cyg_Scheduler::get_lock_times(&lock_ave, &lock_max); |
diag_printf("\nMax lock:"); |
show_ticks_in_us(lock_max); |
diag_printf(", Ave lock:"); |
show_ticks_in_us(lock_ave); |
diag_printf("\n"); |
#endif |
|
#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY) |
// Display latency figures in same format as all other numbers |
disable_clock_latency_measurement(); |
clock_ave = (total_clock_latency*1000) / total_clock_interrupts; |
show_ticks_in_us(clock_ave); |
show_ticks_in_us(min_clock_latency*1000); |
show_ticks_in_us(max_clock_latency*1000); |
show_ticks_in_us(0); |
diag_printf(" Clock/interrupt latency\n\n"); |
enable_clock_latency_measurement(); |
#endif |
|
#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY) && defined(HAL_CLOCK_LATENCY) |
disable_clock_latency_measurement(); |
clock_ave = (total_clock_dsr_latency*1000) / total_clock_dsr_calls; |
show_ticks_in_us(clock_ave); |
show_ticks_in_us(min_clock_dsr_latency*1000); |
show_ticks_in_us(max_clock_dsr_latency*1000); |
show_ticks_in_us(0); |
diag_printf(" Clock DSR latency\n\n"); |
enable_clock_latency_measurement(); |
#endif |
|
#ifndef CYGPKG_KERNEL_SMP_SUPPORT |
disable_clock_latency_measurement(); |
min_stack = STACK_SIZE; |
max_stack = 0; |
total_stack = 0; |
for (i = 0; i < (int)NTEST_THREADS; i++) { |
for (j = 0; j < STACK_SIZE; j++) { |
if (stacks[i][j]) break; |
} |
actual_stack = STACK_SIZE-j; |
if (actual_stack < min_stack) min_stack = actual_stack; |
if (actual_stack > max_stack) max_stack = actual_stack; |
total_stack += actual_stack; |
} |
for (j = 0; j < STACKSIZE; j++) { |
if (((char *)stack[0])[j]) break; |
} |
diag_printf("%5d %5d %5d (main stack: %5d) Thread stack used (%d total)\n", |
total_stack/NTEST_THREADS, min_stack, max_stack, |
STACKSIZE - j, STACK_SIZE); |
|
cyg_test_dump_thread_stack_stats( "All done, main stack", thread[0] ); |
cyg_test_dump_interrupt_stack_stats( "All done" ); |
cyg_test_dump_idlethread_stack_stats( "All done" ); |
#endif |
|
enable_clock_latency_measurement(); |
|
ticks = cyg_current_time(); |
diag_printf("\nTiming complete - %d ms total\n\n", (int)((ticks*ns_per_system_clock)/1000)); |
|
CYG_TEST_PASS_FINISH("Basic timing OK"); |
} |
|
void tm_basic_main( void ) |
{ |
CYG_TEST_INIT(); |
|
if (cyg_test_is_simulator) { |
nsamples = NSAMPLES_SIM; |
ntest_threads = NTEST_THREADS_SIM; |
nthread_switches = NTHREAD_SWITCHES_SIM; |
nmutexes = NMUTEXES_SIM; |
nmboxes = NMBOXES_SIM; |
nsemaphores = NSEMAPHORES_SIM; |
nscheds = NSCHEDS_SIM; |
nflags = NFLAGS_SIM; |
ncounters = NCOUNTERS_SIM; |
nalarms = NALARMS_SIM; |
} else { |
nsamples = NSAMPLES; |
ntest_threads = NTEST_THREADS; |
nthread_switches = NTHREAD_SWITCHES; |
nmutexes = NMUTEXES; |
nmboxes = NMBOXES; |
nsemaphores = NSEMAPHORES; |
nscheds = NSCHEDS; |
nflags = NFLAGS; |
ncounters = NCOUNTERS; |
nalarms = NALARMS; |
} |
|
// Sanity |
#ifdef WORKHORSE_TEST |
ntest_threads = max(512, ntest_threads); |
nmutexes = max(1024, nmutexes); |
nsemaphores = max(1024, nsemaphores); |
nmboxes = max(1024, nmboxes); |
ncounters = max(1024, ncounters); |
nalarms = max(1024, nalarms); |
#else |
ntest_threads = max(64, ntest_threads); |
nmutexes = max(32, nmutexes); |
nsemaphores = max(32, nsemaphores); |
nmboxes = max(32, nmboxes); |
ncounters = max(32, ncounters); |
nflags = max(32, nflags); |
nalarms = max(32, nalarms); |
#endif |
|
new_thread(run_all_tests, 0); |
|
Cyg_Scheduler::scheduler.start(); |
|
} |
|
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
externC void |
cyg_hal_invoke_constructors(); |
#endif |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
tm_basic_main(); |
} |
|
#else // CYGFUN_KERNEL_API_C |
|
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA("Timing tests require:\n" |
"CYGFUN_KERNEL_API_C && \n" |
"CYGSEM_KERNEL_SCHED_MLQUEUE &&\n" |
"CYGVAR_KERNEL_COUNTERS_CLOCK &&\n" |
"!CYGDBG_INFRA_DIAG_USE_DEVICE &&\n" |
"(CYGNUM_KERNEL_SCHED_PRIORITIES > 12)\n"); |
} |
#endif // CYGFUN_KERNEL_API_C, etc. |
|
// EOF tm_basic.cxx |
/mqueue1.cxx
0,0 → 1,411
/*======================================================================== |
// |
// mqueue1.cxx |
// |
// Message queues tests |
// |
//======================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//======================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): jlarmour |
// Contributors: |
// Date: 2000-05-12 |
// Purpose: This file provides tests for eCos mqueues |
// Description: |
// Usage: |
// |
//####DESCRIPTIONEND#### |
// |
//====================================================================== |
*/ |
|
/* CONFIGURATION */ |
|
#include <pkgconf/kernel.h> |
|
/* INCLUDES */ |
|
#include <cyg/infra/cyg_type.h> // common types and externC |
#include <cyg/kernel/thread.hxx> // Cyg_Thread |
#include <cyg/kernel/thread.inl> |
// Specially avoid inlining here due to the way we abuse the mqueue |
// implementation by making lots and lots of calls. |
#define CYGPRI_KERNEL_SYNCH_MQUEUE_INLINE |
#include <cyg/kernel/mqueue.hxx> // Mqueue Header |
#include <cyg/kernel/sema.hxx> // semaphores |
#include <cyg/infra/testcase.h> // test API |
|
// use the common kernel test magic to define 2 threads |
#define NTHREADS 2 |
#include "testaux.hxx" |
|
/* GLOBALS */ |
|
static char mempool[500]; |
static size_t storedmempoollen; |
Cyg_Mqueue *mq; |
static Cyg_Binary_Semaphore t0sem, t1sem; |
static int calledback; |
|
|
/* FUNCTIONS */ |
|
static int |
my_memcmp(const void *m1, const void *m2, size_t n) |
{ |
char *s1 = (char *)m1; |
char *s2 = (char *)m2; |
|
while (n--) { |
if (*s1 != *s2) |
return *s1 - *s2; |
s1++; |
s2++; |
} |
return 0; |
} // my_memcmp() |
|
static void * |
my_alloc( size_t len ) |
{ |
if ( len > sizeof(mempool) ) |
return NULL; |
|
storedmempoollen = len; |
return &mempool[0]; |
} |
|
static void |
my_free( void *ptr, size_t len ) |
{ |
CYG_TEST_PASS_FAIL( (ptr == &mempool[0]) && (len == storedmempoollen), |
"Freed pool correctly"); |
mq = NULL; // invalidate |
} |
|
static void |
callback(Cyg_Mqueue &mq, CYG_ADDRWORD data) |
{ |
calledback += (int)data; |
} |
|
//************************************************************************ |
//************************************************************************ |
|
static void |
t0( CYG_ADDRWORD data ) |
{ |
Cyg_Mqueue::qerr_t err; |
char buf[35]; |
size_t len; |
unsigned int prio; |
bool b; |
|
Cyg_Mqueue the_mq(4, 32, &my_alloc, &my_free, &err ); |
CYG_TEST_PASS_FAIL( Cyg_Mqueue::OK == err, |
"Create queue" ); |
mq = &the_mq; |
|
//------------------------------------------------------------------------ |
|
err = mq->put( "Peter piper picked", sizeof("Peter piper picked"), |
5, true ); |
CYG_TEST_PASS_FAIL( Cyg_Mqueue::OK == err, "Simple (put)"); |
|
t1sem.post(); |
|
//------------------------------------------------------------------------ |
|
t0sem.wait(); |
|
err = mq->get( buf, &len, &prio, true ); |
b = (err == Cyg_Mqueue::OK); |
if (b) |
b = (len == sizeof("a peck of")); |
if (b) |
b = (prio == 100); |
if (b) |
b = (0 == |
my_memcmp(buf, "a peck of", sizeof("a peck of")) |
); |
CYG_TEST_PASS_FAIL( b, "Blocking get"); |
|
//------------------------------------------------------------------------ |
|
t0sem.wait(); |
|
CYG_TEST_PASS_FAIL( 4 == mq->count(), "mq count" ); |
err = mq->get( buf, &len, &prio, false ); |
b = (err == Cyg_Mqueue::OK); |
if (b) |
b = (len == sizeof("pickled peppers")); |
if (b) |
b = (prio == 300); |
if (b) |
b = (0 == |
my_memcmp(buf, "pickled peppers", sizeof("pickled peppers")) |
); |
if (b) |
b = (3 == mq->count()); |
CYG_TEST_PASS_FAIL( b, "Prioritized (get 1)"); |
|
err = mq->get( buf, &len, &prio, false ); |
b = (err == Cyg_Mqueue::OK); |
if (b) |
b = (len == sizeof(".")); |
if (b) |
b = (prio == 250); |
if (b) |
b = (0 == |
my_memcmp(buf, ".", sizeof(".")) |
); |
if (b) |
b = (2 == mq->count()); |
CYG_TEST_PASS_FAIL( b, "Prioritized (get 2)"); |
|
err = mq->get( buf, &len, &prio, false ); |
b = (err == Cyg_Mqueue::OK); |
if (b) |
b = (len == 1); |
if (b) |
b = (prio == 225); |
if (b) |
b = (0 == |
my_memcmp(buf, "", 1) |
); |
if (b) |
b = (1 == mq->count()); |
CYG_TEST_PASS_FAIL( b, "Prioritized (get 3)"); |
|
err = mq->get( buf, &len, &prio, false ); |
b = (err == Cyg_Mqueue::OK); |
if (b) |
b = (len == sizeof("If Peter")); |
if (b) |
b = (prio == 200); |
if (b) |
b = (0 == |
my_memcmp(buf, "If Peter", sizeof("If Peter")) |
); |
if (b) |
b = (0 == mq->count()); |
CYG_TEST_PASS_FAIL( b, "Prioritized (get 4)"); |
|
//------------------------------------------------------------------------ |
|
err = mq->get( buf, &len, &prio, false ); |
|
CYG_TEST_PASS_FAIL( Cyg_Mqueue::WOULDBLOCK == err, |
"Non-blocking get of empty queue" ); |
|
//------------------------------------------------------------------------ |
|
Cyg_Mqueue::callback_fn_t oldcallback; |
|
oldcallback = mq->setnotify( &callback, (CYG_ADDRWORD) 42 ); |
|
err = mq->put( "If Peter", sizeof("If Peter"), |
200, false ); |
CYG_TEST_PASS_FAIL( Cyg_Mqueue::OK == err, |
"Prioritized (put in empty queue)"); |
CYG_TEST_PASS_FAIL( 42 == calledback, "callback" ); |
CYG_TEST_PASS_FAIL( NULL == oldcallback, "oldcallback" ); |
|
err = mq->get( buf, &len, &prio, false ); |
b = (err == Cyg_Mqueue::OK); |
if (b) |
b = (len == sizeof("If Peter")); |
if (b) |
b = (prio == 200); |
if (b) |
b = (0 == |
my_memcmp(buf, "If Peter", sizeof("If Peter")) |
); |
CYG_TEST_PASS_FAIL( b, "Prioritized (get 2)"); |
|
t1sem.post(); |
|
err = mq->get( buf, &len, &prio, true ); |
b = (err == Cyg_Mqueue::OK); |
if (b) |
b = (len == 32); |
if (b) |
b = (42 == calledback); |
if (b) |
b = (prio == 250); |
if (b) |
b = (0 == |
my_memcmp(buf, "12345678901234567890123456789012", 32) |
); |
CYG_TEST_PASS_FAIL( b, "callback (blocked wait)"); |
|
//------------------------------------------------------------------------ |
|
t1sem.post(); |
t0sem.wait(); |
|
} // t0() |
|
|
//************************************************************************ |
//************************************************************************ |
|
|
static void |
t1( CYG_ADDRWORD data ) |
{ |
Cyg_Mqueue::qerr_t err; |
char buf[35]; |
size_t len; |
unsigned int prio; |
bool b; |
|
//------------------------------------------------------------------------ |
|
// wait till t0 says we can go |
t1sem.wait(); |
|
err = mq->get( buf, &len, &prio, true ); |
b = (err == Cyg_Mqueue::OK); |
if (b) |
b = (len == sizeof("Peter piper picked")); |
if (b) |
b = (prio == 5); |
if (b) |
b = (0 == |
my_memcmp(buf, "Peter piper picked", sizeof("Peter piper picked")) |
); |
|
CYG_TEST_PASS_FAIL( b, "Simple"); |
|
//------------------------------------------------------------------------ |
|
t0sem.post(); // t0 should run straight away |
Cyg_Thread::yield(); // but just in case we have a funny sched |
|
// by now t0 is blocked in mq->get |
|
err = mq->put( "a peck of", sizeof("a peck of"), |
100, false ); |
CYG_TEST_PASS_FAIL( Cyg_Mqueue::OK == err, "Block (put in empty queue)"); |
|
//------------------------------------------------------------------------ |
|
err = mq->put( "If Peter", sizeof("If Peter"), |
200, false ); |
CYG_TEST_PASS_FAIL( Cyg_Mqueue::OK == err, |
"Prioritized (put in empty queue)"); |
|
err = mq->put( "pickled peppers", sizeof("pickled peppers"), |
300, false ); |
CYG_TEST_PASS_FAIL( Cyg_Mqueue::OK == err, |
"Prioritized (put in queue w/1)"); |
|
err = mq->put( ".", sizeof("."), 250, false ); |
CYG_TEST_PASS_FAIL( Cyg_Mqueue::OK == err, |
"Prioritized (put in queue w/2)"); |
|
err = mq->put( "", 1, 225, false ); |
CYG_TEST_PASS_FAIL( Cyg_Mqueue::OK == err, |
"Prioritized (put in queue w/3)"); |
|
err = mq->put( "foobar", 6, 1, false ); |
CYG_TEST_PASS_FAIL( Cyg_Mqueue::WOULDBLOCK == err, |
"Prioritized (full queue)"); |
|
t0sem.post(); |
|
//------------------------------------------------------------------------ |
|
t1sem.wait(); |
Cyg_Thread::yield(); // but just in case we have a funny sched |
|
err = mq->put( "12345678901234567890123456789012xxxx", 32, |
250, false ); |
CYG_TEST_PASS_FAIL( Cyg_Mqueue::OK == err, |
"callback (put in queue)"); |
|
//------------------------------------------------------------------------ |
|
t1sem.wait(); |
|
// Create an oversized queue |
{ |
Cyg_Mqueue huge_mq(99999, 99999, &my_alloc, &my_free, &err ); |
CYG_TEST_PASS_FAIL( Cyg_Mqueue::NOMEM == err, |
"Oversized queue rejected" ); |
// and it now gets destructed - but that shouldn't call free |
// to be called |
} |
|
//------------------------------------------------------------------------ |
|
t0sem.post(); // t0 should run straight away |
Cyg_Thread::yield(); // but just in case we have a funny sched |
|
// check that mq was destroyed when t0 dropped off the end |
CYG_TEST_PASS_FAIL( NULL == mq, "queue destroyed correctly" ); |
|
CYG_TEST_EXIT("kernel mqueue test 1"); |
|
} // t1() |
|
|
//************************************************************************ |
//************************************************************************ |
|
externC void |
cyg_user_start(void) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
CYG_TEST_INIT(); |
|
CYG_TEST_INFO( "Starting kernel mqueue test 1" ); |
new_thread( t0, 0); |
new_thread( t1, 1); |
|
#ifdef CYGIMP_THREAD_PRIORITY |
thread[0]->set_priority( 4 ); |
thread[1]->set_priority( 5 ); // make sure the threads execute as intended |
#endif |
} // cyg_user_start() |
|
//------------------------------------------------------------------------ |
|
|
/* EOF mqueue1.cxx */ |
/kthread0.c
0,0 → 1,120
/*================================================================= |
// |
// kthread0.c |
// |
// Kernel C API Thread test 0 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-03-18 |
// Description: Limited to checking constructors/destructors |
//####DESCRIPTIONEND#### |
*/ |
|
#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
#include <cyg/kernel/kapi.h> |
|
#include <cyg/infra/testcase.h> |
|
#ifdef CYGFUN_KERNEL_API_C |
|
#include "testaux.h" |
|
#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
static char stack[STACKSIZE]; |
|
static cyg_thread_entry_t entry; |
|
static void entry( cyg_addrword_t data ) |
{ |
} |
|
static int *p; |
|
#if 0 |
static cyg_handle_t t0,t1; |
static cyg_thread thread0, thread1; |
#endif |
|
static cyg_handle_t t2; |
static cyg_thread thread2; |
|
static bool flash( void ) |
{ |
#if 0 // no facility to allocate stack exists yet. |
cyg_thread_create( entry, 0x111, NULL, 0, &t0, &thread0 ); |
|
cyg_thread_create( entry, (cyg_addrword_t)&t0, STACKSIZE, 0, &t1, &thread0 ); |
#endif |
|
cyg_thread_create(4, entry, (cyg_addrword_t)p, "kthread0", |
(void *)stack, STACKSIZE, &t2, &thread2 ); |
|
return true; |
} |
|
void kthread0_main( void ) |
{ |
CYG_TEST_INIT(); |
|
CHECK(flash()); |
CHECK(flash()); |
|
CYG_TEST_PASS_FINISH("Kernel C API Thread 0 OK"); |
|
} |
|
externC void |
cyg_start( void ) |
{ |
kthread0_main(); |
} |
|
#else /* def CYGFUN_KERNEL_API_C */ |
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA("Kernel C API layer disabled"); |
} |
#endif /* def CYGFUN_KERNEL_API_C */ |
|
/* EOF kthread0.c */ |
/testaux.h
0,0 → 1,62
#ifndef CYGONCE_KERNEL_TESTS_TESTAUX_H |
#define CYGONCE_KERNEL_TESTS_TESTAUX_H |
|
/*================================================================= |
// |
// testaux.h |
// |
// Auxiliary test header file |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-03-09 |
// Description: |
// Defines some convenience functions to get us going. In |
// particular this file reserves space for NTHREADS threads, |
// which can be created by calls to aux_new_thread() |
// It also defines a CHECK function. |
// |
//####DESCRIPTIONEND#### |
*/ |
|
#define CHECK(b) CYG_TEST_CHECK(b,#b) |
|
#endif /* ifndef CYGONCE_KERNEL_TESTS_TESTAUX_H */ |
|
/* EOF testaux.h */ |
/clocktruth.cxx
0,0 → 1,155
//========================================================================== |
// |
// clocktruth.cxx |
// |
// Clock Converter test |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. |
// Copyright (C) 2003 Gary Thomas |
// |
// 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): hmt |
// Contributors: hmt |
// Date: 2001-06-05 |
// Description: Tests the Kernel Real Time Clock for accuracy using a human |
// |
//####DESCRIPTIONEND#### |
|
|
// This is for a human to watch to sanity check the clock rate. |
// It's easier to see what's happening if you enable this: |
#define nRUNFOREVER |
|
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/clock.hxx> |
#include <cyg/kernel/sema.hxx> |
#include <cyg/kernel/thread.hxx> |
|
#include <cyg/infra/testcase.h> |
|
#include <cyg/kernel/clock.inl> |
#include <cyg/kernel/thread.inl> |
|
#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK |
|
#include <cyg/infra/diag.h> |
|
#define NTHREADS 1 |
#include "testaux.hxx" |
|
#ifdef RUNFOREVER |
#define ENDPOINT 8192 |
#else |
#define ENDPOINT 20 |
#endif |
|
static cyg_alarm_fn alarmfunc; |
static void alarmfunc( Cyg_Alarm *alarm, CYG_ADDRWORD data ) |
{ |
Cyg_Binary_Semaphore *sp = (Cyg_Binary_Semaphore *)data; |
sp->post(); |
} |
|
|
static void entry0( CYG_ADDRWORD data ) |
{ |
cyg_uint32 now, then; |
int i; |
|
Cyg_Clock *rtc = Cyg_Clock::real_time_clock; |
|
Cyg_Binary_Semaphore sema; |
|
Cyg_Alarm alarm( rtc, &alarmfunc, (CYG_ADDRWORD)&sema ); |
|
// First, print 100 lines as fast as you can, of distinct ticks. |
for ( i = 0; i < 100; i++ ) { |
now = rtc->current_value_lo(); |
then = now; |
while ( then == now ) |
now = rtc->current_value_lo(); |
|
diag_printf( "INFO<time now %8d>\n", now ); |
} |
|
diag_printf( "INFO<per-second times are: %8d>\n", rtc->current_value_lo() ); |
for ( i = 0; i < 20; i++ ) { |
Cyg_Thread::counted_sleep( 100 ); |
diag_printf( "INFO<per-second time %2d is %8d>\n", |
i, rtc->current_value_lo() ); |
} |
|
alarm.initialize( rtc->current_value() + 100, 100 ); |
alarm.enable(); |
for ( i = 0; i < ENDPOINT; i++ ) { |
sema.wait(); |
diag_printf( "INFO<alarm time %2d is %8d>\n", |
i, rtc->current_value_lo() ); |
} |
|
CYG_TEST_PASS_FINISH("Clock truth OK"); |
} |
|
void clocktruth_main( void ) |
{ |
CYG_TEST_INIT(); |
new_thread(entry0, (CYG_ADDRWORD)&thread_obj[0]); |
Cyg_Scheduler::start(); |
} |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
clocktruth_main(); |
} |
|
#else // def CYGVAR_KERNEL_COUNTERS_CLOCK |
|
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA( "Kernel real-time clock disabled"); |
} |
|
#endif // def CYGVAR_KERNEL_COUNTERS_CLOCK |
|
// EOF clocktruth.cxx |
/kthread1.c
0,0 → 1,136
/*================================================================= |
// |
// kthread1.c |
// |
// Kernel C API Thread test 1 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-03-18 |
// Description: Tests some basic thread functions. |
//####DESCRIPTIONEND#### |
*/ |
|
#include <cyg/kernel/kapi.h> |
|
#include <cyg/infra/testcase.h> |
|
#ifdef CYGFUN_KERNEL_API_C |
|
#include "testaux.h" |
|
#include <cyg/hal/hal_arch.h> // for CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
#ifdef CYGNUM_HAL_STACK_SIZE_TYPICAL |
#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL |
#else |
#define STACKSIZE 2000 |
#endif |
|
static char stack[2][STACKSIZE]; |
|
static cyg_thread thread[2]; |
|
static cyg_handle_t pt0,pt1; |
|
|
static void entry0( cyg_addrword_t data ) |
{ |
CHECK( 222 == (int)data ); |
|
cyg_thread_suspend(pt1); |
cyg_thread_resume(pt1); |
|
cyg_thread_delay(1); |
|
cyg_thread_resume(pt1); |
|
cyg_thread_delay(1); |
|
CYG_TEST_PASS_FINISH("Kernel C API Thread 1 OK"); |
} |
|
static void entry1( cyg_addrword_t data ) |
{ |
cyg_handle_t self; |
CHECK( 333 == (int)data ); |
|
self = cyg_thread_self(); |
|
CHECK( self == pt1 ); |
|
cyg_thread_suspend(pt1); |
|
cyg_thread_exit(); // no guarantee this will be called |
} |
|
void kthread1_main( void ) |
{ |
CYG_TEST_INIT(); |
|
cyg_thread_create(4, entry0, (cyg_addrword_t)222, "kthread1-0", |
(void *)stack[0], STACKSIZE, &pt0, &thread[0] ); |
cyg_thread_create(4, entry1, (cyg_addrword_t)333, "kthread1-1", |
(void *)stack[1], STACKSIZE, &pt1, &thread[1] ); |
|
cyg_thread_resume(pt0); |
cyg_thread_resume(pt1); |
|
cyg_scheduler_start(); |
|
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
externC void |
cyg_start( void ) |
{ |
kthread1_main(); |
} |
|
|
#else /* def CYGFUN_KERNEL_API_C */ |
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA("Kernel C API layer disabled"); |
} |
#endif /* def CYGFUN_KERNEL_API_C */ |
|
/* EOF kthread1.c */ |
/mbox1.cxx
0,0 → 1,201
//========================================================================== |
// |
// mbox1.cxx |
// |
// Mbox test 1 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author: dsm |
// Contributors: dsm |
// Date: 1998-05-19 |
// Description: Tests basic mbox functionality. |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/thread.hxx> // Cyg_Thread |
#include <cyg/kernel/thread.inl> |
#include <cyg/kernel/sched.hxx> // Cyg_Scheduler::start() |
|
#include <cyg/kernel/mbox.hxx> |
|
#include <cyg/infra/testcase.h> |
|
#include <cyg/kernel/sched.inl> |
|
#include <cyg/kernel/timer.hxx> // Cyg_Timer |
#include <cyg/kernel/clock.inl> // Cyg_Clock |
|
#define NTHREADS 2 |
#include "testaux.hxx" |
|
static Cyg_Mbox m0, m1, m2; |
|
static volatile cyg_atomic q = 0; |
|
#ifndef CYGMTH_MBOX_PUT_CAN_WAIT |
#define PUT tryput |
#endif |
|
static void entry0( CYG_ADDRWORD data ) |
{ |
cyg_count8 u,i; |
|
CYG_TEST_INFO("Testing put() and tryput() without wakeup"); |
CYG_TEST_CHECK(!m0.waiting_to_get(), "mbox not initialized properly"); |
CYG_TEST_CHECK(0==m0.peek(), "mbox not initialized properly"); |
CYG_TEST_CHECK(NULL==m0.peek_item(), "mbox not initialized properly"); |
m0.PUT((void *)55); |
CYG_TEST_CHECK(1==m0.peek(), "peek() wrong"); |
CYG_TEST_CHECK(55==(cyg_count8)m0.peek_item(), "peek_item() wrong"); |
for(u=1; m0.tryput((void*)u); u++) { |
CYG_TEST_CHECK(55==(cyg_count8)m0.peek_item(), "peek_item() wrong"); |
CYG_TEST_CHECK(u+1==m0.peek(), "peek() wrong"); |
} |
CYG_TEST_CHECK(u == CYGNUM_KERNEL_SYNCH_MBOX_QUEUE_SIZE, "mbox not configured size"); |
|
// m0 now contains ( 55 1 2 .. u-1 ) |
CYG_TEST_CHECK(u==m0.peek(), "peek() wrong"); |
CYG_TEST_CHECK(55==(cyg_count8)m0.peek_item(), "peek_item() wrong"); |
|
CYG_TEST_INFO("Testing get(), tryget()"); |
|
i = (cyg_count8)m0.tryget(); |
CYG_TEST_CHECK( 55 == i, "Got wrong message" ); |
for(cyg_count8 j=1; j<u;j++) { |
CYG_TEST_CHECK( j == (cyg_count8)m0.peek_item(), "peek_item()" ); |
CYG_TEST_CHECK( m0.peek() == u - j, "peek() wrong" ); |
i = (cyg_count8)m0.get(); |
CYG_TEST_CHECK( j == i, "Got wrong message" ); |
} |
|
CYG_TEST_CHECK( NULL == m0.peek_item(), "peek_item()" ); |
CYG_TEST_CHECK( 0 == m0.peek(), "peek()"); |
|
// m0 now empty |
|
CYG_TEST_CHECK(!m0.waiting_to_put(), "waiting_to_put()"); |
CYG_TEST_CHECK(!m0.waiting_to_get(), "waiting_to_get()"); |
|
CYG_TEST_INFO("Testing get(), blocking"); |
|
CYG_TEST_CHECK(0==q++, "bad synchronization"); |
m1.PUT((void*)99); // wakes t1 |
i = (cyg_count8)m0.get(); // sent by t1 |
CYG_TEST_CHECK(3==i, "Recieved wrong message"); |
CYG_TEST_CHECK(2==q++, "bad synchronization"); |
|
#ifdef CYGFUN_KERNEL_THREADS_TIMER |
CYG_TEST_CHECK(NULL==m0.get( |
Cyg_Clock::real_time_clock->current_value() + 10), |
"unexpectedly found message"); |
CYG_TEST_CHECK(3==q++, "bad synchronization"); |
// Allow t1 to run as this get times out |
// t1 must not be waiting... |
CYG_TEST_CHECK(m0.waiting_to_get(), "waiting_to_get()"); |
|
m0.PUT((void*)7); // wake t1 from timed get |
#ifdef CYGMTH_MBOX_PUT_CAN_WAIT |
q=10; |
while(m0.tryput((void*)6)) // fill m0's queue |
; |
// m0 now contains ( 6 ... 6 ) |
CYG_TEST_CHECK(10==q++, "bad synchronization"); |
m1.put((void*)4); // wake t1 |
CYG_TEST_CHECK(!m0.put((void*)8, 2), "timed put() unexpectedly worked"); |
CYG_TEST_CHECK(12==q++, "bad synchronization"); |
// m0 still contains ( 6 ... 6 ) |
m0.put((void*)9); |
CYG_TEST_CHECK(13==q++, "bad synchronization"); |
#endif |
#endif |
i=(cyg_count8)m2.get(); |
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
static void entry1( CYG_ADDRWORD data ) |
{ |
cyg_count8 i; |
i = (cyg_count8)m1.get(); |
CYG_TEST_CHECK(1==q++, "bad synchronization"); |
m0.PUT((void *)3); // wake t0 |
|
#ifdef CYGFUN_KERNEL_THREADS_TIMER |
CYG_TEST_INFO("Testing timed functions"); |
CYG_TEST_CHECK(7==(cyg_count8)m0.get( |
Cyg_Clock::real_time_clock->current_value() + 20), "timed get()"); |
CYG_TEST_CHECK(4==q++, "bad synchronization"); |
#ifdef CYGMTH_MBOX_PUT_CAN_WAIT |
CYG_TEST_CHECK(4==(cyg_count8)m1.get()); |
|
CYG_TEST_CHECK(11==q++, "bad synchronization"); |
thread[0]->delay(20); // allow t0 to reach put on m1 |
CYG_TEST_CHECK(14==q++, "bad synchronization"); |
CYG_TEST_CHECK(m0.waiting_to_put(), "waiting_to_put()"); |
do { |
// after first get m0 contains ( 6 .. 6 9 ) |
i=(cyg_count8)m0.tryget(); |
} while(6==i); |
CYG_TEST_CHECK(9==i,"put gone awry"); |
#endif |
#endif |
CYG_TEST_PASS_FINISH("Mbox 1 OK"); |
} |
|
void mbox1_main( void ) |
{ |
CYG_TEST_INIT(); |
|
new_thread(entry0, 0); |
new_thread(entry1, 1); |
|
Cyg_Scheduler::start(); |
|
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
mbox1_main(); |
} |
|
// EOF mbox1.cxx |
/flag0.cxx
0,0 → 1,88
//========================================================================== |
// |
// flag0.cxx |
// |
// Flag test 0 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-05-11 |
// Description: Limited to checking constructors/destructors |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/flag.hxx> |
|
#include <cyg/infra/testcase.h> |
|
#include "testaux.hxx" |
|
static Cyg_Flag f0, f1; |
|
|
static bool flash( void ) |
{ |
Cyg_Flag f0; |
|
Cyg_Flag f1; |
|
return true; |
} |
|
void flag0_main( void ) |
{ |
CYG_TEST_INIT(); |
|
CHECK(flash()); |
CHECK(flash()); |
|
CYG_TEST_PASS_FINISH("Flag 0 OK"); |
|
} |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
flag0_main(); |
} |
// EOF flag0.cxx |
/flag1.cxx
0,0 → 1,219
//========================================================================== |
// |
// flag1.cxx |
// |
// Flag test 1 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author: dsm |
// Contributors: dsm |
// Date: 1998-05-11 |
// Description: Tests basic flag functionality. |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/thread.hxx> // Cyg_Thread |
#include <cyg/kernel/thread.inl> |
#include <cyg/kernel/sched.hxx> // Cyg_Scheduler::start() |
|
#include <cyg/kernel/flag.hxx> |
|
#include <cyg/infra/testcase.h> |
|
#include <cyg/kernel/sched.inl> |
|
|
#define NTHREADS 3 |
#include "testaux.hxx" |
|
static Cyg_Flag f0, f1; |
#ifdef CYGFUN_KERNEL_THREADS_TIMER |
static Cyg_Flag f2; |
#endif |
|
static volatile cyg_atomic q = 0; |
#define FIRST_THREAD_WAIT_TIME 5 |
#define SECOND_THREAD_WAIT_TIME 10 |
#define THIRD_THREAD_WAIT_TIME 20 |
|
static void entry0( CYG_ADDRWORD data ) |
{ |
CYG_TEST_INFO("Testing setbits() and maskbits()"); |
CYG_TEST_CHECK(0==f0.peek(), "flag not initialized properly"); |
f0.setbits(0x1); |
CYG_TEST_CHECK(1==f0.peek(), "setbits"); |
f0.setbits(0x3); |
CYG_TEST_CHECK(3==f0.peek(), "setbits"); |
f0.maskbits(~0x5); |
CYG_TEST_CHECK(2==f0.peek(), "maskbits"); |
f0.setbits(); |
CYG_TEST_CHECK(~0u==f0.peek(), "setbits no arg"); |
f0.maskbits(); |
CYG_TEST_CHECK(0==f0.peek(), "maskbits no arg"); |
CYG_TEST_CHECK(0==q++, "bad synchronization"); |
|
CYG_TEST_INFO("Testing wait()"); |
f1.setbits(0x4); |
CYG_TEST_CHECK(0x4==f1.peek(), "maskbits no arg"); |
CYG_TEST_CHECK(1==q++, "bad synchronization"); |
f1.setbits(0x18); // wake t1 |
f1.wait(0x11, Cyg_Flag::AND | Cyg_Flag::CLR); |
CYG_TEST_CHECK(0==f1.peek(), "flag value wrong"); |
CYG_TEST_CHECK(3==q++, "bad synchronization"); |
f0.setbits(0x2); // wake t1 |
f1.wait(0x10, Cyg_Flag::AND ); |
f0.setbits(0x1); // wake t1 |
|
f1.wait(0x11, Cyg_Flag::AND | Cyg_Flag::CLR); |
|
#ifdef CYGFUN_KERNEL_THREADS_TIMER |
f2.wait(0x2, Cyg_Flag::OR); |
CYG_TEST_CHECK(20==q,"bad synchronization"); |
f2.wait(0x10, Cyg_Flag::AND, |
Cyg_Clock::real_time_clock->current_value()+THIRD_THREAD_WAIT_TIME); |
CYG_TEST_CHECK(21==q++,"bad synchronization"); |
#endif |
f0.wait(1, Cyg_Flag::OR); |
|
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
static void entry1( CYG_ADDRWORD data ) |
{ |
f1.wait(0xc, Cyg_Flag::AND); |
CYG_TEST_CHECK(2==q++, "bad synchronization"); |
CYG_TEST_CHECK(0x1c==f1.peek(), "flag value wrong"); |
f1.setbits(0x1); // wake t0 |
f0.wait(0x3, Cyg_Flag::OR); |
CYG_TEST_CHECK(4==q++, "bad synchronization"); |
CYG_TEST_CHECK(2==f0.peek(), "flag value wrong"); |
|
f1.setbits(0xf0); // wake t0,t2 |
f0.wait(0x5, Cyg_Flag::AND | Cyg_Flag::CLR); // wait for t0 & t2 |
CYG_TEST_CHECK(0==f0.peek(), "flag value wrong"); |
CYG_TEST_CHECK(0xf0==f1.peek(), "flag value wrong"); |
CYG_TEST_CHECK(5==q++, "bad synchronization"); |
f1.maskbits(); |
CYG_TEST_CHECK(0==f1.peek(), "flag value wrong"); |
|
CYG_TEST_INFO("Testing poll()"); |
f0.setbits(0x55); |
CYG_TEST_CHECK(0x55==f0.peek(), "flag value wrong"); |
CYG_TEST_CHECK(0x55==f0.poll(0x3, Cyg_Flag::OR),"bad poll() return"); |
CYG_TEST_CHECK(0==f0.poll(0xf, Cyg_Flag::AND),"poll()"); |
CYG_TEST_CHECK(0==f0.poll(0xa, Cyg_Flag::OR),"poll()"); |
CYG_TEST_CHECK(0x55==f0.peek(), "flag value wrong"); |
CYG_TEST_CHECK(0x55==f0.poll(0xf, Cyg_Flag::OR | Cyg_Flag::CLR),"poll"); |
CYG_TEST_CHECK(0x0==f0.peek(), "flag value wrong"); |
f0.setbits(0x50); |
CYG_TEST_CHECK(0x50==f0.poll(0x10, Cyg_Flag::AND | Cyg_Flag::CLR),"poll"); |
CYG_TEST_CHECK(0x0==f0.peek(), "flag value wrong"); |
|
CYG_TEST_INFO("Testing waiting()"); |
f0.maskbits(); |
CYG_TEST_CHECK(!f0.waiting(), "waiting()"); |
|
#ifdef CYGFUN_KERNEL_THREADS_TIMER |
thread[1]->delay( 10 ); // allow other threads to reach wait on f1 |
CYG_TEST_CHECK(f1.waiting(), "waiting() not true"); |
f1.setbits(); // wake one of t0,t2 |
CYG_TEST_CHECK(f1.waiting(), "waiting() not true"); |
#else |
f1.setbits(0x11); // wake one of t0,t2 |
#endif |
f1.setbits(0x11); // wake other of t0,t2 |
CYG_TEST_CHECK(!f1.waiting(), "waiting not false"); |
|
#ifdef CYGFUN_KERNEL_THREADS_TIMER |
CYG_TEST_INFO("Testing wait() with timeout"); |
q=20; |
f2.setbits(0x2); // synchronize with t0,t2 |
CYG_TEST_CHECK(20==q,"bad synchronization"); |
f2.wait(0x20, Cyg_Flag::AND, |
Cyg_Clock::real_time_clock->current_value()+SECOND_THREAD_WAIT_TIME); |
CYG_TEST_CHECK(22==q++,"bad synchronization"); |
#endif |
|
CYG_TEST_PASS_FINISH("Flag 1 OK"); |
} |
|
static void entry2( CYG_ADDRWORD data ) |
{ |
f1.wait(0x60, Cyg_Flag::OR); |
f0.setbits(0x4); |
|
f1.wait(0x11, Cyg_Flag::AND | Cyg_Flag::CLR); |
#ifdef CYGFUN_KERNEL_THREADS_TIMER |
f2.wait(0x2, Cyg_Flag::OR); |
CYG_TEST_CHECK(20==q,"bad synchronization"); |
CYG_TEST_CHECK(0==f2.wait(0x40, Cyg_Flag::AND, |
Cyg_Clock::real_time_clock->current_value()+FIRST_THREAD_WAIT_TIME), |
"timed wait() wrong"); |
CYG_TEST_CHECK(20==q++,"bad synchronization"); |
// Now wake t0 before it times out |
f2.setbits(0x10); |
#endif |
f0.wait(1, Cyg_Flag::OR); |
|
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
void flag1_main( void ) |
{ |
CYG_TEST_INIT(); |
|
new_thread(entry0, 0); |
new_thread(entry1, 1); |
new_thread(entry2, 2); |
|
Cyg_Scheduler::start(); |
|
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
flag1_main(); |
} |
|
// EOF flag1.cxx |
/intr0.cxx
0,0 → 1,209
//================================================================= |
// |
// intr0.cxx |
// |
// Interrupt test 0 |
// |
//================================================================= |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//================================================================= |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm, jlarmour |
// Date: 1999-02-16 |
// Description: Very basic test of interrupt objects |
// Options: |
// CYGIMP_KERNEL_INTERRUPTS_DSRS_TABLE |
// CYGIMP_KERNEL_INTERRUPTS_DSRS_TABLE_SIZE |
// CYGIMP_KERNEL_INTERRUPTS_DSRS_LIST |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/intr.hxx> |
#include <cyg/hal/hal_intr.h> |
|
#include <cyg/infra/testcase.h> |
|
#include "testaux.hxx" |
|
static cyg_ISR isr0, isr1; |
static cyg_DSR dsr0, dsr1; |
|
static char intr0_obj[sizeof(Cyg_Interrupt)]; |
static char intr1_obj[sizeof(Cyg_Interrupt)]; |
|
static cyg_uint32 isr0(cyg_vector vector, CYG_ADDRWORD data) |
{ |
CYG_UNUSED_PARAM(CYG_ADDRWORD, data); |
|
Cyg_Interrupt::acknowledge_interrupt(vector); |
return 0; |
} |
|
static void dsr0(cyg_vector vector, cyg_ucount32 count, CYG_ADDRWORD data) |
{ |
CYG_UNUSED_PARAM(cyg_vector, vector); |
CYG_UNUSED_PARAM(cyg_ucount32, count); |
CYG_UNUSED_PARAM(CYG_ADDRWORD, data); |
} |
|
static cyg_uint32 isr1(cyg_vector vector, CYG_ADDRWORD data) |
{ |
CYG_UNUSED_PARAM(cyg_vector, vector); |
CYG_UNUSED_PARAM(CYG_ADDRWORD, data); |
return 0; |
} |
|
static void dsr1(cyg_vector vector, cyg_ucount32 count, CYG_ADDRWORD data) |
{ |
CYG_UNUSED_PARAM(cyg_vector, vector); |
CYG_UNUSED_PARAM(cyg_ucount32, count); |
CYG_UNUSED_PARAM(CYG_ADDRWORD, data); |
} |
|
static bool flash( void ) |
{ |
Cyg_Interrupt intr0 = Cyg_Interrupt(CYGNUM_HAL_ISR_MIN, 0, (CYG_ADDRWORD)333, isr0, dsr0 ); |
|
return true; |
} |
|
/* IMPORTANT: The calling convention for VSRs is target dependent. It is |
* unlikely that a plain C or C++ routine would function correctly on any |
* particular platform, even if it could correctly access the system |
* resources necessary to handle the event that caused it to be called. |
* VSRs usually must be written in assembly language. |
* |
* This is just a test program. The routine vsr0() below is defined simply |
* to define an address that will be in executable memory. If an event |
* causes this VSR to be called, all bets are off. If it is accidentally |
* installed in the vector for the realtime clock, the system will likely |
* freeze. |
*/ |
|
static cyg_VSR vsr0; |
|
static void vsr0() |
{ |
} |
|
void intr0_main( void ) |
{ |
CYG_TEST_INIT(); |
|
CHECK(flash()); |
CHECK(flash()); |
|
// Make sure the chosen levels are not already in use. |
int in_use; |
cyg_vector lvl1 = CYGNUM_HAL_ISR_MIN + (1 % CYGNUM_HAL_ISR_COUNT); |
HAL_INTERRUPT_IN_USE( lvl1, in_use ); |
Cyg_Interrupt* intr0 = NULL; |
if (!in_use) |
intr0 = new((void *)&intr0_obj[0]) Cyg_Interrupt( lvl1, 1, (CYG_ADDRWORD)777, isr0, dsr0 ); |
|
cyg_vector lvl2 = CYGNUM_HAL_ISR_MIN + ( 15 % CYGNUM_HAL_ISR_COUNT); |
HAL_INTERRUPT_IN_USE( lvl2, in_use ); |
Cyg_Interrupt* intr1 = NULL; |
if (!in_use && lvl1 != lvl2) |
intr1 = new((void *)&intr1_obj[0]) Cyg_Interrupt( lvl2, 1, 888, isr1, dsr1 ); |
|
// Check these functions at least exist |
Cyg_Interrupt::disable_interrupts(); |
Cyg_Interrupt::enable_interrupts(); |
|
if (intr0) |
intr0->attach(); |
if (intr1) |
intr1->attach(); |
if (intr0) |
intr0->detach(); |
if (intr1) |
intr1->detach(); |
|
// If this attaching interrupt replaces the previous interrupt |
// instead of adding to it we could be in a big mess if the |
// vector is being used by something important. |
|
cyg_vector v = (CYGNUM_HAL_VSR_MIN + 11) % CYGNUM_HAL_VSR_COUNT; |
cyg_VSR *old_vsr, *new_vsr; |
Cyg_Interrupt::set_vsr( v, vsr0, &old_vsr ); |
Cyg_Interrupt::get_vsr( v, &new_vsr ); |
CHECK( vsr0 == new_vsr ); |
|
new_vsr = NULL; |
Cyg_Interrupt::set_vsr( v, old_vsr, &new_vsr ); |
CHECK( new_vsr == vsr0 ); |
|
Cyg_Interrupt::set_vsr( v, new_vsr ); |
new_vsr = NULL; |
Cyg_Interrupt::get_vsr( v, &new_vsr ); |
CHECK( vsr0 == new_vsr ); |
|
Cyg_Interrupt::set_vsr( v, old_vsr ); |
CHECK( vsr0 == new_vsr ); |
new_vsr = NULL; |
Cyg_Interrupt::get_vsr( v, &new_vsr ); |
CHECK( old_vsr == new_vsr ); |
|
CHECK( NULL != vsr0 ); |
|
cyg_vector v1; |
#ifdef CYGPKG_HAL_MIPS_TX39 |
// This can be removed when PR 17831 is fixed |
if ( cyg_test_is_simulator ) |
v1 = 12 % CYGNUM_HAL_ISR_COUNT; |
else /* NOTE TRAILING ELSE... */ |
#endif |
v1 = CYGNUM_HAL_ISR_MIN + (6 % CYGNUM_HAL_ISR_COUNT); |
|
Cyg_Interrupt::mask_interrupt(v1); |
Cyg_Interrupt::unmask_interrupt(v1); |
|
Cyg_Interrupt::configure_interrupt(v1, true, true); |
|
CYG_TEST_PASS_FINISH("Intr 0 OK"); |
} |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
intr0_main(); |
} |
// EOF intr0.cxx |
/sync2.cxx
0,0 → 1,201
//========================================================================== |
// |
// sync2.cxx |
// |
// Sync test 2 -- test of different locking mechanisms |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-02-18 |
// Description: |
// Creates some threads and tests the various synchronization |
// mechanisms. Four threads are created t0..t3. t0 and t3 grab a |
// mutex and check they have exclusive access to shared variable. |
// t0,t1,t2 post each other in a loop with a semaphore so that |
// only one is running at any time. t1,t2,t3 do a similar thing |
// with counting semaphores, except that there are two active |
// threads. |
// Omissions: |
// Doesn't test condition variables |
// |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/thread.hxx> |
#include <cyg/kernel/thread.inl> |
#include <cyg/kernel/sched.hxx> |
#include <cyg/kernel/mutex.hxx> |
#include <cyg/kernel/sema.hxx> |
|
#include <cyg/infra/testcase.h> |
|
#include <cyg/kernel/sched.inl> |
|
#define NTHREADS 4 |
|
#include "testaux.hxx" |
|
static Cyg_Mutex m0; |
static Cyg_Binary_Semaphore s0, s1, s2(1); |
static Cyg_Counting_Semaphore cs0, cs1, cs2, cs3; |
|
static const cyg_ucount16 n = 1000; |
static cyg_ucount8 m0d=99, sd=2, cd0=99, cd1=99; |
|
static void entry0( CYG_ADDRWORD data ) |
{ |
for(cyg_ucount16 i=0; i<n; i++) { |
s2.wait(); |
CHECK( 2 == sd ); |
sd = 0; |
m0.lock(); { |
m0d = 0; |
s0.post(); |
CHECK( 0 == m0d ); |
} m0.unlock(); |
} |
// wait for 3 explicit posts to indicate threads have stopped. |
for(cyg_ucount8 i=0; i<3; i++) |
cs3.wait(); |
|
CHECK( ! s0.posted() ); |
CHECK( ! s1.posted() ); |
CHECK( s2.posted() ); |
|
CHECK( 0 == cs0.peek() ); |
CHECK( 0 == cs1.peek() ); |
CHECK( 0 == cs2.peek() ); |
CHECK( 0 == cs3.peek() ); |
|
CHECK( 0 == cd0 ); |
CHECK( 0 == cd1 ); |
CYG_TEST_PASS_FINISH("Sync 2 OK"); |
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
static void entry1( CYG_ADDRWORD data ) |
{ |
for(cyg_ucount16 i=0; i<n; i++) { |
s0.wait(); |
CHECK( 0 == sd ); |
sd = 1; |
cd0 = 1; |
cs1.post(); |
cd1 = 1; |
cs1.post(); |
s1.post(); |
cs0.wait(); |
CHECK( 0 == cd0 ); |
cs0.wait(); |
CHECK( 0 == cd1 ); |
} |
cs3.post(); |
s0.wait(); |
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
static void entry2( CYG_ADDRWORD data ) |
{ |
for(cyg_ucount16 i=0; i<n; i++) { |
s1.wait(); |
CHECK( 1 == sd ); |
sd = 2; |
cs1.wait(); |
CHECK( 1 == cd0 ); |
cd0 = 2; |
cs2.post(); |
s2.post(); |
cs1.wait(); |
CHECK( 1 == cd1 ); |
cd1 = 2; |
cs2.post(); |
} |
cs3.post(); |
s1.wait(); |
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
static void entry3( CYG_ADDRWORD data ) |
{ |
for(cyg_ucount16 i=0; i < n*2; i++) { |
cs2.wait(); |
CHECK( 2 == cd0 || 2 == cd1 ); |
m0.lock(); { |
m0d = 3; |
if( 2 == cd0 ) |
cd0 = 0; |
else { |
CHECK( 2 == cd1 ); |
cd1 = 0; |
} |
cs0.post(); |
CHECK( 3 == m0d ); |
} m0.unlock(); |
} |
cs3.post(); |
cs1.wait(); |
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
|
void sync2_main(void) |
{ |
CYG_TEST_INIT(); |
|
new_thread(entry0, 0); |
new_thread(entry1, 1); |
new_thread(entry2, 2); |
new_thread(entry3, 3); |
|
Cyg_Scheduler::start(); |
|
CYG_TEST_PASS_FINISH("Not reached"); |
} |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
sync2_main(); |
} |
|
// EOF sync2.cxx |
/timeslice.c
0,0 → 1,281
//========================================================================== |
// |
// timeslice.c |
// |
// Timeslice test |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): nickg |
// Contributors: nickg |
// Date: 2001-06-18 |
// Description: A basic timeslicing test. |
// |
//####DESCRIPTIONEND#### |
//========================================================================== |
|
#include <pkgconf/kernel.h> |
#include <pkgconf/hal.h> |
|
#include <cyg/hal/hal_arch.h> |
|
#include <cyg/kernel/smp.hxx> |
|
#include <cyg/kernel/kapi.h> |
|
#include <cyg/infra/testcase.h> |
#include <cyg/infra/diag.h> |
|
//========================================================================== |
|
#if defined(CYGSEM_KERNEL_SCHED_TIMESLICE) && \ |
defined(CYGFUN_KERNEL_API_C) && \ |
defined(CYGSEM_KERNEL_SCHED_MLQUEUE) && \ |
defined(CYGVAR_KERNEL_COUNTERS_CLOCK) && \ |
!defined(CYGDBG_INFRA_DIAG_USE_DEVICE) && \ |
(CYGNUM_KERNEL_SCHED_PRIORITIES > 12) |
|
//========================================================================== |
|
#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL*5 |
|
#define NTHREADS_MAX (CYGNUM_KERNEL_CPU_MAX*6) |
|
static int ncpus = CYGNUM_KERNEL_CPU_MAX; |
|
static char test_stack[STACK_SIZE]; |
static cyg_thread test_thread; |
static cyg_handle_t main_thread; |
|
static char stacks[NTHREADS_MAX][STACK_SIZE]; |
static cyg_thread test_threads[NTHREADS_MAX]; |
static cyg_handle_t threads[NTHREADS_MAX]; |
|
static volatile int failed = false; |
|
static volatile cyg_uint32 slicerun[NTHREADS_MAX][CYGNUM_KERNEL_CPU_MAX]; |
|
//========================================================================== |
|
void |
test_thread_timeslice(CYG_ADDRESS id) |
{ |
for(;;) |
slicerun[id][CYG_KERNEL_CPU_THIS()]++; |
} |
|
//========================================================================== |
|
void run_test_timeslice(int nthread) |
{ |
int i,j; |
cyg_uint32 cpu_total[CYGNUM_KERNEL_CPU_MAX]; |
cyg_uint32 cpu_threads[CYGNUM_KERNEL_CPU_MAX]; |
cyg_uint32 thread_total[NTHREADS_MAX]; |
|
CYG_TEST_INFO( "Timeslice Test: Check timeslicing works"); |
|
// Init flags. |
for (i = 0; i < nthread; i++) |
for( j = 0; j < ncpus; j++ ) |
slicerun[i][j] = 0; |
|
// Set my priority higher than any I plan to create |
cyg_thread_set_priority(cyg_thread_self(), 2); |
|
for (i = 0; i < nthread; i++) { |
cyg_thread_create(10, // Priority - just a number |
test_thread_timeslice, // entry |
i, // index |
"test_thread", // Name |
&stacks[i][0], // Stack |
STACK_SIZE, // Size |
&threads[i], // Handle |
&test_threads[i] // Thread data structure |
); |
cyg_thread_resume( threads[i]); |
} |
|
// Just wait a while, until the threads have all run for a bit. |
cyg_thread_delay( CYGNUM_KERNEL_SCHED_TIMESLICE_TICKS*100 ); |
|
// Suspend all the threads |
for (i = 0; i < nthread; i++) { |
cyg_thread_suspend(threads[i]); |
} |
|
|
// And check that a thread ran on each CPU, and that each thread |
// ran. |
|
|
diag_printf(" Thread "); |
for( j = 0; j < ncpus; j++ ) |
{ |
cpu_total[j] = 0; |
cpu_threads[j] = 0; |
// " %11d" __123456789ab" |
diag_printf(" CPU %2d",j); |
} |
// " %11d" __123456789ab" |
diag_printf(" Total\n"); |
for (i = 0; i < nthread; i++) |
{ |
thread_total[i] = 0; |
diag_printf(" %2d ",i); |
for( j = 0; j < ncpus; j++ ) |
{ |
thread_total[i] += slicerun[i][j]; |
cpu_total[j] += slicerun[i][j]; |
if( slicerun[i][j] > 0 ) |
cpu_threads[j]++; |
diag_printf(" %11d",slicerun[i][j]); |
} |
diag_printf(" %11d\n",thread_total[i]); |
if( thread_total[i] == 0 ) |
failed++; |
} |
|
diag_printf(" Total "); |
for( j = 0; j < ncpus; j++ ) |
diag_printf(" %11d",cpu_total[j]); |
diag_printf("\n"); |
diag_printf("Threads "); |
for( j = 0; j < ncpus; j++ ) |
{ |
diag_printf(" %11d",cpu_threads[j]); |
if( cpu_threads[j] < 2 ) |
failed++; |
} |
diag_printf("\n"); |
|
// Delete all the threads |
for (i = 0; i < nthread; i++) { |
cyg_thread_delete(threads[i]); |
} |
|
CYG_TEST_INFO( "Timeslice Test: done"); |
} |
|
|
//========================================================================== |
|
void |
run_tests(CYG_ADDRESS id) |
{ |
int step; |
int nthread; |
|
// Try to run about 10 times in total, with varying numbers of threads |
// from only one extra up to the full set: |
|
step = (NTHREADS_MAX - (1 + CYG_KERNEL_CPU_COUNT()))/10; |
if( step == 0 ) step = 1; |
|
for( nthread = 1 + CYG_KERNEL_CPU_COUNT() ; |
nthread <= NTHREADS_MAX ; |
nthread += step ) |
run_test_timeslice(nthread); |
|
if( failed ) |
CYG_TEST_FAIL_FINISH("Timeslice test failed\n"); |
|
CYG_TEST_PASS_FINISH("Timeslice test OK"); |
} |
|
//========================================================================== |
|
void timeslice_main( void ) |
{ |
CYG_TEST_INIT(); |
|
// Work out how many CPUs we actually have. |
ncpus = CYG_KERNEL_CPU_COUNT(); |
|
cyg_thread_create(0, // Priority - just a number |
run_tests, // entry |
0, // index |
"run_tests", // Name |
test_stack, // Stack |
STACK_SIZE, // Size |
&main_thread, // Handle |
&test_thread // Thread data structure |
); |
cyg_thread_resume( main_thread); |
|
cyg_scheduler_start(); |
} |
|
//========================================================================== |
|
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
externC void |
cyg_hal_invoke_constructors(); |
#endif |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
timeslice_main(); |
} |
|
//========================================================================== |
|
#else // CYGSEM_KERNEL_SCHED_TIMESLICE etc |
|
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA("SMP test requires:\n" |
"CYGSEM_KERNEL_SCHED_TIMESLICE &&\n" |
"CYGPKG_KERNEL_SMP_SUPPORT &&\n" |
"CYGFUN_KERNEL_API_C && \n" |
"CYGSEM_KERNEL_SCHED_MLQUEUE &&\n" |
"CYGVAR_KERNEL_COUNTERS_CLOCK &&\n" |
"!CYGPKG_HAL_I386_LINUX &&\n" |
"!CYGDBG_INFRA_DIAG_USE_DEVICE &&\n" |
"(CYGNUM_KERNEL_SCHED_PRIORITIES > 12)\n"); |
} |
|
#endif // CYGSEM_KERNEL_SCHED_TIMESLICE etc. |
|
//========================================================================== |
// EOF timeslice.c |
/smp.cxx
0,0 → 1,473
//========================================================================== |
// |
// smp.cxx |
// |
// SMP tests |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): nickg |
// Contributors: nickg |
// Date: 2001-06-18 |
// Description: Some basic SMP tests. |
// |
//####DESCRIPTIONEND#### |
//========================================================================== |
|
#include <pkgconf/kernel.h> |
#include <pkgconf/hal.h> |
|
#if 1 |
#include <cyg/kernel/sched.hxx> |
#include <cyg/kernel/thread.hxx> |
#include <cyg/kernel/thread.inl> |
#include <cyg/kernel/mutex.hxx> |
#include <cyg/kernel/sema.hxx> |
#include <cyg/kernel/sched.inl> |
#include <cyg/kernel/clock.hxx> |
#include <cyg/kernel/clock.inl> |
#endif |
|
#include <cyg/kernel/kapi.h> |
|
#include <cyg/infra/testcase.h> |
#include <cyg/infra/diag.h> |
|
//========================================================================== |
|
#if defined(CYGPKG_KERNEL_SMP_SUPPORT) && \ |
defined(CYGFUN_KERNEL_API_C) && \ |
defined(CYGSEM_KERNEL_SCHED_MLQUEUE) && \ |
defined(CYGVAR_KERNEL_COUNTERS_CLOCK) && \ |
!defined(CYGPKG_HAL_I386_LINUX) && \ |
!defined(CYGDBG_INFRA_DIAG_USE_DEVICE) && \ |
(CYGNUM_KERNEL_SCHED_PRIORITIES > 12) |
|
//========================================================================== |
|
#define NTHREADS 1 |
#include "testaux.hxx" |
|
#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
#define NTHREADS_MAX (CYGNUM_KERNEL_CPU_MAX*3) |
|
static int ncpus = CYGNUM_KERNEL_CPU_MAX; |
static int nthread = NTHREADS_MAX; |
|
static char stacks[NTHREADS_MAX][STACK_SIZE]; |
static cyg_thread test_threads[NTHREADS_MAX]; |
static cyg_handle_t threads[NTHREADS_MAX]; |
|
static volatile cyg_uint32 cpu_run[CYGNUM_KERNEL_CPU_MAX]; |
static volatile int failed = false; |
static volatile cyg_uint32 cpu_thread[CYGNUM_KERNEL_CPU_MAX]; |
|
static volatile cyg_uint32 slicerun[NTHREADS_MAX][CYGNUM_KERNEL_CPU_MAX]; |
|
|
static cyg_mutex_t mx; |
|
|
//========================================================================== |
// Compute a name for a thread |
char * |
thread_name(char *basename, int indx) { |
return "<<NULL>>"; // Not currently used |
} |
|
//========================================================================== |
|
void |
test_thread_cpu(CYG_ADDRESS id) |
{ |
for(;;) |
cpu_run[CYG_KERNEL_CPU_THIS()] = true; |
} |
|
//========================================================================== |
// First test: just run as many threads as CPUs and check that we |
// get to run on each CPU. |
|
void run_smp_test_cpus() |
{ |
int i; |
|
CYG_TEST_INFO( "CPU Test: Check CPUs functional"); |
|
// Init flags. |
for (i = 0; i < ncpus; i++) |
cpu_run[i] = false; |
|
// Set my priority higher than any I plan to create |
cyg_thread_set_priority(cyg_thread_self(), 2); |
|
for (i = 0; i < ncpus; i++) { |
cyg_thread_create(10, // Priority - just a number |
test_thread_cpu, // entry |
i, // index |
thread_name("thread", i), // Name |
&stacks[i][0], // Stack |
STACK_SIZE, // Size |
&threads[i], // Handle |
&test_threads[i] // Thread data structure |
); |
cyg_thread_resume( threads[i]); |
} |
|
// Just wait a while, until the threads have all run for a bit. |
cyg_thread_delay( 10 ); |
|
// Delete all the threads |
for (i = 0; i < ncpus; i++) { |
cyg_thread_delete(threads[i]); |
} |
|
// And check that a thread ran on each CPU |
for (i = 0; i < ncpus; i++) { |
// CYG_TEST_CHECK( cpu_run[i], "CPU didn't run"); |
if( !cpu_run[i] ) |
{ |
CYG_TEST_INFO( "CPU didn't run" ); |
failed++; |
} |
} |
|
CYG_TEST_INFO( "CPU Test: done"); |
} |
|
|
//========================================================================== |
|
void |
test_thread_pri(CYG_ADDRESS id) |
{ |
for(;;) |
{ |
cpu_thread[CYG_KERNEL_CPU_THIS()] = id; |
} |
} |
|
//========================================================================== |
// Second test: Run a thread on each CPU and then by manipulating the |
// priorities, get the current thread to migrate to each CPU in turn. |
|
|
void run_smp_test_pri() |
{ |
int i; |
|
CYG_TEST_INFO( "Pri Test: Check set_priority functionality"); |
|
// Init flags. |
for (i = 0; i < ncpus; i++) |
cpu_run[i] = false; |
|
// Set my priority higher than any I plan to creat |
cyg_thread_set_priority(cyg_thread_self(), 2); |
|
for (i = 0; i < ncpus; i++) { |
cyg_thread_create(10, // Priority - just a number |
test_thread_pri, // entry |
i, // index |
thread_name("thread", i), // Name |
&stacks[i][0], // Stack |
STACK_SIZE, // Size |
&threads[i], // Handle |
&test_threads[i] // Thread data structure |
); |
cyg_thread_resume( threads[i]); |
} |
|
cyg_thread_delay( 2 ); |
|
cyg_handle_t cthread = threads[0]; |
cyg_thread_set_priority(cthread, 25); |
|
// Just wait a while, until the threads have all run for a bit. |
cyg_thread_delay( 2 ); |
|
for (i = 0; i < ncpus*500; i++) |
{ |
HAL_SMP_CPU_TYPE cpu = i % CYG_KERNEL_CPU_COUNT(); |
|
if( cpu != CYG_KERNEL_CPU_THIS() ) |
{ |
// At this point we have the current thread running on a |
// CPU at priority 2, ncpus-1 threads running at priority |
// 10 and the last thread (cthread) in the run queue at |
// priority 25. |
|
// Pick a thread on a different CPU |
cyg_handle_t dthread; |
|
do |
{ |
dthread = threads[cpu_thread[cpu]]; |
} while( dthread == cthread ); |
|
// Change the priority of the victim thread to 20. It is |
// still higher priority than cthread so it will continue |
// running. |
|
cyg_thread_set_priority(dthread, 20); |
|
// Now change our priority to 15. We are still higher |
// priority that cthread so we will still run. |
|
cyg_thread_set_priority(cyg_thread_self(), 15); |
|
// Finally change the priority of cthread to 10. This will |
// cause it to preempt us on the current CPU. In turn we |
// will preempt dthread on its CPU. |
|
// NOTE: This relies somewhat on the SMP scheduler doing |
// what we expect here. Specifically, that it will preempt |
// the current thread with cthread locally. A more |
// sophisticated scheduler might decide that the most |
// efficient thing to do is to preempt dthread with |
// cthread remotely, leaving the current thread where it |
// is. If we ever bother to implement this, then this test |
// will need to change. |
|
cyg_thread_set_priority(cthread, 10); |
|
// Spin here a while until the scheduler sorts itself out. |
|
for( int j = 0; j < 100000; j++ ); |
|
// Indicate that we have run on this CPU |
cpu_run[CYG_KERNEL_CPU_THIS()]++; |
|
// Restore our priority to 2 and depress dthread to 25 and |
// make it the new cthread. |
|
cyg_thread_set_priority(cyg_thread_self(), 2); |
cyg_thread_set_priority(dthread, 25); |
cthread = dthread; |
} |
} |
|
|
// Delete all the threads |
for (i = 0; i < ncpus; i++) { |
cyg_thread_delete(threads[i]); |
} |
|
// And check that a thread ran on each CPU |
for (i = 0; i < ncpus; i++) { |
// CYG_TEST_CHECK( cpu_run[i], "CPU didn't run"); |
if( !cpu_run[i] ) |
{ |
CYG_TEST_INFO( "CPU didn't run" ); |
failed++; |
} |
} |
|
CYG_TEST_INFO( "PRI Test: done"); |
} |
|
//========================================================================== |
|
void |
test_thread_timeslice(CYG_ADDRESS id) |
{ |
for(;;) |
slicerun[id][CYG_KERNEL_CPU_THIS()]++; |
} |
|
//========================================================================== |
// First test: just run as many threads as CPUs and check that we |
// get to run on each CPU. |
|
void run_smp_test_timeslice() |
{ |
int i; |
|
CYG_TEST_INFO( "Timeslice Test: Check timeslicing works"); |
|
// Init flags. |
for (i = 0; i < nthread; i++) |
for( int j = 0; j < ncpus; j++ ) |
slicerun[i][j] = 0; |
|
// Set my priority higher than any I plan to create |
cyg_thread_set_priority(cyg_thread_self(), 2); |
|
for (i = 0; i < nthread; i++) { |
cyg_thread_create(10, // Priority - just a number |
test_thread_timeslice, // entry |
i, // index |
thread_name("thread", i), // Name |
&stacks[i][0], // Stack |
STACK_SIZE, // Size |
&threads[i], // Handle |
&test_threads[i] // Thread data structure |
); |
cyg_thread_resume( threads[i]); |
} |
|
// Just wait a while, until the threads have all run for a bit. |
cyg_thread_delay( 200 ); |
|
// Delete all the threads |
for (i = 0; i < nthread; i++) { |
cyg_thread_suspend(threads[i]); |
} |
|
|
// And check that a thread ran on each CPU |
|
cyg_uint32 cpu_total[ncpus]; |
cyg_uint32 cpu_threads[ncpus]; |
cyg_uint32 thread_total[nthread]; |
|
diag_printf(" Thread "); |
for( int j = 0; j < ncpus; j++ ) |
{ |
cpu_total[j] = 0; |
cpu_threads[j] = 0; |
diag_printf(" CPU %2d",j); |
} |
diag_printf(" Total\n"); |
for (i = 0; i < nthread; i++) |
{ |
thread_total[i] = 0; |
diag_printf(" %2d ",i); |
for( int j = 0; j < ncpus; j++ ) |
{ |
thread_total[i] += slicerun[i][j]; |
cpu_total[j] += slicerun[i][j]; |
if( slicerun[i][j] > 0 ) |
cpu_threads[j]++; |
diag_printf(" %8d",slicerun[i][j]); |
} |
diag_printf("%8d\n",thread_total[i]); |
} |
diag_printf(" Total "); |
for( int j = 0; j < ncpus; j++ ) |
diag_printf(" %8d",cpu_total[j]); |
diag_printf("\n"); |
diag_printf("Threads "); |
for( int j = 0; j < ncpus; j++ ) |
{ |
diag_printf(" %8d",cpu_threads[j]); |
if( cpu_threads[j] < 2 ) |
failed++; |
} |
diag_printf("\n"); |
|
// Delete all the threads |
for (i = 0; i < nthread; i++) { |
cyg_thread_delete(threads[i]); |
} |
|
CYG_TEST_INFO( "Timeslice Test: done"); |
} |
|
|
//========================================================================== |
|
void |
run_smp_tests(CYG_ADDRESS id) |
{ |
cyg_mutex_init( &mx ); |
|
for( int i = 0; i < 100; i++ ) |
{ |
run_smp_test_cpus(); |
run_smp_test_pri(); |
run_smp_test_timeslice(); |
} |
|
if( failed ) |
CYG_TEST_FAIL_FINISH("SMP tests failed\n"); |
|
CYG_TEST_PASS_FINISH("SMP tests OK"); |
} |
|
//========================================================================== |
|
void smp_main( void ) |
{ |
CYG_TEST_INIT(); |
|
// Work out how many CPUs we actually have. |
ncpus = CYG_KERNEL_CPU_COUNT(); |
|
new_thread(run_smp_tests, 0); |
|
cyg_scheduler_start(); |
} |
|
//========================================================================== |
|
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
externC void |
cyg_hal_invoke_constructors(); |
#endif |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
smp_main(); |
} |
|
//========================================================================== |
|
#else // CYGPKG_KERNEL_SMP_SUPPORT etc. |
|
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA("SMP test requires:\n" |
"CYGPKG_KERNEL_SMP_SUPPORT &&\n" |
"CYGFUN_KERNEL_API_C && \n" |
"CYGSEM_KERNEL_SCHED_MLQUEUE &&\n" |
"CYGVAR_KERNEL_COUNTERS_CLOCK &&\n" |
"!CYGPKG_HAL_I386_LINUX &&\n" |
"!CYGDBG_INFRA_DIAG_USE_DEVICE &&\n" |
"(CYGNUM_KERNEL_SCHED_PRIORITIES > 12)\n"); |
} |
#endif // CYGPKG_KERNEL_SMP_SUPPORT etc. |
|
//========================================================================== |
// EOF tm_basic.cxx |
/ksem0.c
0,0 → 1,100
/*================================================================= |
// |
// ksem0.c |
// |
// Kernel C API Semaphore test 0 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-03-20 |
// Description: Limited to checking initialisation/destruction |
//####DESCRIPTIONEND#### |
*/ |
|
#include <cyg/kernel/kapi.h> |
|
#include <cyg/infra/testcase.h> |
|
#ifdef CYGFUN_KERNEL_API_C |
|
#include "testaux.h" |
|
cyg_sem_t s0, s1, s2; |
|
static bool flash( void ) |
{ |
cyg_semaphore_init( &s0, 0 ); |
cyg_semaphore_init( &s1, 1 ); |
cyg_semaphore_init( &s2, 17 ); |
|
cyg_semaphore_destroy( &s0 ); |
cyg_semaphore_destroy( &s1 ); |
cyg_semaphore_destroy( &s2 ); |
|
return true; |
} |
|
void ksem0_main( void ) |
{ |
CYG_TEST_INIT(); |
|
CHECK(flash()); |
CHECK(flash()); |
|
CYG_TEST_PASS_FINISH("Kernel C API Semaphore 0 OK"); |
|
} |
|
externC void |
cyg_start( void ) |
{ |
ksem0_main(); |
} |
|
|
#else /* def CYGFUN_KERNEL_API_C */ |
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA("Kernel C API layer disabled"); |
} |
#endif /* def CYGFUN_KERNEL_API_C */ |
|
/* EOF ksem0.c */ |
/sync3.cxx
0,0 → 1,231
//========================================================================== |
// |
// sync3.cxx |
// |
// Sync test 3 -- tests priorities and priority inheritance |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-02-18 |
// Description: |
// Creates mutexes and threads to set up starvation condition. |
// Checks simple priority inheritance cures this. |
// |
// The starvation condition is caused by the highest priority |
// thread, t0 waiting on a mutex which is never released because |
// it is held by t2. t2 never releases it because t1 will be |
// running at a priority level higher than t2 (but lower than t0). |
// |
// With priority inheritance enabled, t2 will inherit its priority |
// from t0 when t0 tries to grab the mutex. |
// |
// Options: |
// CYGIMP_THREAD_PRIORITY |
// CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT |
// CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_SIMPLE |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/thread.hxx> |
#include <cyg/kernel/thread.inl> |
#include <cyg/kernel/sched.hxx> |
#include <cyg/kernel/mutex.hxx> |
#include <cyg/kernel/sema.hxx> |
|
#include <cyg/infra/testcase.h> |
|
#include <cyg/kernel/sched.inl> |
|
#if defined(CYGIMP_THREAD_PRIORITY) && \ |
!defined(CYGPKG_KERNEL_SMP_SUPPORT) |
|
// ------------------------------------------------------------------------ |
// Manufacture a simpler feature test macro for priority inheritance than |
// the configuration gives us. We have priority inheritance if it is configured |
// as the only protocol, or if it is the default protocol for dynamic protocol |
// choice. |
// FIXME: If we have dynamic protocol choice, we can also set priority inheritance |
// as the protocol to be used on the mutexes we are interested in. At present we |
// do not do this. |
|
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT |
# ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC |
# ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_INHERIT |
# define PRIORITY_INHERITANCE |
# else |
# undef PRIORITY_INHERITANCE |
# endif |
# else |
# define PRIORITY_INHERITANCE |
# endif |
#else |
# undef PRIORITY_INHERITANCE |
#endif |
|
// ------------------------------------------------------------------------ |
|
#define NTHREADS 3 |
|
#include "testaux.hxx" |
|
static Cyg_Mutex m0; |
static Cyg_Binary_Semaphore s0, s1, s2; |
|
static cyg_ucount8 m0d = 9; |
|
static void check_priorities_normal() |
{ |
CHECK( 5 == thread[0]->get_priority()); |
CHECK( 6 == thread[1]->get_priority()); |
CHECK( 7 == thread[2]->get_priority()); |
} |
|
static void check_priorities_inherited() |
{ |
CHECK( 5 == thread[0]->get_priority()); |
CHECK( 6 == thread[1]->get_priority()); |
#ifdef PRIORITY_INHERITANCE |
CHECK( 5 == thread[2]->get_current_priority()); |
#endif |
CHECK( 7 == thread[2]->get_priority()); |
|
} |
|
static void entry0( CYG_ADDRWORD data ) |
{ |
s0.wait(); // wait until t2 has gained m0.lock |
check_priorities_normal(); |
m0.lock(); { |
check_priorities_normal(); |
CHECK( 2 == m0d ); |
m0d = 0; |
} m0.unlock(); |
check_priorities_normal(); |
#ifdef PRIORITY_INHERITANCE |
CYG_TEST_PASS_FINISH("Sync 3 OK -- priority inheritance worked"); |
#else |
CYG_TEST_FAIL_FINISH("Sync 3: thread not starved"); |
#endif |
// NOT REACHED |
} |
|
static void entry1( CYG_ADDRWORD data ) |
{ |
s1.wait(); |
// The delay below will allow testing of the priority inheritance |
// mechanism when scheduler does not guarantee to schedule threads |
// in strict priority order. |
for ( volatile cyg_ucount32 i=0; i < 100000; i++ ) |
; // math is hard |
|
#ifdef PRIORITY_INHERITANCE |
// thread0 should have stopped by this point |
CYG_TEST_FAIL_FINISH("Sync 3: priority inheritance mechanism failed"); |
#else |
// With strict priority scheduling and no priority inheritance |
// this is expected to happen. |
CYG_TEST_PASS_FINISH("Sync 3 OK"); |
#endif |
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
void entry2( CYG_ADDRWORD data ) |
{ |
m0.lock(); { |
CHECK( 9 == m0d ); |
check_priorities_normal(); |
s0.post(); // Now I have lock on m0, wake t0 then t1 |
check_priorities_inherited(); |
s1.post(); |
check_priorities_inherited(); |
m0d = 2; |
} m0.unlock(); |
check_priorities_normal(); |
m0.lock(); { |
check_priorities_normal(); |
CHECK( 0 == m0d ); |
m0d = 21; |
s2.wait(); // never posted |
} m0.unlock(); |
} |
|
|
|
void sync3_main(void) |
{ |
CYG_TEST_INIT(); |
|
new_thread( entry0, 0); |
new_thread( entry1, 1); |
new_thread( entry2, 2); |
|
thread[0]->set_priority(5); |
thread[1]->set_priority(6); |
thread[2]->set_priority(7); |
|
Cyg_Scheduler::start(); |
|
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
sync3_main(); |
} |
|
#else // defined(CYGIMP_THREAD_PRIORITY) etc |
|
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_PASS_FINISH("Sync3 test requires:\n" |
"defined(CYGIMP_THREAD_PRIORITY) &&\n" |
"!defined(CYGPKG_KERNEL_SMP_SUPPORT)\n"); |
|
} |
|
#endif // defined(CYGIMP_THREAD_PRIORITY) etc |
|
// EOF sync3.cxx |
/ksem1.c
0,0 → 1,169
/*================================================================= |
// |
// ksem1.c |
// |
// C API semaphore test 1 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-03-20 |
// Description: Tests basic semaphore functionality. |
//####DESCRIPTIONEND#### |
*/ |
|
#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
#include <cyg/kernel/kapi.h> |
|
#include <cyg/infra/testcase.h> |
|
#ifdef CYGFUN_KERNEL_API_C |
|
#include "testaux.h" |
|
#define NTHREADS 2 |
#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
static cyg_handle_t thread[NTHREADS]; |
|
static cyg_thread thread_obj[NTHREADS]; |
static char stack[NTHREADS][STACKSIZE]; |
|
|
static cyg_sem_t s0, s1, s2; |
|
static volatile cyg_ucount8 q = 0; |
|
static void entry0( cyg_addrword_t data ) |
{ |
cyg_ucount32 val; |
|
cyg_semaphore_wait(&s0); |
CHECK( 1 == q++ ); |
cyg_semaphore_post(&s1); |
cyg_semaphore_wait(&s0); |
CHECK( 3 == q++ ); |
cyg_semaphore_peek(&s0, &val); |
CHECK( 0 == val); |
CHECK( ! cyg_semaphore_trywait(&s0) ); |
cyg_semaphore_post(&s0); |
CHECK( 4 == q++ ); |
cyg_semaphore_peek(&s0, &val); |
CHECK( 1 == val); |
cyg_semaphore_post(&s0); |
cyg_semaphore_peek(&s0, &val); |
CHECK( 2 == val); |
cyg_semaphore_post(&s1); |
cyg_semaphore_peek(&s2, &val); |
CHECK( 0 == val); |
cyg_semaphore_wait(&s2); |
CHECK( 6 == q++ ); |
CYG_TEST_PASS_FINISH("Kernel C API Semaphore 1 OK"); |
} |
|
static void entry1( cyg_addrword_t data ) |
{ |
cyg_count32 val; |
|
cyg_semaphore_peek(&s1, &val); |
CHECK( 2 == val); |
cyg_semaphore_wait(&s1); |
cyg_semaphore_peek(&s1, &val); |
CHECK( 1 == val); |
cyg_semaphore_wait(&s1); |
CHECK( 0 == q++ ); |
cyg_semaphore_peek(&s0, &val); |
CHECK( 0 == val); |
cyg_semaphore_post(&s0); |
cyg_semaphore_wait(&s1); |
CHECK( 2 == q++ ); |
cyg_semaphore_post(&s0); |
cyg_semaphore_wait(&s1); |
CHECK( 5 == q++ ); |
cyg_semaphore_peek(&s0, &val); |
CHECK( 2 == val); |
CHECK( cyg_semaphore_trywait(&s0) ); |
cyg_semaphore_peek(&s0, &val); |
CHECK( 1 == val); |
CHECK( cyg_semaphore_trywait(&s0) ); |
cyg_semaphore_peek(&s0, &val); |
CHECK( 0 == val); |
cyg_semaphore_post(&s2); |
cyg_semaphore_wait(&s0); |
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
void ksem1_main( void ) |
{ |
CYG_TEST_INIT(); |
|
cyg_semaphore_init( &s0, 0); |
cyg_semaphore_init( &s1, 2); |
cyg_semaphore_init( &s2, 0); |
|
cyg_thread_create(4, entry0 , (cyg_addrword_t)0, "ksem1-0", |
(void *)stack[0], STACKSIZE,&thread[0], &thread_obj[0]); |
cyg_thread_resume(thread[0]); |
|
cyg_thread_create(4, entry1 , (cyg_addrword_t)1, "ksem1-1", |
(void *)stack[1], STACKSIZE, &thread[1], &thread_obj[1]); |
cyg_thread_resume(thread[1]); |
|
cyg_scheduler_start(); |
|
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
externC void |
cyg_start( void ) |
{ |
ksem1_main(); |
} |
|
|
#else /* def CYGFUN_KERNEL_API_C */ |
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA("Kernel C API layer disabled"); |
} |
#endif /* def CYGFUN_KERNEL_API_C */ |
|
/* EOF ksem1.c */ |
/clockcnv.cxx
0,0 → 1,287
//========================================================================== |
// |
// clockcnv.cxx |
// |
// Clock Converter test |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. |
// Copyright (C) 2003 Gary Thomas |
// |
// 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): hmt |
// Contributors: hmt |
// Date: 2000-01-24 |
// Description: Tests the Kernel Real Time Clock Converter subsystem |
// |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/clock.hxx> |
#include <cyg/kernel/thread.hxx> |
|
#include <cyg/infra/testcase.h> |
|
#include <cyg/kernel/clock.inl> |
#include <cyg/kernel/thread.inl> |
|
#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK |
|
#include <cyg/infra/diag.h> |
|
static void null_printf(const char *, ...) |
{ /* nothing */ } |
|
#define PRINTF0 diag_printf |
#define nPRINTF0 null_printf |
|
#define nPRINTF1 diag_printf |
#define PRINTF1 null_printf |
|
#define nPRINTF2 diag_printf |
#define PRINTF2 null_printf |
|
|
#define NTHREADS 1 |
#include "testaux.hxx" |
|
static struct { cyg_uint32 ns; double scale; } ns_tickers[] = { |
{ 70000000, 7.0 }, // 7cS |
{ 50000000, 5.0 }, // 5cS |
{ 45000000, 4.5 }, // 4.5cS |
{ 30000000, 3.0 }, // 3cS |
{ 20000000, 2.0 }, // 2cS |
{ 10000000, 1.0 }, // 1cS - no change |
{ 5000000, 0.5 }, // 1/2 a cS |
{ 4900000, 0.49 }, // a bit below |
{ 3333333, 0.3333333 }, // 1/3 cS |
{ 1250000, 0.125 }, // 800Hz |
{ 1000000, 0.1 }, // 1000Hz |
{ 909090, 0.0909090 }, // 1100Hz |
{ 490000, 0.049 }, // 490uS |
{ 333333, 0.0333333 }, // 1/30 cS, 1/3mS |
{ 49000, 0.0049 }, // 49uS |
{ 33333, 0.0033333 }, // 1/30 mS |
{ 4900, 0.00049 }, // 4.9uS |
// now some outlandish ones |
{ 170, 0.000017 }, // 170nS |
{ 11, 0.0000011 }, // 11nS |
{ 1000000000u, 100.0 }, // one second |
{ 1234567777u, 123.4567777 }, // 1.234... seconds |
{ 4294967291u, 429.4967291 }, // 4.3 seconds, nearly maxint. |
// now some which are prime in the nS per tick field |
{ 909091, 0.0909091 }, // also 1100Hz - but 909091 is a prime! |
// and some eye-pleasing primes from the www - if they're not actually |
// prime, don't blame me. http://www.rsok.com/~jrm/printprimes.html |
{ 1000003, 0.1000003 }, |
{ 1477771, 0.1477771 }, |
{ 2000003, 0.2000003 }, |
{ 2382001, 0.2382001 }, |
{ 3333133, 0.3333133 }, |
{ 3999971, 0.3999971 }, |
{ 5555591, 0.5555591 }, |
{ 6013919, 0.6013919 }, |
// That's enough |
}; |
|
static void entry0( CYG_ADDRWORD data ) |
{ |
// First just try it with the clock as default: |
Cyg_Clock *rtc = Cyg_Clock::real_time_clock; |
|
Cyg_Clock::converter cv, rcv; |
Cyg_Clock::cyg_resolution res; |
|
unsigned int counter = 0; |
unsigned int skipped = 0; |
|
unsigned int i; |
for ( i = 0; i < sizeof( ns_tickers )/sizeof( ns_tickers[0] ); i++ ) { |
|
unsigned int lcounter = 0; |
unsigned int lskipped = 0; |
|
rtc->get_other_to_clock_converter( ns_tickers[i].ns, &cv ); |
rtc->get_clock_to_other_converter( ns_tickers[i].ns, &rcv ); |
|
PRINTF1( "ns per tick: %d\n", ns_tickers[i].ns ); |
PRINTF1( " converter: * %d / %d * %d / %d\n", |
(int)cv.mul1, (int)cv.div1, (int)cv.mul2,(int) cv.div2 ); |
PRINTF1( " reverser: * %d / %d * %d / %d\n", |
(int)rcv.mul1, (int)rcv.div1, (int)rcv.mul2, (int)rcv.div2 ); |
|
double d = 1.0; |
d *= (double)cv.mul1; |
d /= (double)cv.div1; |
d *= (double)cv.mul2; |
d /= (double)cv.div2; |
d *= (double)rcv.mul1; |
d /= (double)rcv.div1; |
d *= (double)rcv.mul2; |
d /= (double)rcv.div2; |
PRINTF1( " composite product %d.%d\n", |
(int)d, ((int)(d * 1000000) % 1000000 ) ); |
d -= 1.0; |
CYG_TEST_CHECK( d < +0.0001, "Overflow in composite product" ); |
CYG_TEST_CHECK( d > -0.0001, "Underflow in composite product" ); |
|
res = rtc->get_resolution(); |
|
double factor_other_to_clock; |
double factor_clock_to_other; |
|
// res.dividend/res.divisor is the number of nS in a system |
// clock tick. So: |
d = (double)res.dividend/(double)res.divisor; |
|
factor_other_to_clock = ns_tickers[i].scale * 1.0e7 / d ; |
factor_clock_to_other = d / (ns_tickers[i].scale * 1.0e7); |
|
unsigned int j; |
for ( j = 1; j < 100; j++ ) { |
cyg_uint64 delay; |
if (cyg_test_is_simulator) |
j += 30; // test fewer values |
/* tr.b..m..k.. */ |
|
#ifdef CYGPKG_HAL_V85X_V850_CEB |
j += 30; // test fewer values |
#endif |
|
for ( delay = j; delay < 1000000000000ll; delay *= 10 ) { |
// get the converted result |
cyg_uint64 result = Cyg_Clock::convert( delay, &cv ); |
|
counter++; lcounter++; |
if ( (double)delay * (double)cv.mul1 > 1.6e+19 || |
(double)delay * (double)rcv.mul1 > 1.6e+19 ) { |
// in silly territory now, give up. |
// (that's MAXINT squared, approx.) |
skipped++; lskipped++; |
continue; // so the counter is accurate |
} |
|
PRINTF2( "delay %x%08x to result %x%08x\n", |
(int)(delay >> 32), (int)delay, |
(int)(result >> 32), (int)result ); |
|
// get what it should be in double maths |
double delta = factor_other_to_clock * (double)delay; |
if ( delta > 1000.0 ) { |
delta = (double)result - delta; |
delta /= (double)result; |
CYG_TEST_CHECK( delta <= +0.01, |
"Proportional overflow in conversion to" ); |
CYG_TEST_CHECK( delta >= -0.01, |
"Proportional underflow in conversion to" ); |
} |
else { |
cyg_uint64 lo = (cyg_uint64)(delta); // assume TRUNCATION |
cyg_uint64 hi = lo + 1; |
CYG_TEST_CHECK( hi >= result, |
"Range overflow in conversion to" ); |
CYG_TEST_CHECK( lo <= result, |
"Range underflow in conversion to" ); |
} |
|
// get the converted result |
result = Cyg_Clock::convert( delay, &rcv ); |
|
PRINTF2( "delay %x%08x from result %x%08x\n", |
(int)(delay >> 32), (int)delay, |
(int)(result >> 32), (int)result ); |
|
// get what it should be in double maths |
delta = factor_clock_to_other * (double)delay; |
if ( delta > 1000.0 ) { |
delta = (double)result - delta; |
delta /= (double)result; |
CYG_TEST_CHECK( delta <= +0.01, |
"Proportional overflow in conversion from" ); |
CYG_TEST_CHECK( delta >= -0.01, |
"Proportional underflow in conversion from" ); |
} |
else { |
cyg_uint64 lo = (cyg_uint64)(delta); // assume TRUNCATION |
cyg_uint64 hi = lo + 1; |
CYG_TEST_CHECK( hi >= result, |
"Range overflow in conversion from" ); |
CYG_TEST_CHECK( lo <= result, |
"Range underflow in conversion from" ); |
} |
|
if (cyg_test_is_simulator) |
break; |
} |
} |
PRINTF0( "INFO:<%d nS/tick: tested %d values, skipped %d because of overflow>\n", |
ns_tickers[i].ns, lcounter, lskipped ); |
} |
|
PRINTF0( "INFO:<tested %d values, total skipped %d because of overflow>\n", |
counter, skipped ); |
|
CYG_TEST_PASS_FINISH("ClockCnv OK"); |
} |
|
void clockcnv_main( void ) |
{ |
CYG_TEST_INIT(); |
new_thread(entry0, (CYG_ADDRWORD)&thread_obj[0]); |
Cyg_Scheduler::start(); |
} |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
clockcnv_main(); |
} |
|
#else // def CYGVAR_KERNEL_COUNTERS_CLOCK |
|
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA( "Kernel real-time clock disabled"); |
} |
|
#endif // def CYGVAR_KERNEL_COUNTERS_CLOCK |
|
// EOF clockcnv.cxx |
/kexcept1.c
0,0 → 1,288
/*================================================================= |
// |
// kexcept1.cxx |
// |
// Kernel C API Exception test 1 |
// |
//================================================================= |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//================================================================= |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm, jlarmour |
// Date: 1999-02-16 |
// Description: Test basic exception functionality |
//####DESCRIPTIONEND#### |
*/ |
|
#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
#include <cyg/kernel/kapi.h> |
|
#include <cyg/infra/testcase.h> |
|
#ifdef CYGPKG_KERNEL_EXCEPTIONS |
|
#ifdef CYGFUN_KERNEL_API_C |
|
#include <cyg/hal/hal_intr.h> // exception ranges |
|
#include "testaux.h" |
|
#ifndef CYGPKG_HAL_ARM_PID |
#define EXCEPTION_DATA_ACCESS |
#endif |
|
#define NTHREADS 1 |
#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
static cyg_handle_t thread[NTHREADS]; |
|
static cyg_thread thread_obj[NTHREADS]; |
static char stack[NTHREADS][STACKSIZE]; |
|
|
|
#ifdef EXCEPTION_DATA_ACCESS |
static cyg_exception_handler_t handler0; |
|
static void handler0(cyg_addrword_t data, cyg_code_t number, cyg_addrword_t info) |
{ |
CYG_TEST_INFO("handler 0 called"); |
|
CYG_TEST_CHECK((cyg_addrword_t)123 == data, "handler given wrong data"); |
|
// ignore machine specific stuff |
CYG_UNUSED_PARAM(cyg_code_t, number); |
CYG_UNUSED_PARAM(cyg_addrword_t, info); |
|
CYG_TEST_PASS_FINISH("Except 1 OK"); |
} |
#endif |
|
static int d0; |
|
static void handler1(cyg_addrword_t data, cyg_code_t number, cyg_addrword_t info) |
{ |
CYG_TEST_INFO("handler 1 called"); |
|
CYG_TEST_CHECK((cyg_addrword_t)&d0 == data, "handler given wrong data"); |
|
#ifdef CYGSEM_KERNEL_EXCEPTIONS_DECODE |
CYG_TEST_CHECK(number == CYGNUM_HAL_EXCEPTION_MAX, "handler given wrong number"); |
#else |
CYG_UNUSED_PARAM(cyg_code_t, number); |
#endif |
|
CYG_TEST_CHECK((cyg_addrword_t)99 == info, "handler given wrong info"); |
} |
|
|
#ifdef EXCEPTION_DATA_ACCESS |
// The following function attempts to cause an exception in various |
// hacky ways. It is machine dependent what exception is generated. |
// It does reads rather than writes hoping not to corrupt anything |
// important. |
static int |
cause_fpe(int num) |
{ |
double a; |
|
a = 1.0/num; // Depending on FPU emulation and/or |
// the FPU architecture, this may |
// cause an exception. |
// (float division by zero) |
|
return ((int)a)/num; // This may cause an exception if |
// the architecture supports it. |
// (integer division by zero). |
} // cause_fpe() |
|
void cause_exception(void) |
{ |
int x; |
unsigned int p=0; |
|
// First try for an address exception (unaligned access exception |
// or SEGV/BUS exceptions) |
do { |
x=*(volatile int *)(p-1); |
p+=0x100000; |
} while(p != 0); |
|
// Next try an integer or floating point divide-by-zero exception. |
cause_fpe(0); |
} |
#endif |
|
static void entry0( CYG_ADDRWORD data ) |
{ |
#ifdef EXCEPTION_DATA_ACCESS |
cyg_code_t n; |
#endif |
cyg_exception_handler_t *old_handler, *old_handler1; |
cyg_addrword_t old_data, old_data1; |
|
CYG_UNUSED_PARAM(CYG_ADDRESS, data); |
|
cyg_exception_set_handler( |
CYGNUM_HAL_EXCEPTION_MAX, |
&handler1, |
(cyg_addrword_t)&d0, |
&old_handler, |
&old_data); |
|
cyg_exception_set_handler( |
CYGNUM_HAL_EXCEPTION_MAX, |
&handler1, |
(cyg_addrword_t)&d0, |
&old_handler1, |
&old_data1); |
|
CYG_TEST_CHECK(old_handler1 == &handler1, |
"register exception: old_handler not the one previously registered"); |
CYG_TEST_CHECK(old_data1 == (cyg_addrword_t)&d0, |
"register exception: old_data not those previously registered"); |
|
cyg_exception_call_handler( |
cyg_thread_self(), |
CYGNUM_HAL_EXCEPTION_MAX, |
(cyg_addrword_t)99); |
|
CYG_TEST_INFO("handler 1 returned"); |
|
cyg_exception_clear_handler(CYGNUM_HAL_EXCEPTION_MAX); |
cyg_exception_clear_handler(CYGNUM_HAL_EXCEPTION_MAX); |
|
#ifdef EXCEPTION_DATA_ACCESS |
|
#if 0 |
#elif defined(CYGPKG_HAL_POWERPC_SIM) |
// The exception generated by the SIM is not recognized by GDB. |
// PR 19945 workaround. |
CYG_TEST_NA("Not applicable to PowerPC SIM"); |
#endif |
|
for(n = CYGNUM_HAL_EXCEPTION_MIN; n <= CYGNUM_HAL_EXCEPTION_MAX; n++) { |
cyg_exception_set_handler( |
n, |
handler0, |
(cyg_addrword_t)123, |
&old_handler1, |
&old_data1); |
} |
|
CYG_TEST_PASS("Attempting to provoke exception"); |
|
cause_exception(); |
|
CYG_TEST_FAIL_FINISH("Couldn't cause exception"); |
#else // EXCEPTION_DATA_ACCESS |
CYG_TEST_NA("Platform does not support data exceptions"); |
#endif |
} |
|
#ifdef CYG_HAL_MIPS_TX39_JMR3904 |
|
extern void __default_exception_vsr(void); |
|
#endif |
|
void except0_main( void ) |
{ |
// Use CYG_TEST_GDBCMD _before_ CYG_TEST_INIT() |
CYG_TEST_GDBCMD("handle SIGBUS nostop"); |
CYG_TEST_GDBCMD("handle SIGSEGV nostop"); |
CYG_TEST_GDBCMD("handle SIGFPE nostop"); |
|
CYG_TEST_INIT(); |
|
#ifdef HAL_VSR_SET_TO_ECOS_HANDLER |
// Reclaim the VSR off CygMon possibly |
#ifdef CYGNUM_HAL_EXCEPTION_DATA_ACCESS |
HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_DATA_ACCESS, NULL ); |
#endif |
#ifdef CYGNUM_HAL_EXCEPTION_DATA_TLBMISS_ACCESS |
HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_DATA_TLBMISS_ACCESS, NULL ); |
#endif |
#ifdef CYGNUM_HAL_EXCEPTION_DATA_UNALIGNED_ACCESS |
HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_DATA_UNALIGNED_ACCESS, NULL ); |
#endif |
#ifdef CYGNUM_HAL_EXCEPTION_ILLEGAL_INSTRUCTION |
HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_ILLEGAL_INSTRUCTION, NULL ); |
#endif |
#ifdef CYGNUM_HAL_EXCEPTION_DIV_BY_ZERO |
HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_DIV_BY_ZERO, NULL ); |
#endif |
#ifdef CYGNUM_HAL_EXCEPTION_FPU |
HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_FPU, NULL ); |
#endif |
#ifdef CYGNUM_HAL_EXCEPTION_FPU_DIV_BY_ZERO |
HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_FPU_DIV_BY_ZERO, NULL ); |
#endif |
#endif |
|
cyg_thread_create(4, entry0 , (cyg_addrword_t)0, "kexcept1", |
(void *)stack[0], STACKSIZE, &thread[0], &thread_obj[0]); |
cyg_thread_resume(thread[0]); |
|
cyg_scheduler_start(); |
|
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
externC void |
cyg_start( void ) |
{ |
except0_main(); |
} |
|
#else // def CYGFUN_KERNEL_API_C |
#define N_A_MSG "Kernel C API layer disabled" |
#endif // def CYGFUN_KERNEL_API_C |
#else // def CYGPKG_KERNEL_EXCEPTIONS |
#define N_A_MSG "Exceptions disabled" |
#endif // def CYGPKG_KERNEL_EXCEPTIONS |
|
#ifdef N_A_MSG |
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA( N_A_MSG); |
} |
#endif // N_A_MSG |
|
/* EOF kexcept1.c */ |
/kphilo.c
0,0 → 1,236
//========================================================================== |
// |
// kphilo.c |
// |
// A test of the dining philosophers problem |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-02-24 |
// Description: A test of the dining philosophers problem |
//####DESCRIPTIONEND#### |
// |
|
#include <cyg/kernel/kapi.h> |
|
#include <cyg/infra/cyg_ass.h> |
#include <cyg/kernel/diag.h> |
|
// ------------------------------------------------------------------------- |
// Data for the philosophers problem |
|
#define PHILOSOPHERS 15 // number of philosophers |
#define STACKSIZE (2*1024) // size of thread stack |
|
// array of stacks for philosopher threads |
char thread_stack[PHILOSOPHERS][STACKSIZE]; |
|
// array of threads. |
cyg_thread thread[PHILOSOPHERS]; |
|
cyg_handle_t thread_handle[PHILOSOPHERS]; |
|
// array of chopsticks |
cyg_sem_t chopstick[PHILOSOPHERS]; |
|
cyg_ucount32 data_index; |
|
// ------------------------------------------------------------------------- |
// State recording and display |
|
static char pstate[PHILOSOPHERS+1]; // state vector showing what each |
// philosopher is doing |
|
cyg_mutex_t state_mutex; |
|
#ifdef CYG_HAL_MN10300_MN103002 |
static cyg_count8 eaters = 0; |
#endif |
|
void change_state(int id, char newstate) |
{ |
cyg_mutex_lock(&state_mutex); |
|
#ifdef CYG_HAL_MN10300_MN103002 |
if( pstate[id] == 'E' ) eaters--; |
if( newstate == 'E' ) eaters++; |
// led(eaters); |
#endif |
|
pstate[id] = newstate; |
|
diag_write_string(pstate); |
#if 0 |
diag_write_char(' '); |
diag_write_dec(Cyg_Scheduler::get_thread_switches()); |
#endif |
diag_write_char('\n'); |
|
cyg_mutex_unlock(&state_mutex); |
|
} |
|
char get_state( int id) |
{ |
char s; |
cyg_mutex_lock(&state_mutex); |
|
s = pstate[id]; |
|
cyg_mutex_unlock(&state_mutex); |
|
return s; |
} |
|
// ------------------------------------------------------------------------- |
// Thread to behave like a philosopher |
|
void Philosopher( cyg_addrword_t vid ) |
{ |
cyg_uint32 id = (cyg_uint32)vid; |
cyg_sem_t *first_stick = &chopstick[id]; |
cyg_sem_t *second_stick = &chopstick[(id+1)%PHILOSOPHERS]; |
#ifdef CYGPKG_INFRA_DEBUG |
int left_philo = ((id==0)?PHILOSOPHERS:id)-1; |
int right_philo = (id==PHILOSOPHERS-1)?0:(id+1); |
#endif |
|
CYG_ASSERT( id >= 0 && id < PHILOSOPHERS, "Bad id"); |
|
// Deadlock avoidance. The easiest way to make the philosophers |
// behave is to make each pick up the lowest numbered stick |
// first. This is how it works out anyway for all the philosophers |
// except the last, who must have his sticks swapped. |
|
if( id == PHILOSOPHERS-1 ) |
{ |
cyg_sem_t *t = first_stick; |
first_stick = second_stick; |
second_stick = t; |
} |
|
for(;;) |
{ |
cyg_ucount32 val; |
|
// The following variable is shared by all philosophers. |
// It is incremented unprotected, but this does not matter |
// since it is only present to introduce a little variability |
// into the think and eat times. |
|
static volatile int cycle = 0; |
|
// Think for a bit |
|
cyg_thread_delay((id+cycle++)%12); // Cogito ergo sum... |
|
// I am now hungry, try to get the chopsticks |
|
change_state(id,'H'); |
|
// Get the first stick |
cyg_semaphore_wait(first_stick); |
|
// Get the second stick |
cyg_semaphore_wait(second_stick); |
|
// Got them, now eat |
|
change_state(id,'E'); |
|
// Check that the world is as I think it is... |
cyg_semaphore_peek( first_stick, &val); |
CYG_ASSERT( val == 0, "Not got first stick"); |
cyg_semaphore_peek( second_stick, &val); |
CYG_ASSERT( val == 0, "Not got second stick"); |
CYG_ASSERT( get_state(left_philo) != 'E', "Left neighbour also eating!!"); |
CYG_ASSERT( get_state(right_philo) != 'E', "Right neighbour also eating!!"); |
|
cyg_thread_delay((id+cycle++)%6); // munch munch |
|
// Finished eating, put down sticks. |
|
change_state(id,'T'); |
|
cyg_semaphore_post( first_stick ); |
cyg_semaphore_post( second_stick ); |
|
} |
} |
|
// ------------------------------------------------------------------------- |
|
externC void |
cyg_start( void ) |
{ |
int i; |
|
diag_init(); |
|
diag_write_string("Philosophers\n"); |
diag_write_string("Started\n"); |
|
// Zero last element in state so it acts like |
// a string. |
pstate[PHILOSOPHERS] = 0; |
|
#if 1 |
for( i = 0; i < PHILOSOPHERS; i++ ) |
{ |
change_state(i,'T'); // starting state |
|
cyg_thread_create(4, Philosopher, (cyg_addrword_t)i, "philosopher", |
(void *)(&thread_stack[i]), STACKSIZE, |
&thread_handle[i], &thread[i]); |
|
// resume it |
cyg_thread_resume(thread_handle[i]); |
|
// and make the matching chopstick present |
cyg_semaphore_init( &chopstick[i], 1); |
} |
#endif |
|
// Get the world going |
cyg_scheduler_start(); |
|
} |
|
// ------------------------------------------------------------------------- |
// EOF kphilo.c |
/cnt_sem0.cxx
0,0 → 1,89
//========================================================================== |
// |
// cnt_sem0.cxx |
// |
// Counting semaphore test 0 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-02-24 |
// Description: Limited to checking constructors/destructors |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/sema.hxx> |
|
#include <cyg/infra/testcase.h> |
|
static Cyg_Counting_Semaphore sema0, sema1(0), sema2(1); |
|
#include "testaux.hxx" |
|
static bool flash( void ) |
{ |
Cyg_Counting_Semaphore s0; |
|
Cyg_Counting_Semaphore s1(97); |
|
Cyg_Counting_Semaphore s2(0); |
|
return true; |
} |
|
void cnt_sem0_main( void ) |
{ |
CYG_TEST_INIT(); |
|
CHECK(flash()); |
CHECK(flash()); |
|
CYG_TEST_PASS_FINISH("Counting Semaphore 0 OK"); |
} |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
cnt_sem0_main(); |
} |
|
// EOF cnt_sem0.cxx |
/cnt_sem1.cxx
0,0 → 1,135
//========================================================================== |
// |
// cnt_sem1.cxx |
// |
// Counting semaphore test 1 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-02-24 |
// Description: Tests basic counting semaphore functionality. |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/thread.hxx> // Cyg_Thread |
#include <cyg/kernel/thread.inl> |
#include <cyg/kernel/sched.hxx> // Cyg_Scheduler::start() |
|
#include <cyg/kernel/sema.hxx> |
|
#include <cyg/infra/testcase.h> |
|
#include <cyg/kernel/sched.inl> |
|
|
#define NTHREADS 2 |
#include "testaux.hxx" |
|
static Cyg_Counting_Semaphore s0(0), s1(2), s2; |
|
static volatile cyg_ucount8 q = 0; |
|
static void entry0( CYG_ADDRWORD data ) |
{ |
s0.wait(); |
CHECK( 1 == q++ ); |
s1.post(); |
s0.wait(); |
CHECK( 3 == q++ ); |
CHECK( 0 == s0.peek() ); |
CHECK( ! s0.trywait() ); |
s0.post(); |
CHECK( 4 == q++ ); |
CHECK( 1 == s0.peek() ); |
s0.post(); |
CHECK( 2 == s0.peek() ); |
s1.post(); |
CHECK( 0 == s2.peek() ); |
s2.wait(); |
CHECK( 6 == q++ ); |
CYG_TEST_PASS_FINISH("Counting Semaphore 1 OK"); |
} |
|
static void entry1( CYG_ADDRWORD data ) |
{ |
CHECK( 2 == s1.peek() ); |
s1.wait(); |
CHECK( 1 == s1.peek() ); |
s1.wait(); |
CHECK( 0 == q++ ); |
CHECK( 0 == s0.peek() ); |
s0.post(); |
s1.wait(); |
CHECK( 2 == q++ ); |
s0.post(); |
s1.wait(); |
CHECK( 5 == q++ ); |
CHECK( 2 == s0.peek() ); |
CHECK( s0.trywait() ); |
CHECK( 1 == s0.peek() ); |
CHECK( s0.trywait() ); |
CHECK( 0 == s0.peek() ); |
s2.post(); |
s0.wait(); |
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
void cnt_sem1_main( void ) |
{ |
CYG_TEST_INIT(); |
|
new_thread(entry0, 0); |
new_thread(entry1, 1); |
|
Cyg_Scheduler::start(); |
|
CYG_TEST_FAIL_FINISH("Not reached"); |
} |
|
externC void |
cyg_start( void ) |
{ |
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
cyg_hal_invoke_constructors(); |
#endif |
cnt_sem1_main(); |
} |
|
// EOF cnt_sem1.cxx |
/kmutex0.c
0,0 → 1,98
/*================================================================= |
// |
// kmutex0.c |
// |
// Kernel C API Mutex and condition variable test 0 |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): dsm |
// Contributors: dsm |
// Date: 1998-03-23 |
// Description: Limited to checking constructors/destructors |
//####DESCRIPTIONEND#### |
*/ |
|
#include <cyg/kernel/kapi.h> |
|
#include <cyg/infra/testcase.h> |
|
#ifdef CYGFUN_KERNEL_API_C |
|
#include "testaux.h" |
|
static cyg_mutex_t mutex0; |
|
static cyg_cond_t cvar0; |
|
static bool flash( void ) |
{ |
cyg_mutex_init( &mutex0 ); |
cyg_cond_init( &cvar0, &mutex0 ); |
|
cyg_cond_destroy( &cvar0 ); |
cyg_mutex_destroy( &mutex0 ); |
|
return true; |
} |
|
void kmutex0_main( void ) |
{ |
CYG_TEST_INIT(); |
|
CHECK(flash()); |
CHECK(flash()); |
|
CYG_TEST_PASS_FINISH("Kernel C API Mutex 0 OK"); |
} |
|
externC void |
cyg_start( void ) |
{ |
kmutex0_main(); |
} |
|
#else /* def CYGFUN_KERNEL_API_C */ |
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA("Kernel C API layer disabled"); |
} |
#endif /* def CYGFUN_KERNEL_API_C */ |
|
/* EOF kmutex0.c */ |
/stress_threads.c
0,0 → 1,859
//========================================================================== |
// |
// stress_threads.cxx |
// |
// Basic thread stress test |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): rosalia |
// Contributors: rosalia, jskov |
// Date: 1999-04-13 |
// Description: Very simple thread stress test, with some memory |
// allocation and alarm handling. |
// |
// Notes: |
// If client_makes_request is big, it means that there are made many more |
// client requests than can be serviced. Consequently, clients are wasting |
// CPU time and should be sleeping more. |
// |
// The list of handler invocations show how many threads are running |
// at the same time. The more powerful the CPU, the more the numbers |
// should spread out. |
//####DESCRIPTIONEND#### |
|
#include <pkgconf/system.h> |
#include <cyg/infra/testcase.h> |
|
#include <cyg/hal/hal_arch.h> |
|
#if defined(CYGPKG_KERNEL) && defined(CYGPKG_IO) && defined(CYGPKG_ISOINFRA) |
|
#include <pkgconf/kernel.h> |
#include <pkgconf/isoinfra.h> |
#include CYGHWR_MEMORY_LAYOUT_H |
|
#if defined(CYGFUN_KERNEL_API_C) |
|
#include <cyg/kernel/kapi.h> |
|
#ifdef CYGINT_ISO_STDIO_FORMATTED_IO |
|
#include <stdio.h> |
#include <stdlib.h> |
|
#if defined(CYGPKG_LIBM) |
|
#include <math.h> |
#include <assert.h> |
|
#include <cyg/kernel/test/stackmon.h> |
|
#if defined(CYGFUN_KERNEL_THREADS_TIMER) |
#if CYGINT_ISO_MALLOC |
|
/* if TIME_LIMIT is defined, it represents the number of seconds this |
test should last; if it is undefined the test will go forever */ |
#define DEATH_TIME_LIMIT 20 |
/* #undef DEATH_TIME_LIMIT */ |
|
// STACK_SIZE is typical +2kB for printf family calls which use big |
// auto variables. Add more for handler which calls perform_stressful_tasks() |
#define STACK_SIZE (2*1024 + CYGNUM_HAL_STACK_SIZE_TYPICAL) |
#define STACK_SIZE_HANDLER (STACK_SIZE + 30*CYGNUM_HAL_STACK_FRAME_SIZE) |
|
#define N_MAIN 1 |
|
// If we have instrumentation enabled, make the execution time in the |
// simulator even shorter that we were going to anyway. |
#ifdef CYGPKG_KERNEL_INSTRUMENT |
#define SIM_DELAY_DIVISOR 100 |
#else |
#define SIM_DELAY_DIVISOR 10 |
#endif |
|
//----------------------------------------------------------------------- |
// Some targets need to define a smaller number of handlers due to |
// memory restrictions. |
#if defined(CYGMEM_REGION_ram_SIZE) && (CYGMEM_REGION_ram_SIZE < 0x80000) |
#define MAX_HANDLERS 4 |
#define N_LISTENERS 1 |
#define N_CLIENTS 1 |
|
#undef STACK_SIZE |
#undef STACK_SIZE_HANDLER |
#define STACK_SIZE (1024 + CYGNUM_HAL_STACK_SIZE_TYPICAL) |
#define STACK_SIZE_HANDLER (STACK_SIZE + 10*CYGNUM_HAL_STACK_FRAME_SIZE) |
#endif |
|
//----------------------------------------------------------------------- |
// If no target specific definitions, use defaults |
#ifndef MAX_HANDLERS |
#define MAX_HANDLERS 19 |
#define N_LISTENERS 4 |
#define N_CLIENTS 4 |
#endif |
|
/* Allocate priorities in this order. This ensures that handlers |
(which are the ones using the CPU) get enough CPU time to actually |
complete their tasks. |
|
The empty space ensures that if libc main() thread should happen to |
be in the priority range of the handlers, no handlers are |
accidently reduced so much in priority to get below |
listeners/clients. */ |
|
#define P_MAIN_PROGRAM 1 |
#define P_MAIN_PROGRAM_E (P_MAIN_PROGRAM+N_MAIN) |
|
#define P_BASE_HANDLER (P_MAIN_PROGRAM_E) |
#define P_BASE_HANDLER_E (P_BASE_HANDLER+MAX_HANDLERS) |
|
#define P_BASE_EMPTY (P_BASE_HANDLER_E) |
#define P_BASE_EMPTY_E (P_BASE_EMPTY+2) |
|
#define P_BASE_LISTENER (P_BASE_EMPTY_E) |
#define P_BASE_LISTENER_E (P_BASE_LISTENER+N_LISTENERS) |
|
#define P_BASE_CLIENT (P_BASE_LISTENER_E) |
#define P_BASE_CLIENT_E (P_BASE_CLIENT+N_CLIENTS) |
|
#define P_MAX (P_BASE_CLIENT_E) |
|
/* Ensure there's room for what we request */ |
#if (CYGNUM_KERNEL_SCHED_PRIORITIES >= P_MAX) |
|
/* if we use the bitmap scheduler we must make sure we don't use the |
same priority more than once, so we must store those already in use */ |
static volatile char priority_in_use[P_MAX]; |
|
/* We may not get the priority we ask for (scheduler may decide to ignore |
schedule hint). So keep a table of priorities actually assigned to |
the threads. This information may come in handy for debugging - it's |
not actively used by the code. */ |
static volatile int priority_translation[P_MAX]; |
|
/* now declare (and allocate space for) some kernel objects, like the |
threads we will use */ |
cyg_thread main_thread_s; |
cyg_thread handler_thread_s[MAX_HANDLERS]; |
cyg_thread listener_thread_s[N_LISTENERS]; |
cyg_thread client_thread_s[N_CLIENTS]; |
|
/* space for stacks for all threads */ |
char main_stack[STACK_SIZE]; |
char handler_stack[MAX_HANDLERS][STACK_SIZE_HANDLER]; |
char listener_stack[N_LISTENERS][STACK_SIZE]; |
char client_stack[N_CLIENTS][STACK_SIZE]; |
|
/* now the handles for the threads */ |
cyg_handle_t mainH; |
cyg_handle_t handlerH[MAX_HANDLERS]; |
cyg_handle_t listenerH[N_LISTENERS]; |
cyg_handle_t clientH[N_CLIENTS]; |
|
/* space for thread names */ |
char thread_name[P_MAX][20]; |
|
/* and now variables for the procedure which is the thread */ |
cyg_thread_entry_t main_program, client_program, listener_program, |
handler_program; |
|
/* a few mutexes used in the code */ |
cyg_mutex_t client_request_lock, handler_slot_lock, statistics_print_lock, |
free_handler_lock; |
|
/* global variables with which the handler IDs and thread priorities |
to free are communicated from handlers to main_program. Access to |
these are protected by free_handler_lock. An id of -1 means the |
that the variables are empty. */ |
volatile int free_handler_pri = 0; |
volatile int free_handler_id = -1; |
|
/* a global variable with which the client and server coordinate */ |
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 */ |
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 */ |
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 { |
/* store the number of times each handler has been invoked */ |
unsigned long handler_invocation_histogram[MAX_HANDLERS]; |
|
/* store how many times malloc has been attempted and how many times |
it has failed */ |
unsigned long malloc_tries, malloc_failures; |
|
/* how many threads have been created */ |
unsigned long thread_creations, thread_exits; |
}; |
|
struct s_statistics statistics; |
|
/* some function prototypes; those with the sc_ prefix are |
"statistics-collecting" versions of the cyg_ primitives */ |
cyg_addrword_t sc_thread_create( |
cyg_addrword_t sched_info, /* scheduling info (eg pri) */ |
cyg_thread_entry_t *entry, /* entry point function */ |
cyg_addrword_t entry_data, /* entry data */ |
char *name, /* optional thread name */ |
void *stack_base, /* stack base, NULL = alloc */ |
cyg_ucount32 stack_size, /* stack size, 0 = default */ |
cyg_handle_t *handle, /* returned thread handle */ |
cyg_thread *thread /* put thread here */ |
); |
|
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, |
cyg_alarm *death_alarm_p, int *killed_p); |
void print_statistics(int print_full); |
|
/* we need to declare the alarm handling function (which is defined |
below), so that we can pass it to cyg_alarm_initialize() */ |
cyg_alarm_t report_alarm_func, death_alarm_func; |
|
/* handle and alarm for the report alarm */ |
cyg_handle_t report_alarmH, counterH, system_clockH; |
cyg_alarm report_alarm; |
|
/* main launches all the threads of the test */ |
int |
main(void) |
{ |
int i; |
|
CYG_TEST_INIT(); |
CYG_TEST_INFO("Stress threads test compiled on " __DATE__); |
|
cyg_mutex_init(&client_request_lock); |
cyg_mutex_init(&statistics_print_lock); |
cyg_mutex_init(&free_handler_lock); |
|
/* initialize statistics */ |
memset(&statistics, 0, sizeof(statistics)); |
|
/* clear priority table */ |
for (i = 0; i < sizeof(priority_in_use); i++) |
priority_in_use[i] = 0; |
|
/* initialize main thread */ |
{ |
priority_translation[P_MAIN_PROGRAM] = |
sc_thread_create(P_MAIN_PROGRAM, main_program, (cyg_addrword_t) 0, |
"main_program", (void *) main_stack, STACK_SIZE, |
&mainH, &main_thread_s); |
priority_in_use[P_MAIN_PROGRAM]++; |
} |
|
/* initialize all handler threads to not be in use */ |
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]; |
sprintf(name, "listener-%02d", i); |
priority_translation[prio] = |
sc_thread_create(prio, listener_program, (cyg_addrword_t) i, |
name, (void *) listener_stack[i], STACK_SIZE, |
&listenerH[i], &listener_thread_s[i]); |
CYG_ASSERT(0 == priority_in_use[prio], "Priority already in use!"); |
priority_in_use[prio]++; |
} |
for (i = 0; i < N_CLIENTS; ++i) { |
int prio = P_BASE_CLIENT + i; |
char* name = &thread_name[prio][0]; |
sprintf(name, "client-%02d", i); |
priority_translation[prio] = |
sc_thread_create(prio, client_program, (cyg_addrword_t) i, |
name, (void *) client_stack[i], STACK_SIZE, |
&(clientH[i]), &client_thread_s[i]); |
CYG_ASSERT(0 == priority_in_use[prio], "Priority already in use!"); |
priority_in_use[prio]++; |
} |
|
cyg_thread_resume(mainH); |
for (i = 0; i < N_CLIENTS; ++i) { |
cyg_thread_resume(clientH[i]); |
} |
for (i = 0; i < N_LISTENERS; ++i) { |
cyg_thread_resume(listenerH[i]); |
} |
|
/* set up the alarm which gives periodic wakeups to say "time to |
print a report */ |
system_clockH = cyg_real_time_clock(); |
cyg_clock_to_counter(system_clockH, &counterH); |
|
cyg_alarm_create(counterH, report_alarm_func, |
(cyg_addrword_t) 4000, |
&report_alarmH, &report_alarm); |
if (cyg_test_is_simulator) { |
time_report_delay = 2; |
} else { |
time_report_delay = 60; |
} |
|
cyg_alarm_initialize(report_alarmH, cyg_current_time()+200, |
time_report_delay*100); |
|
return 0; |
} |
|
/* main_program() -- frees resources and prints status. */ |
void main_program(cyg_addrword_t data) |
{ |
#ifdef DEATH_TIME_LIMIT |
cyg_handle_t deathH; |
cyg_alarm death_alarm; |
int is_dead = 0; |
|
setup_death_alarm(0, &deathH, &death_alarm, &is_dead); |
#endif /* DEATH_TIME_LIMIT */ |
|
for (;;) { |
int handler_id = -1; |
int handler_pri = 0; |
|
cyg_mutex_lock(&free_handler_lock); { |
// If any handler has left its ID, copy the ID and |
// priority values to local variables, and free up the |
// global communication variables again. |
if (-1 != free_handler_id) { |
handler_id = free_handler_id; |
handler_pri = free_handler_pri; |
free_handler_id = -1; |
} |
} cyg_mutex_unlock(&free_handler_lock); |
|
if (-1 != handler_id) { |
stop_handler(handler_id, handler_pri); |
} |
|
// If it's time to report status or quit, set pause flag and |
// keep looping until all handlers have stopped. |
if (time_to_report) { |
// 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. |
if (is_dead) { |
// 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(1); |
CYG_TEST_PASS_FINISH("Kernel thread stress test OK"); |
} |
} |
#endif /* DEATH_TIME_LIMIT */ |
|
cyg_thread_delay(3); |
} |
} |
|
/* client_program() -- an obnoxious client which makes a lot of requests */ |
void client_program(cyg_addrword_t data) |
{ |
int delay; |
|
system_clockH = cyg_real_time_clock(); |
cyg_clock_to_counter(system_clockH, &counterH); |
|
for (;;) { |
delay = (rand() % 20); |
|
/* now send a request to the server */ |
cyg_mutex_lock(&client_request_lock); { |
if (0 == clients_paused) |
client_makes_request++; |
} cyg_mutex_unlock(&client_request_lock); |
|
cyg_thread_delay(10+delay); |
} |
} |
|
/* listener_program() -- listens for a request and spawns a handler to |
take care of the request */ |
void listener_program(cyg_addrword_t data) |
{ |
for (;;) { |
int make_request = 0; |
cyg_mutex_lock(&client_request_lock); { |
if (client_makes_request > 0) { |
--client_makes_request; |
make_request = 1; |
} |
} cyg_mutex_unlock(&client_request_lock); |
|
if (make_request) |
start_handler(); |
|
cyg_thread_delay(2 + (rand() % 10)); |
} |
} |
|
/* handler_program() -- is spawned to handle each incoming request */ |
void handler_program(cyg_addrword_t data) |
{ |
/* here is where we perform specific stressful tasks */ |
perform_stressful_tasks(); |
|
cyg_thread_delay(4 + (int) (0.5*log(1.0 + fabs((rand() % 1000000))))); |
|
{ |
// Loop until the handler id and priority can be communicated to |
// the main_program. |
int freed = 0; |
do { |
cyg_mutex_lock(&free_handler_lock); { |
if (-1 == free_handler_id) { |
free_handler_id = data; |
free_handler_pri = P_BASE_HANDLER+(int) data; |
freed = 1; |
} |
} cyg_mutex_unlock(&free_handler_lock); |
if (!freed) |
cyg_thread_delay(2); |
} while (!freed); |
} |
|
// Then exit. |
cyg_thread_exit(); |
} |
|
/* start a new handler */ |
void start_handler(void) |
{ |
int prio; |
char* name; |
int handler_slot = 0; |
int found = 0; |
|
while (!found) { |
cyg_mutex_lock(&handler_slot_lock); { |
for (handler_slot = 0; handler_slot < MAX_HANDLERS;++handler_slot){ |
if (!handler_thread_in_use[handler_slot]) { |
found = 1; |
handler_thread_in_use[handler_slot]++; |
handler_thread_in_use_count++; |
break; |
} |
} |
} cyg_mutex_unlock(&handler_slot_lock); |
if (!found) |
cyg_thread_delay(1); |
} |
|
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); |
|
priority_translation[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]; |
} |
|
/* 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]; |
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]; |
|
/* 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 |
allocation/deallocation concurrent with other thread execution |
(although I'm about to throw in a yield()) */ |
for (i = 0; i < MAX_MALLOCED_SPACES; ++i) { |
++statistics.malloc_tries; |
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(); |
} |
if (i % (MAX_MALLOCED_SPACES/15) == 0) { |
cyg_thread_delay(i % 5); |
} |
} |
|
cyg_thread_delay(5); |
|
/* now free it all up */ |
for (i = 0; i < MAX_MALLOCED_SPACES; ++i) { |
if (spaces[i] != NULL) { |
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]); |
} else { |
++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. */ |
for (i = 0; i < 10; ++i) { |
cyg_mempool_fix_create(pool_space[i], 100, (i+1)*3, |
&mempool_handles[i], &mempool_objects[i]); |
} |
|
for (i = 0; i < 10; ++i) { |
spaces[i] = cyg_mempool_fix_try_alloc(mempool_handles[i]); |
} |
|
for (i = 0; i < 10; ++i) { |
if (spaces[i]) { |
cyg_mempool_fix_delete(mempool_handles[i]); |
} |
} |
} |
|
/* report_alarm_func() is invoked as an alarm handler, so it should be |
quick and simple. in this case it sets a global flag which is |
checked by main_program. */ |
void report_alarm_func(cyg_handle_t alarmH, cyg_addrword_t data) |
{ |
time_to_report = 1; |
} |
|
#ifdef DEATH_TIME_LIMIT |
/* this sets up death alarms. it gets the handle and alarm from the |
caller, since they must persist for the life of the alarm */ |
void setup_death_alarm(cyg_addrword_t data, cyg_handle_t *deathHp, |
cyg_alarm *death_alarm_p, int *killed_p) |
{ |
cyg_handle_t system_clockH, counterH; |
cyg_resolution_t rtc_res; |
|
system_clockH = cyg_real_time_clock(); |
cyg_clock_to_counter(system_clockH, &counterH); |
|
cyg_alarm_create(counterH, death_alarm_func, |
(cyg_addrword_t) killed_p, |
deathHp, death_alarm_p); |
rtc_res = cyg_clock_get_resolution(system_clockH); |
{ |
cyg_tick_count_t tick_delay; |
tick_delay = (long long) |
((1000000000.0*rtc_res.divisor) |
*((double)DEATH_TIME_LIMIT)/((double)rtc_res.dividend)); |
if ( cyg_test_is_simulator ) |
tick_delay /= SIM_DELAY_DIVISOR; |
#ifdef CYGPKG_HAL_SYNTH |
// 20 seconds is a long time compared to the run time of other tests. |
// Reduce to 10 seconds, allowing more tests to get run. |
tick_delay /= 2; |
#endif |
|
cyg_alarm_initialize(*deathHp, cyg_current_time() + tick_delay, 0); |
} |
} |
#endif |
|
/* death_alarm_func() is the alarm handler that kills the current |
thread after a specified timeout. It does so by setting a flag the |
thread is constantly checking. */ |
void death_alarm_func(cyg_handle_t alarmH, cyg_addrword_t data) |
{ |
int *killed_p; |
killed_p = (int *) data; |
*killed_p = 1; |
} |
|
/* now I write the sc_ versions of the cyg_functions */ |
cyg_addrword_t sc_thread_create( |
cyg_addrword_t sched_info, /* scheduling info (eg pri) */ |
cyg_thread_entry_t *entry, /* entry point function */ |
cyg_addrword_t entry_data, /* entry data */ |
char *name, /* optional thread name */ |
void *stack_base, /* stack base, NULL = alloc */ |
cyg_ucount32 stack_size, /* stack size, 0 = default */ |
cyg_handle_t *handle, /* returned thread handle */ |
cyg_thread *thread /* put thread here */ |
) |
{ |
++statistics.thread_creations; |
|
cyg_thread_create(sched_info, entry, entry_data, name, |
stack_base, stack_size, handle, thread); |
|
return cyg_thread_get_priority(*handle); |
} |
|
|
#define MINS_HOUR (60) |
#define MINS_DAY (60*24) |
|
void print_statistics(int print_full) |
{ |
int i; |
static int stat_dumps = 0; |
static int print_count = 0; |
static int shift_count = 0; |
int minutes; |
|
stat_dumps++; |
|
// Find number of minutes. |
minutes = time_report_delay*stat_dumps / 60; |
|
if (!print_full) { |
// Return if time/minutes not integer. |
if ((time_report_delay*stat_dumps % 60) != 0) |
return; |
|
// After the first day, only dump stat once per day. Do print |
// a . on the hour though. |
if ((minutes > MINS_DAY) && ((minutes % MINS_DAY) != 0)) { |
if ((minutes % MINS_HOUR) == 0) { |
printf("."); |
fflush(stdout); |
} |
return; |
} |
|
// After the first hour of the first day, only dump stat once |
// per hour. Do print . each minute though. |
if ((minutes < MINS_DAY) && (minutes > MINS_HOUR) |
&& ((minutes % MINS_HOUR) != 0)) { |
printf("."); |
fflush(stdout); |
return; |
} |
} |
|
printf("\nState dump %d (%d hours, %d minutes) [numbers >>%d]\n", |
++print_count, minutes / MINS_HOUR, minutes % MINS_HOUR, |
shift_count); |
|
cyg_mutex_lock(&statistics_print_lock); { |
//-------------------------------- |
// Information private to this test: |
printf(" Handler-invocations: "); |
for (i = 0; i < MAX_HANDLERS; ++i) { |
printf("%4lu ", statistics.handler_invocation_histogram[i]); |
} |
printf("\n"); |
printf(" malloc()-tries/failures: -- %7lu %7lu\n", |
statistics.malloc_tries, statistics.malloc_failures); |
printf(" client_makes_request: %d\n", client_makes_request); |
|
// Check for big numbers and reduce if getting close to overflow |
if (statistics.malloc_tries > 0x40000000) { |
shift_count++; |
for (i = 0; i < MAX_HANDLERS; ++i) { |
statistics.handler_invocation_histogram[i] >>= 1; |
} |
statistics.malloc_tries >>= 1; |
statistics.malloc_failures >>= 1; |
} |
} cyg_mutex_unlock(&statistics_print_lock); |
|
#if CYGINT_ISO_MALLINFO |
//-------------------------------- |
// System information |
{ |
struct mallinfo mem_info; |
|
mem_info = mallinfo(); |
|
printf(" Memory system: Total=0x%08x Free=0x%08x Max=0x%08x\n", |
mem_info.arena, mem_info.fordblks, mem_info.maxfree); |
} |
#endif |
|
// Dump stack status |
printf(" Stack usage:\n"); |
cyg_test_dump_interrupt_stack_stats( " Interrupt" ); |
cyg_test_dump_idlethread_stack_stats( " Idle" ); |
|
cyg_test_dump_stack_stats(" Main", main_stack, |
main_stack + sizeof(main_stack)); |
for (i = 0; i < MAX_HANDLERS; i++) { |
cyg_test_dump_stack_stats(" Handler", handler_stack[i], |
handler_stack[i] + sizeof(handler_stack[i])); |
} |
for (i = 0; i < N_LISTENERS; i++) { |
cyg_test_dump_stack_stats(" Listener", listener_stack[i], |
listener_stack[i] + sizeof(listener_stack[i])); |
} |
for (i = 0; i < N_CLIENTS; i++) { |
cyg_test_dump_stack_stats(" Client", client_stack[i], |
client_stack[i] + sizeof(client_stack[i])); |
} |
} |
|
#else /* (CYGNUM_KERNEL_SCHED_PRIORITIES >= */ |
/* (N_MAIN+N_CLIENTS+N_LISTENERS+MAX_HANDLERS)) */ |
#define N_A_MSG "not enough priorities available" |
#endif /* (CYGNUM_KERNEL_SCHED_PRIORITIES >= */ |
/* (N_MAIN+N_CLIENTS+N_LISTENERS+MAX_HANDLERS)) */ |
|
#else /* CYGINT_ISO_MALLOC */ |
# define N_A_MSG "this test needs malloc" |
#endif /* CYGINT_ISO_MALLOC */ |
|
#else /* CYGFUN_KERNEL_THREADS_TIMER */ |
# define N_A_MSG "this test needs kernel threads timer" |
#endif /* CYGFUN_KERNEL_THREADS_TIMER */ |
|
#else /* CYGPKG_LIBM */ |
# define N_A_MSG "this test needs libm" |
#endif /* CYGPKG_LIBM */ |
|
#else /* CYGINT_ISO_STDIO_FORMATTED_IO */ |
# define N_A_MSG "this test needs stdio formatted I/O" |
#endif /* CYGINT_ISO_STDIO_FORMATTED_IO */ |
|
#else // def CYGFUN_KERNEL_API_C |
# define N_A_MSG "this test needs Kernel C API" |
#endif |
|
#else // def CYGPKG_KERNEL && CYGPKG_IO && CYGPKG_ISOINFRA |
# define N_A_MSG "this tests needs Kernel, isoinfra and IO" |
#endif |
|
#ifdef N_A_MSG |
externC void |
cyg_start( void ) |
{ |
CYG_TEST_INIT(); |
CYG_TEST_NA( N_A_MSG); |
} |
#endif // N_A_MSG |