static void test_isr_locks( void ) { ISR_Level normal_interrupt_level = _ISR_Get_level(); ISR_lock_Control initialized = ISR_LOCK_INITIALIZER; ISR_lock_Control lock; ISR_lock_Context lock_context; _ISR_lock_Initialize( &lock ); rtems_test_assert( memcmp( &lock, &initialized, sizeof( lock ) ) == 0 ); _ISR_lock_ISR_disable_and_acquire( &lock, &lock_context ); rtems_test_assert( normal_interrupt_level != _ISR_Get_level() ); _ISR_lock_Release_and_ISR_enable( &lock, &lock_context ); rtems_test_assert( normal_interrupt_level == _ISR_Get_level() ); _ISR_lock_Acquire( &lock, &lock_context ); rtems_test_assert( normal_interrupt_level == _ISR_Get_level() ); _ISR_lock_Release( &lock, &lock_context ); rtems_test_assert( normal_interrupt_level == _ISR_Get_level() ); _ISR_lock_Destroy( &lock ); _ISR_lock_Destroy( &initialized ); }
static void isr_level_check_task( rtems_task_argument arg ) { test_isr_level_context *ctx = (test_isr_level_context *) arg; rtems_status_code sc; ctx->actual_level = _ISR_Get_level(); sc = rtems_event_send( ctx->master_task_id, TEST_ISR_EVENT ); rtems_test_assert( sc == RTEMS_SUCCESSFUL ); ( void ) rtems_task_suspend( RTEMS_SELF ); rtems_test_assert( 0 ); }
void _Assert_Thread_dispatching_repressed( void ) { bool dispatch_is_disabled; ISR_Level level; Per_CPU_Control *per_cpu; _ISR_Disable( level ); per_cpu = _Per_CPU_Get_by_index( _SMP_Get_current_processor() ); dispatch_is_disabled = per_cpu->thread_dispatch_disable_level != 0; _ISR_Enable( level ); _Assert( dispatch_is_disabled || _ISR_Get_level() != 0 ); }
void _Giant_Drop( Per_CPU_Control *self_cpu ) { Giant_Control *giant = &_Giant; uint32_t self_cpu_index = _Per_CPU_Get_index( self_cpu ); _Assert( _ISR_Get_level() != 0 ); if ( giant->owner_cpu == self_cpu_index ) { giant->nest_level = 0; giant->owner_cpu = NO_OWNER_CPU; _SMP_lock_Release( &giant->lock, &self_cpu->Giant_lock_context ); } }
static void test_isr_level( void ) { ISR_Level mask = CPU_MODES_INTERRUPT_MASK; ISR_Level normal = _ISR_Get_level(); ISR_Level current = 0; ISR_Level last_proper_level; _ISR_Set_level( current ); rtems_test_assert( _ISR_Get_level() == current ); for ( current = current + 1 ; current <= mask ; ++current ) { ISR_Level actual; _ISR_Set_level( current ); actual = _ISR_Get_level(); rtems_test_assert( actual == current || actual == ( current - 1 ) ); if ( _ISR_Get_level() != current ) { break; } } last_proper_level = current - 1; for ( current = current + 1 ; current <= mask ; ++current ) { _ISR_Set_level( current ); rtems_test_assert( _ISR_Get_level() == current ); } _ISR_Set_level( normal ); /* * Now test that the ISR level specified for _Thread_Initialize() propagates * properly to the thread. */ test_isr_level_for_new_threads( last_proper_level ); }
rtems_status_code rtems_task_mode( rtems_mode mode_set, rtems_mode mask, rtems_mode *previous_mode_set ) { Thread_Control *executing; RTEMS_API_Control *api; ASR_Information *asr; bool is_asr_enabled = false; bool needs_asr_dispatching = false; rtems_mode old_mode; if ( !previous_mode_set ) return RTEMS_INVALID_ADDRESS; executing = _Thread_Executing; api = executing->API_Extensions[ THREAD_API_RTEMS ]; asr = &api->Signal; old_mode = (executing->is_preemptible) ? RTEMS_PREEMPT : RTEMS_NO_PREEMPT; if ( executing->budget_algorithm == THREAD_CPU_BUDGET_ALGORITHM_NONE ) old_mode |= RTEMS_NO_TIMESLICE; else old_mode |= RTEMS_TIMESLICE; old_mode |= (asr->is_enabled) ? RTEMS_ASR : RTEMS_NO_ASR; old_mode |= _ISR_Get_level(); *previous_mode_set = old_mode; /* * These are generic thread scheduling characteristics. */ if ( mask & RTEMS_PREEMPT_MASK ) executing->is_preemptible = _Modes_Is_preempt(mode_set) ? true : false; if ( mask & RTEMS_TIMESLICE_MASK ) { if ( _Modes_Is_timeslice(mode_set) ) { executing->budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE; executing->cpu_time_budget = _Thread_Ticks_per_timeslice; } else executing->budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_NONE; } /* * Set the new interrupt level */ if ( mask & RTEMS_INTERRUPT_MASK ) _Modes_Set_interrupt_level( mode_set ); /* * This is specific to the RTEMS API */ is_asr_enabled = false; needs_asr_dispatching = false; if ( mask & RTEMS_ASR_MASK ) { is_asr_enabled = _Modes_Is_asr_disabled( mode_set ) ? false : true; if ( is_asr_enabled != asr->is_enabled ) { asr->is_enabled = is_asr_enabled; _ASR_Swap_signals( asr ); if ( _ASR_Are_signals_pending( asr ) ) { needs_asr_dispatching = true; executing->do_post_task_switch_extension = true; } } } if ( _System_state_Is_up( _System_state_Get() ) ) if ( _Thread_Evaluate_mode() || needs_asr_dispatching ) _Thread_Dispatch(); return RTEMS_SUCCESSFUL; }
void _Thread_Handler( void ) { Thread_Control *executing = _Thread_Executing; ISR_Level level; /* * Some CPUs need to tinker with the call frame or registers when the * thread actually begins to execute for the first time. This is a * hook point where the port gets a shot at doing whatever it requires. */ _Context_Initialization_at_thread_begin(); #if !defined(RTEMS_SMP) /* * have to put level into a register for those cpu's that use * inline asm here */ level = executing->Start.isr_level; _ISR_Set_level( level ); #endif /* * Initialize the floating point context because we do not come * through _Thread_Dispatch on our first invocation. So the normal * code path for performing the FP context switch is not hit. */ #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) #if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE ) if ( (executing->fp_context != NULL) && !_Thread_Is_allocated_fp( executing ) ) { if ( _Thread_Allocated_fp != NULL ) _Context_Save_fp( &_Thread_Allocated_fp->fp_context ); _Thread_Allocated_fp = executing; } #endif #endif /* * Take care that 'begin' extensions get to complete before * 'switch' extensions can run. This means must keep dispatch * disabled until all 'begin' extensions complete. */ _User_extensions_Thread_begin( executing ); /* * At this point, the dispatch disable level BETTER be 1. */ #if defined(RTEMS_SMP) { /* * On SMP we enter _Thread_Handler() with interrupts disabled and * _Thread_Dispatch() obtained the per-CPU lock for us. We have to * release it here and set the desired interrupt level of the thread. */ Per_CPU_Control *cpu_self = _Per_CPU_Get(); _Assert( cpu_self->thread_dispatch_disable_level == 1 ); _Assert( _ISR_Get_level() != 0 ); _Thread_Debug_set_real_processor( executing, cpu_self ); cpu_self->thread_dispatch_disable_level = 0; _Profiling_Thread_dispatch_enable( cpu_self, 0 ); level = executing->Start.isr_level; _ISR_Set_level( level); /* * The thread dispatch level changed from one to zero. Make sure we lose * no thread dispatch necessary update. */ _Thread_Dispatch(); } #else _Thread_Enable_dispatch(); #endif /* * RTEMS supports multiple APIs and each API can define a different * thread/task prototype. The following code supports invoking the * user thread entry point using the prototype expected. */ if ( executing->Start.prototype == THREAD_START_NUMERIC ) { executing->Wait.return_argument = (*(Thread_Entry_numeric) executing->Start.entry_point)( executing->Start.numeric_argument ); } #if defined(RTEMS_POSIX_API) else if ( executing->Start.prototype == THREAD_START_POINTER ) { executing->Wait.return_argument = (*(Thread_Entry_pointer) executing->Start.entry_point)( executing->Start.pointer_argument ); } #endif #if defined(FUNCTIONALITY_NOT_CURRENTLY_USED_BY_ANY_API) else if ( executing->Start.prototype == THREAD_START_BOTH_POINTER_FIRST ) { executing->Wait.return_argument = (*(Thread_Entry_both_pointer_first) executing->Start.entry_point)( executing->Start.pointer_argument, executing->Start.numeric_argument ); } else if ( executing->Start.prototype == THREAD_START_BOTH_NUMERIC_FIRST ) { executing->Wait.return_argument = (*(Thread_Entry_both_numeric_first) executing->Start.entry_point)( executing->Start.numeric_argument, executing->Start.pointer_argument ); } #endif /* * In the switch above, the return code from the user thread body * was placed in return_argument. This assumed that if it returned * anything (which is not supporting in all APIs), then it would be * able to fit in a (void *). */ _User_extensions_Thread_exitted( executing ); _Terminate( INTERNAL_ERROR_CORE, true, INTERNAL_ERROR_THREAD_EXITTED ); }
void _Assert_Thread_dispatching_repressed( void ) { _Assert( !_Thread_Dispatch_is_enabled() || _ISR_Get_level() != 0 ); }
void _Thread_Handler( void ) { Thread_Control *executing = _Thread_Executing; ISR_Level level; Per_CPU_Control *cpu_self; /* * Some CPUs need to tinker with the call frame or registers when the * thread actually begins to execute for the first time. This is a * hook point where the port gets a shot at doing whatever it requires. */ _Context_Initialization_at_thread_begin(); /* On SMP we enter _Thread_Handler() with interrupts disabled */ _SMP_Assert( _ISR_Get_level() != 0 ); /* * have to put level into a register for those cpu's that use * inline asm here */ level = executing->Start.isr_level; _ISR_Set_level( level ); /* * Initialize the floating point context because we do not come * through _Thread_Dispatch on our first invocation. So the normal * code path for performing the FP context switch is not hit. */ _Thread_Restore_fp( executing ); /* * Do not use the level of the thread control block, since it has a * different format. */ _ISR_Local_disable( level ); /* * At this point, the dispatch disable level BETTER be 1. */ cpu_self = _Per_CPU_Get(); _Assert( cpu_self->thread_dispatch_disable_level == 1 ); /* * Make sure we lose no thread dispatch necessary update and execute the * post-switch actions. As a side-effect change the thread dispatch level * from one to zero. Do not use _Thread_Enable_dispatch() since there is no * valid thread dispatch necessary indicator in this context. */ _Thread_Do_dispatch( cpu_self, level ); /* * Invoke the thread begin extensions in the context of the thread entry * function with thread dispatching enabled. This enables use of dynamic * memory allocation, creation of POSIX keys and use of C++ thread local * storage. Blocking synchronization primitives are allowed also. */ _User_extensions_Thread_begin( executing ); /* * RTEMS supports multiple APIs and each API can define a different * thread/task prototype. The following code supports invoking the * user thread entry point using the prototype expected. */ ( *executing->Start.Entry.adaptor )( executing ); /* * In the call above, the return code from the user thread body which return * something was placed in return_argument. This assumed that if it * returned anything (which is not supporting in all APIs), then it would be * able to fit in a (void *). */ _User_extensions_Thread_exitted( executing ); _Terminate( INTERNAL_ERROR_CORE, true, INTERNAL_ERROR_THREAD_EXITTED ); }
int main( int argc, char **argv ) #endif { pthread_spinlock_t spinlock; pthread_spinlock_t spinlock2; int status; TEST_BEGIN(); puts( "pthread_spin_init( &spinlock, PTHREAD_PROCESS_PRIVATE ) -- OK" ); status = pthread_spin_init( &spinlock, PTHREAD_PROCESS_PRIVATE ); rtems_test_assert( status == 0 ); puts( "pthread_spin_destroy( &spinlock ) -- OK" ); status = pthread_spin_destroy( &spinlock ); rtems_test_assert( status == 0 ); puts( "pthread_spin_init( &spinlock, PTHREAD_PROCESS_SHARED ) -- OK" ); status = pthread_spin_init( &spinlock, PTHREAD_PROCESS_PRIVATE ); rtems_test_assert( status == 0 ); puts( "pthread_spin_destroy( &spinlock ) -- OK" ); status = pthread_spin_destroy( &spinlock ); rtems_test_assert( status == 0 ); puts( "pthread_spin_init( &spinlock, 0x1234 ) -- OK" ); status = pthread_spin_init( &spinlock, 0x1234 ); rtems_test_assert( status == 0 ); puts( "pthread_spin_init( &spinlock2, 0 ) -- OK" ); status = pthread_spin_init( &spinlock2, 0 ); rtems_test_assert( status == 0 ); rtems_test_assert( _ISR_Get_level() == 0 ); puts( "pthread_spin_lock( &spinlock ) -- OK" ); status = pthread_spin_lock( &spinlock ); rtems_test_assert( status == 0 ); rtems_test_assert( _ISR_Get_level() != 0 ); puts( "pthread_spin_lock( &spinlock2 ) -- OK" ); status = pthread_spin_lock( &spinlock2 ); rtems_test_assert( status == 0 ); rtems_test_assert( _ISR_Get_level() != 0 ); puts( "pthread_spin_unlock( &spinlock2 ) -- OK" ); status = pthread_spin_unlock( &spinlock2 ); rtems_test_assert( status == 0 ); rtems_test_assert( _ISR_Get_level() != 0 ); puts( "pthread_spin_unlock( &spinlock ) -- OK" ); status = pthread_spin_unlock( &spinlock ); rtems_test_assert( status == 0 ); rtems_test_assert( _ISR_Get_level() == 0 ); puts( "pthread_spin_trylock( &spinlock ) -- OK" ); status = pthread_spin_trylock( &spinlock ); rtems_test_assert( status == 0 ); rtems_test_assert( _ISR_Get_level() != 0 ); puts( "pthread_spin_trylock( &spinlock2 ) -- OK" ); status = pthread_spin_trylock( &spinlock2 ); rtems_test_assert( status == 0 ); rtems_test_assert( _ISR_Get_level() != 0 ); puts( "pthread_spin_unlock( &spinlock2 ) -- OK" ); status = pthread_spin_unlock( &spinlock2 ); rtems_test_assert( status == 0 ); rtems_test_assert( _ISR_Get_level() != 0 ); puts( "pthread_spin_unlock( &spinlock ) -- OK" ); status = pthread_spin_unlock( &spinlock ); rtems_test_assert( status == 0 ); rtems_test_assert( _ISR_Get_level() == 0 ); puts( "pthread_spin_destroy( &spinlock2 ) -- OK" ); status = pthread_spin_destroy( &spinlock2 ); rtems_test_assert( status == 0 ); puts( "pthread_spin_destroy( &spinlock ) -- OK" ); status = pthread_spin_destroy( &spinlock ); rtems_test_assert( status == 0 ); TEST_END(); exit(0); }
rtems_status_code rtems_task_mode( rtems_mode mode_set, rtems_mode mask, rtems_mode *previous_mode_set ) { Thread_Control *executing; RTEMS_API_Control *api; ASR_Information *asr; bool needs_asr_dispatching; rtems_mode old_mode; if ( !previous_mode_set ) return RTEMS_INVALID_ADDRESS; executing = _Thread_Get_executing(); api = executing->API_Extensions[ THREAD_API_RTEMS ]; asr = &api->Signal; old_mode = (executing->is_preemptible) ? RTEMS_PREEMPT : RTEMS_NO_PREEMPT; if ( executing->budget_algorithm == THREAD_CPU_BUDGET_ALGORITHM_NONE ) old_mode |= RTEMS_NO_TIMESLICE; else old_mode |= RTEMS_TIMESLICE; old_mode |= (asr->is_enabled) ? RTEMS_ASR : RTEMS_NO_ASR; old_mode |= _ISR_Get_level(); *previous_mode_set = old_mode; /* * These are generic thread scheduling characteristics. */ if ( mask & RTEMS_PREEMPT_MASK ) { #if defined( RTEMS_SMP ) if ( rtems_configuration_is_smp_enabled() && !_Modes_Is_preempt( mode_set ) ) { return RTEMS_NOT_IMPLEMENTED; } #endif executing->is_preemptible = _Modes_Is_preempt( mode_set ); } if ( mask & RTEMS_TIMESLICE_MASK ) { if ( _Modes_Is_timeslice(mode_set) ) { executing->budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE; executing->cpu_time_budget = _Thread_Ticks_per_timeslice; } else executing->budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_NONE; } /* * Set the new interrupt level */ if ( mask & RTEMS_INTERRUPT_MASK ) _Modes_Set_interrupt_level( mode_set ); /* * This is specific to the RTEMS API */ needs_asr_dispatching = false; if ( mask & RTEMS_ASR_MASK ) { bool is_asr_enabled = !_Modes_Is_asr_disabled( mode_set ); if ( is_asr_enabled != asr->is_enabled ) { asr->is_enabled = is_asr_enabled; _ASR_Swap_signals( asr ); if ( _ASR_Are_signals_pending( asr ) ) { needs_asr_dispatching = true; } } } _RTEMS_Tasks_Dispatch_if_necessary( executing, needs_asr_dispatching ); return RTEMS_SUCCESSFUL; }
void rtems_initialize_data_structures(void) { _System_state_Handler_initialization( FALSE ); _CPU_Initialize(); /* * Do this as early as possible to ensure no debugging output * is even attempted to be printed. */ _Debug_Manager_initialization(); _API_extensions_Initialization(); _Thread_Dispatch_initialization(); _User_extensions_Handler_initialization(); _ISR_Handler_initialization(); /* * Initialize the internal support API and allocator Mutex */ _Objects_Information_table[OBJECTS_INTERNAL_API] = _Internal_Objects; _API_Mutex_Initialization( 2 ); _API_Mutex_Allocate( &_RTEMS_Allocator_Mutex ); _API_Mutex_Allocate( &_Once_Mutex ); _Watchdog_Handler_initialization(); _TOD_Handler_initialization(); _Thread_Handler_initialization(); _Scheduler_Handler_initialization(); _SMP_Handler_initialize(); _CPU_set_Handler_initialization(); /* MANAGERS */ /* * Install our API Object Management Table and initialize the * various managers. */ _Objects_Information_table[OBJECTS_CLASSIC_API] = _RTEMS_Objects; _RTEMS_tasks_Manager_initialization(); _Semaphore_Manager_initialization(); /* * Install our API Object Management Table and initialize the * various managers. */ _Objects_Information_table[OBJECTS_POSIX_API] = _POSIX_Objects; _POSIX_Key_Manager_initialization(); /* * Discover and initialize the secondary cores in an SMP system. */ _SMP_Handler_initialize(); _System_state_Set( SYSTEM_STATE_BEFORE_MULTITASKING ); /* * No threads should be created before this point!!! * _Thread_Executing and _Thread_Heir are not set. * * At this point all API extensions are in place. After the call to * _Thread_Create_idle() _Thread_Executing and _Thread_Heir will be set. */ _Thread_Create_idle(); /* * Scheduling can properly occur now as long as we avoid dispatching. */ _System_state_Set( SYSTEM_STATE_UP ); _SMP_Request_start_multitasking(); _Thread_Start_multitasking(); /* Add Initialization of the Thread_Dispatch wrapper */ Init__wrap__Thread_Dispatch(); /* * Now we are back in a non-dispatching critical section */ #if defined(RTEMS_SMP) { ISR_Level level; /* * On SMP we enter _Thread_Handler() with interrupts disabled and * _Thread_Dispatch() obtained the per-CPU lock for us. We have to * release it here and set the desired interrupt level of the thread. */ Per_CPU_Control *cpu_self = _Per_CPU_Get(); _Assert( cpu_self->thread_dispatch_disable_level == 1 ); _Assert( _ISR_Get_level() != 0 ); cpu_self->thread_dispatch_disable_level = 0; _Profiling_Thread_dispatch_enable( cpu_self, 0 ); /* For whatever reason, we haven't locked our per cpu yet in the * Scheduler Simulator. Until this is done, this release is not needed. */ /* _Per_CPU_Release( cpu_self ); */ level = _Thread_Executing->Start.isr_level; _ISR_Set_level( level); /* * The thread dispatch level changed from one to zero. Make sure we lose * no thread dispatch necessary update. */ _Thread_Dispatch(); } #else _Thread_Enable_dispatch(); #endif /* * Print an initial message */ check_heir_and_executing(); }