/* * Simple test program to demonstrate priority inversion when blocking * -Ulf Ivraeus ------------- --- -- - - - * Saab Ericsson Space AB * phone: +46 (0)31 735 4542 * e-mail: ulf.ivraeus@space.se * ----------------------------- --- -- - - - * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rtems.org/license/LICENSE. */ /******************************************************************** Semaphore Ids: Sync Mutex Id = 0x18010009 Local Mutex Id = 0x1801000a Remote Mutex Id = 0x1801000b Task Ids: TaMedium[0] Id = 0x08010002 TaMedium[1] Id = 0x08010003 TaMedium[2] Id = 0x08010004 TaHigh Id = 0x08010005 TaLow Id = 0x08010006 TaHwSim Id = 0x08010007 ********************************************************************/ /********************************************************************/ /* define this to use the RTEMS 4.5 scheme for object names */ /* #define TEST_ON_RTEMS_45 */ /* define this to print the Id of the calling task */ /* #define TEST_ON_TASK_ID */ /* define this if you are (1) on a ERC32 and (2) want a SW ISR trigger */ #if defined(__sparc__) /* #define TEST_USE_ISR */ #endif /* define this if you want the test to exit */ #define TEST_EXIT_AFTER_ITERATIONS 10 /********************************************************************/ #define CONFIGURE_INIT #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "tmacros.h" #include const char rtems_test_name[] = "SP 35"; #if defined(TEST_EXIT_AFTER_ITERATIONS) volatile uint32_t Iterations = 0; #endif const char *CallerName(void); /* Task entry point prototypes */ rtems_task Init(rtems_task_argument ignored); rtems_task Medium_Exec(rtems_task_argument TaskArg); rtems_task Low_Exec(rtems_task_argument TaskArg); rtems_task High_Exec(rtems_task_argument TaskArg); rtems_task LocalHwSim_Exec(rtems_task_argument TaskArg); /* ISR that signals that HW has completed */ rtems_isr LocalHwIsr(/*in*/ rtems_vector_number Vector); /* Test driver functions */ void AccessLocalHw(void); void AccessRemoteHw(void); const char *CallerName(void) { static char buffer[32]; Thread_Control *executing = _Thread_Get_executing(); #if defined(TEST_PRINT_TASK_ID) sprintf( buffer, "0x%08x -- %d", rtems_task_self(), _Thread_Get_priority( executing ) ); #else volatile union { uint32_t u; unsigned char c[4]; } TempName; #if defined(TEST_ON_RTEMS_45) TempName.u = *(uint32_t *)executing->Object.name; #else TempName.u = (uint32_t) executing->Object.name.name_u32; #endif sprintf( buffer, "%c%c%c%c -- %" PRIdPriority_Control, TempName.c[0], TempName.c[1], TempName.c[2], TempName.c[3], _Thread_Get_priority( executing ) ); #endif return buffer; } #define NofMediumTask_C 3 /* RTEMS identifiers */ rtems_id TaMedium[NofMediumTask_C]; /* Medium-prio tasks accessing */ /* the common local HW */ rtems_id TaHwSim; /* HW simulator */ rtems_id TaLow; /* Low-prio task accessing common */ /* remote HW */ rtems_id TaHigh; /* High-prio task accessing common */ /* remote HW */ rtems_id LocalHwSync_S; /* Syncrhonize task to local HW */ rtems_id LocalHwAccess_R; /* Execlusive access to the local HW */ rtems_id RemoteHwAccess_R; /* Execlusive access to the remote HW */ /* The following variable triggers simulated HW activity */ volatile bool StartHw = false; rtems_task Medium_Exec(rtems_task_argument TaskArg) { printf("Medium_Exec (%" PRIdrtems_task_argument ") begins...\n", TaskArg); rtems_task_wake_after(50); while(1) { AccessLocalHw(); } /* JRS - task does not get here */ printf("Medium_Exec (%" PRIdrtems_task_argument ") ends...\n", TaskArg); while(1) { rtems_task_wake_after(10000); } } rtems_task High_Exec(rtems_task_argument TaskArg) { printf("High_Exec (%" PRIdrtems_task_argument ") begins...\n", TaskArg); /* Delay more than the Low-prio task so that Remote HW access resource is * taken before call to AccesRemoteHw. */ rtems_task_wake_after(250); while(1) { AccessRemoteHw(); } /* JRS - task does not get here */ printf("High_Exec (%" PRIdrtems_task_argument ") ends...\n", TaskArg); while(1) { rtems_task_wake_after(10000); } /* task does not get here */ } rtems_task Low_Exec(rtems_task_argument TaskArg) { printf("Low_Exec (%" PRIdrtems_task_argument ") begins...\n", TaskArg); /* Delay less than High-prio task so that we take the remote HW access * resource before it does it. However, delay longer than the mid-prio * tasks so that we know for certain that they have taken control over * the local HW access. */ rtems_task_wake_after(100); while(1) { AccessRemoteHw(); } /* JRS - task does not get here */ printf("Low_Exec (%" PRIdrtems_task_argument ") ends...\n", TaskArg); while(1) { rtems_task_wake_after(10000); } } rtems_task LocalHwSim_Exec(rtems_task_argument TaskArg) { #if 0 int ISRCount = 0; #endif printf("LocalHwSim_Exec begins...\n"); while(1) { if (StartHw) { /* A test task has activated the HW, wait for a while and then * generate an interrupt */ rtems_task_wake_after(100); StartHw = FALSE; #if defined(TEST_USE_ISR) __asm__ volatile ("ta 5"); __asm__ volatile ("nop"); __asm__ volatile ("nop"); #else LocalHwIsr( 0x85 ); #endif } } printf("LocalHwSim_Exec ends...\n"); while(1) { rtems_task_wake_after(10000); } } rtems_isr LocalHwIsr(/*in*/ rtems_vector_number Vector) { rtems_status_code status; /* Signal synchroniztion semaphore to invoke waiting task */ status = rtems_semaphore_release(LocalHwSync_S); if (status != RTEMS_SUCCESSFUL) { printf( "LocalHwISR release %d\n", status ); while(1); /* Error */ } return; } void AccessLocalHw(void) { rtems_status_code Sts; printf(" AccessLocalHw called by %s\n", CallerName()); /* Obtain exclusive access to local HW, Start HW, Wait for completion, * Release access */ Sts = rtems_semaphore_obtain(LocalHwAccess_R, RTEMS_WAIT, RTEMS_NO_TIMEOUT); directive_failed( Sts, "rtems_semaphore_obtain(LocalHwAccess_R...)" ); StartHw = TRUE; Sts = rtems_semaphore_obtain(LocalHwSync_S, RTEMS_WAIT, RTEMS_NO_TIMEOUT); directive_failed( Sts, "rtems_semaphore_obtain(LocalHwAccess_R...)" ); Sts = rtems_semaphore_release(LocalHwAccess_R); directive_failed( Sts, "rtems_semaphore_release(LocalHwAccess_R)" ); printf(" AccessLocalHw returns to %s\n", CallerName()); #if defined(TEST_EXIT_AFTER_ITERATIONS) if ( ++Iterations == 10 ) { TEST_END(); exit(0); } #endif return; } void AccessRemoteHw(void) { rtems_status_code Sts; printf("AccessRemoteHw called by %s\n", CallerName()); /* Obtain exclusive access to remote HW, Start HW, Wait for completion, * Release access */ Sts = rtems_semaphore_obtain(RemoteHwAccess_R, RTEMS_WAIT, RTEMS_NO_TIMEOUT); directive_failed( Sts, "rtems_semaphore_obtain(RemoteHwAccess_R...)" ); /* Carry out the remote access via the Local HW interface */ printf("AccessRemoteHw access local %s\n", CallerName()); AccessLocalHw(); Sts = rtems_semaphore_release(RemoteHwAccess_R); directive_failed( Sts, "rtems_semaphore_release(RemoreHwAccess_R" ); printf("AccessRemoteHw returns to %s\n", CallerName()); return; } /*************************************************************************/ /********************** INITIALIZATION *********************/ /*************************************************************************/ /* The Init operation (the Init-task) */ rtems_task Init(rtems_task_argument ignored) { rtems_status_code status; #if defined(TEST_USE_ISR) rtems_isr_entry DummyIsr; #endif int i; TEST_BEGIN(); /* Create synchronisation semaphore for LocalHwIsr -> Test Tasks */ status = rtems_semaphore_create( rtems_build_name ('S', 'Y', 'N', 'C'), /* name */ 0, /* initial count = 0 */ RTEMS_LOCAL | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_FIFO, 0, &LocalHwSync_S); /* *id */ directive_failed( status, "rtems_semaphore_create (SYNC)" ); printf( "Sync Mutex Id = 0x%08" PRIxrtems_id "\n", LocalHwSync_S ); /* Create resource semaphore for exclusive access to the local HW */ status = rtems_semaphore_create( rtems_build_name ('R', 'E', 'S', '1'), /* name */ 1, /* count */ RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_LOCAL, /* attribute_set */ 1, /* insignificant */ /* priority_ceiling */ &LocalHwAccess_R); /* *id */ directive_failed( status, "rtems_semaphore_create (RES1)" ); printf( "Local Mutex Id = 0x%08" PRIxrtems_id "\n", LocalHwAccess_R ); /* Create resource semaphore for exclusive access to the remote HW */ status = rtems_semaphore_create( rtems_build_name ('R', 'E', 'S', '2'), /* name */ 1, /* count */ RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_LOCAL, /* attribute_set */ 1, /* insignificant */ /* priority_ceiling */ &RemoteHwAccess_R); /* *id */ directive_failed( status, "rtems_semaphore_create (RES2)" ); printf( "Remote Mutex Id = 0x%08" PRIxrtems_id "\n", RemoteHwAccess_R ); #if defined(TEST_USE_ISR) /* Install ISR for HW/SW synchronization, use ta 0x85 which is synchronous */ status = rtems_interrupt_catch(LocalHwIsr, 0x85 + 0x100, &DummyIsr); directive_failed( status, "rtems_interrupt_catch" ); #endif printf("Ending Init-task\n"); /* Create and start all tasks in the test */ /* -- Medium-prio Test Tasks --- */ for (i = 0; i < NofMediumTask_C; i++) { #define MEDIUM_PRIORITY ((RTEMS_MAXIMUM_PRIORITY / 2u) + 1u) status = rtems_task_create( rtems_build_name('M','E','D','0'+i), /* Name */ MEDIUM_PRIORITY, /* Priority */ RTEMS_MINIMUM_STACK_SIZE*2, /* Stack size (8KB) */ RTEMS_DEFAULT_MODES | RTEMS_NO_ASR, /* Mode */ RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT, /* Attributes */ &TaMedium[i]); /* Assigned ID */ directive_failed( status, "rtems_task_create (MEDn)" ); printf( "TaMedium[%d] Id = 0x%08" PRIxrtems_id "\n", i, TaMedium[i] ); status = rtems_task_start( TaMedium[i], Medium_Exec, (rtems_task_argument) i ); directive_failed( status, "rtems_task_start (MEDn)" ); } /* -- High-prio Test Task --- */ #define HIGH_PRIORITY ((RTEMS_MAXIMUM_PRIORITY / 2u)) status = rtems_task_create( rtems_build_name('H','I','G','H'), /* Name */ HIGH_PRIORITY, /* Priority */ RTEMS_MINIMUM_STACK_SIZE*2, /* Stack size (8KB) */ RTEMS_DEFAULT_MODES | RTEMS_NO_ASR, /* Mode */ RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT, /* Attributes */ &TaHigh); /* Assigned ID */ directive_failed( status, "rtems_task_create (HIGH)" ); printf( "TaHigh Id = 0x%08" PRIxrtems_id "\n", TaHigh ); status = rtems_task_start(TaHigh, High_Exec, 0); directive_failed( status, "rtems_task_start (HIGH)" ); /* -- Low-prio Test Task --- */ #define LOW_PRIORITY (RTEMS_MAXIMUM_PRIORITY - 1u) status = rtems_task_create( rtems_build_name('L','O','W',' '), /* Name */ LOW_PRIORITY, /* Priority */ RTEMS_MINIMUM_STACK_SIZE*2, /* Stack size (8KB) */ RTEMS_DEFAULT_MODES | RTEMS_NO_ASR, /* Mode */ RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT, /* Attributes */ &TaLow); /* Assigned ID */ directive_failed( status, "rtems_task_create (LOW)" ); printf( "TaLow Id = 0x%08" PRIxrtems_id "\n", TaLow ); status = rtems_task_start(TaLow, Low_Exec, 0); directive_failed( status, "rtems_task_start (LOW)" ); /* -- HW Simulator Task --- */ #define HWTASK_PRIORITY (RTEMS_MAXIMUM_PRIORITY - 2u) status = rtems_task_create( rtems_build_name('H','W','S','M'), /* Name */ HWTASK_PRIORITY, /* Priority */ RTEMS_MINIMUM_STACK_SIZE*2, /* Stack size (8KB) */ RTEMS_DEFAULT_MODES | RTEMS_NO_ASR, /* Mode */ RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT, /* Attributes */ &TaHwSim); /* Assigned ID */ directive_failed( status, "rtems_task_create (HWSM)" ); printf( "TaHwSim Id = 0x%08" PRIxrtems_id "\n", TaHwSim ); status = rtems_task_start(TaHwSim, LocalHwSim_Exec, 0); directive_failed( status, "rtems_task_start (HWSM)" ); /* Destroy the Init task (and let the ready tasks start running) */ rtems_task_exit(); } /* configuration information */ #define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION #define CONFIGURE_RTEMS_INIT_TASKS_TABLE #define CONFIGURE_EXTRA_TASK_STACKS (RTEMS_MINIMUM_STACK_SIZE * 3) #define CONFIGURE_MAXIMUM_TASKS 10 #define CONFIGURE_MAXIMUM_SEMAPHORES 10 #include /* end of file */