static Per_CPU_Control *_Thread_Wait_for_join( Thread_Control *executing, Per_CPU_Control *cpu_self ) { #if defined(RTEMS_POSIX_API) ISR_lock_Context lock_context; _Thread_State_acquire( executing, &lock_context ); if ( _Thread_Is_joinable( executing ) && _Thread_queue_Is_empty( &executing->Join_queue.Queue ) ) { _Thread_Set_state_locked( executing, STATES_WAITING_FOR_JOIN_AT_EXIT ); _Thread_State_release( executing, &lock_context ); _Thread_Dispatch_enable( cpu_self ); /* Let other threads run */ cpu_self = _Thread_Dispatch_disable(); } else { _Thread_State_release( executing, &lock_context ); } #endif return cpu_self; }
bool _Thread_Start( Thread_Control *the_thread, const Thread_Entry_information *entry, ISR_lock_Context *lock_context ) { Per_CPU_Control *cpu_self; _Thread_State_acquire_critical( the_thread, lock_context ); if ( !_States_Is_dormant( the_thread->current_state ) ) { _Thread_State_release( the_thread, lock_context ); return false; } the_thread->Start.Entry = *entry; _Thread_Load_environment( the_thread ); _Thread_Clear_state_locked( the_thread, STATES_ALL_SET ); cpu_self = _Thread_Dispatch_disable_critical( lock_context ); _Thread_State_release( the_thread, lock_context ); _User_extensions_Thread_start( the_thread ); _Thread_Dispatch_enable( cpu_self ); return true; }
static int _POSIX_Threads_Join( pthread_t thread, void **value_ptr ) { Thread_Control *the_thread; Thread_queue_Context queue_context; Per_CPU_Control *cpu_self; Thread_Control *executing; void *value; _Thread_queue_Context_initialize( &queue_context ); _Thread_queue_Context_set_expected_level( &queue_context, 1 ); the_thread = _Thread_Get( thread, &queue_context.Lock_context ); if ( the_thread == NULL ) { return ESRCH; } cpu_self = _Per_CPU_Get(); executing = _Per_CPU_Get_executing( cpu_self ); if ( executing == the_thread ) { _ISR_lock_ISR_enable( &queue_context.Lock_context ); return EDEADLK; } _Thread_State_acquire_critical( the_thread, &queue_context.Lock_context ); if ( !_Thread_Is_joinable( the_thread ) ) { _Thread_State_release( the_thread, &queue_context.Lock_context ); return EINVAL; } if ( _States_Is_waiting_for_join_at_exit( the_thread->current_state ) ) { value = the_thread->Life.exit_value; _Thread_Clear_state_locked( the_thread, STATES_WAITING_FOR_JOIN_AT_EXIT ); _Thread_Dispatch_disable_with_CPU( cpu_self, &queue_context.Lock_context ); _Thread_State_release( the_thread, &queue_context.Lock_context ); _Thread_Dispatch_enable( cpu_self ); } else { _Thread_Join( the_thread, STATES_INTERRUPTIBLE_BY_SIGNAL | STATES_WAITING_FOR_JOIN, executing, &queue_context ); if ( _POSIX_Get_error_after_wait( executing ) != 0 ) { _Assert( _POSIX_Get_error_after_wait( executing ) == EINTR ); return EINTR; } value = executing->Wait.return_argument; } if ( value_ptr != NULL ) { *value_ptr = value; } return 0; }
static void _Thread_Remove_life_change_request( Thread_Control *the_thread ) { ISR_lock_Context lock_context; uint32_t pending_requests; _Thread_State_acquire( the_thread, &lock_context ); pending_requests = the_thread->Life.pending_life_change_requests; the_thread->Life.pending_life_change_requests = pending_requests - 1; if ( pending_requests == 1 ) { /* * Do not remove states used for thread queues to avoid race conditions on * SMP configurations. We could interrupt an extract operation on another * processor disregarding the thread wait flags. Rely on * _Thread_queue_Extract_with_proxy() for removal of these states. */ _Thread_Clear_state_locked( the_thread, STATES_LIFE_IS_CHANGING | STATES_SUSPENDED | ( STATES_BLOCKED & ~STATES_LOCALLY_BLOCKED ) ); } _Thread_State_release( the_thread, &lock_context ); }
States_Control _Thread_Set_state( Thread_Control *the_thread, States_Control state ) { ISR_lock_Context lock_context; States_Control previous_state; States_Control next_state; _Assert( state != 0 ); _Thread_State_acquire( the_thread, &lock_context ); previous_state = the_thread->current_state; next_state = _States_Set( state, previous_state); the_thread->current_state = next_state; if ( _States_Is_ready( previous_state ) ) { _Scheduler_Block( the_thread ); } _Thread_State_release( the_thread, &lock_context ); return previous_state; }
void _Thread_Exit( Thread_Control *executing, Thread_Life_state set, void *exit_value ) { ISR_lock_Context lock_context; _Assert( _Watchdog_Get_state( &executing->Timer.Watchdog ) == WATCHDOG_INACTIVE ); _Assert( executing->current_state == STATES_READY || executing->current_state == STATES_SUSPENDED ); _Thread_State_acquire( executing, &lock_context ); _Thread_Set_exit_value( executing, exit_value ); _Thread_Change_life_locked( executing, 0, set, THREAD_LIFE_PROTECTED | THREAD_LIFE_CHANGE_DEFERRED ); _Thread_State_release( executing, &lock_context ); }
void _Signal_Action_handler( Thread_Control *executing, Thread_Action *action, ISR_lock_Context *lock_context ) { RTEMS_API_Control *api; ASR_Information *asr; rtems_signal_set signal_set; Modes_Control prev_mode; (void) action; /* * Signal Processing */ api = executing->API_Extensions[ THREAD_API_RTEMS ]; asr = &api->Signal; signal_set = _ASR_Get_posted_signals( asr ); _Thread_State_release( executing, lock_context ); if ( signal_set == 0 ) { return; } asr->nest_level += 1; rtems_task_mode( asr->mode_set, RTEMS_ALL_MODE_MASKS, &prev_mode ); (*asr->handler)( signal_set ); asr->nest_level -= 1; rtems_task_mode( prev_mode, RTEMS_ALL_MODE_MASKS, &prev_mode ); }
void _Thread_Cancel( Thread_Control *the_thread, Thread_Control *executing, void *exit_value ) { ISR_lock_Context lock_context; Thread_Life_state previous; Per_CPU_Control *cpu_self; Priority_Control priority; _Assert( the_thread != executing ); _Thread_State_acquire( the_thread, &lock_context ); _Thread_Set_exit_value( the_thread, exit_value ); previous = _Thread_Change_life_locked( the_thread, 0, THREAD_LIFE_TERMINATING, 0 ); cpu_self = _Thread_Dispatch_disable_critical( &lock_context ); priority = _Thread_Get_priority( executing ); if ( _States_Is_dormant( the_thread->current_state ) ) { _Thread_State_release( the_thread, &lock_context ); _Thread_Make_zombie( the_thread ); } else if ( _Thread_Is_life_change_allowed( previous ) ) { _Thread_Add_life_change_request( the_thread ); _Thread_State_release( the_thread, &lock_context ); _Thread_Finalize_life_change( the_thread, priority ); } else { _Thread_Add_life_change_request( the_thread ); _Thread_Clear_state_locked( the_thread, STATES_SUSPENDED ); _Thread_State_release( the_thread, &lock_context ); _Thread_Raise_real_priority( the_thread, priority ); _Thread_Remove_life_change_request( the_thread ); } _Thread_Dispatch_enable( cpu_self ); }
rtems_status_code rtems_task_set_priority( rtems_id id, rtems_task_priority new_priority, rtems_task_priority *old_priority_p ) { Thread_Control *the_thread; ISR_lock_Context lock_context; const Scheduler_Control *scheduler; Priority_Control old_priority; rtems_status_code status; if ( old_priority_p == NULL ) { return RTEMS_INVALID_ADDRESS; } the_thread = _Thread_Get( id, &lock_context ); if ( the_thread == NULL ) { #if defined(RTEMS_MULTIPROCESSING) return _RTEMS_tasks_MP_Set_priority( id, new_priority, old_priority_p ); #else return RTEMS_INVALID_ID; #endif } if ( new_priority != RTEMS_CURRENT_PRIORITY ) { RTEMS_tasks_Set_priority_context context; Per_CPU_Control *cpu_self; cpu_self = _Thread_Dispatch_disable_critical( &lock_context ); _ISR_lock_ISR_enable( &lock_context ); context.new_priority = new_priority; _Thread_Change_priority( the_thread, 0, &context, _RTEMS_tasks_Set_priority_filter, false ); _Thread_Dispatch_enable( cpu_self ); scheduler = context.scheduler; old_priority = context.old_priority; status = context.status; } else { _Thread_State_acquire_critical( the_thread, &lock_context ); scheduler = _Scheduler_Get_own( the_thread ); old_priority = _Thread_Get_priority( the_thread ); _Thread_State_release( the_thread, &lock_context ); status = RTEMS_SUCCESSFUL; } *old_priority_p = _RTEMS_Priority_From_core( scheduler, old_priority ); return status; }
bool _Thread_Restart_other( Thread_Control *the_thread, const Thread_Entry_information *entry, ISR_lock_Context *lock_context ) { Thread_Life_state previous; Per_CPU_Control *cpu_self; _Thread_State_acquire_critical( the_thread, lock_context ); if ( _States_Is_dormant( the_thread->current_state ) ) { _Thread_State_release( the_thread, lock_context ); return false; } the_thread->Start.Entry = *entry; previous = _Thread_Change_life_locked( the_thread, 0, THREAD_LIFE_RESTARTING, 0 ); cpu_self = _Thread_Dispatch_disable_critical( lock_context ); if ( _Thread_Is_life_change_allowed( previous ) ) { _Thread_Add_life_change_request( the_thread ); _Thread_State_release( the_thread, lock_context ); _Thread_Finalize_life_change( the_thread, the_thread->Start.initial_priority ); } else { _Thread_Clear_state_locked( the_thread, STATES_SUSPENDED ); _Thread_State_release( the_thread, lock_context ); } _Thread_Dispatch_enable( cpu_self ); return true; }
void _Thread_Restart_self( Thread_Control *executing, const Thread_Entry_information *entry, ISR_lock_Context *lock_context ) { Per_CPU_Control *cpu_self; Thread_queue_Context queue_context; _Assert( _Watchdog_Get_state( &executing->Timer.Watchdog ) == WATCHDOG_INACTIVE ); _Assert( executing->current_state == STATES_READY || executing->current_state == STATES_SUSPENDED ); _Thread_queue_Context_initialize( &queue_context ); _Thread_queue_Context_clear_priority_updates( &queue_context ); _Thread_State_acquire_critical( executing, lock_context ); executing->Start.Entry = *entry; _Thread_Change_life_locked( executing, 0, THREAD_LIFE_RESTARTING, THREAD_LIFE_PROTECTED | THREAD_LIFE_CHANGE_DEFERRED ); cpu_self = _Thread_Dispatch_disable_critical( lock_context ); _Thread_State_release( executing, lock_context ); _Thread_Wait_acquire_default( executing, lock_context ); _Thread_Priority_change( executing, &executing->Real_priority, executing->Start.initial_priority, false, &queue_context ); _Thread_Wait_release_default( executing, lock_context ); _Thread_Priority_update( &queue_context ); _Thread_Dispatch_enable( cpu_self ); RTEMS_UNREACHABLE(); }
static void CPU_usage_Per_thread_handler( Thread_Control *the_thread ) { const Scheduler_Control *scheduler; ISR_lock_Context state_lock_context; ISR_lock_Context scheduler_lock_context; _Thread_State_acquire( the_thread, &state_lock_context ); scheduler = _Scheduler_Get( the_thread ); _Scheduler_Acquire_critical( scheduler, &scheduler_lock_context ); _Timestamp_Set_to_zero( &the_thread->cpu_time_used ); _Scheduler_Release_critical( scheduler, &scheduler_lock_context ); _Thread_State_release( the_thread, &state_lock_context ); }
static bool _POSIX_signals_Unblock_thread_done( Thread_Control *the_thread, POSIX_API_Control *api, bool status ) { ISR_lock_Context lock_context; _Thread_State_acquire( the_thread, &lock_context ); _Thread_Add_post_switch_action( the_thread, &api->Signal_action, _POSIX_signals_Action_handler ); _Thread_State_release( the_thread, &lock_context ); return status; }
Thread_Life_state _Thread_Change_life( Thread_Life_state clear, Thread_Life_state set, Thread_Life_state ignore ) { ISR_lock_Context lock_context; Thread_Control *executing; Per_CPU_Control *cpu_self; Thread_Life_state previous; executing = _Thread_State_acquire_for_executing( &lock_context ); previous = _Thread_Change_life_locked( executing, clear, set, ignore ); cpu_self = _Thread_Dispatch_disable_critical( &lock_context ); _Thread_State_release( executing, &lock_context ); _Thread_Dispatch_enable( cpu_self ); return previous; }
void _Thread_Restart_self( Thread_Control *executing, const Thread_Entry_information *entry, ISR_lock_Context *lock_context ) { Per_CPU_Control *cpu_self; Priority_Control unused; _Assert( _Watchdog_Get_state( &executing->Timer.Watchdog ) == WATCHDOG_INACTIVE ); _Assert( executing->current_state == STATES_READY || executing->current_state == STATES_SUSPENDED ); _Thread_State_acquire_critical( executing, lock_context ); executing->Start.Entry = *entry; _Thread_Change_life_locked( executing, 0, THREAD_LIFE_RESTARTING, THREAD_LIFE_PROTECTED | THREAD_LIFE_CHANGE_DEFERRED ); cpu_self = _Thread_Dispatch_disable_critical( lock_context ); _Thread_State_release( executing, lock_context ); _Thread_Set_priority( executing, executing->Start.initial_priority, &unused, true ); _Thread_Dispatch_enable( cpu_self ); RTEMS_UNREACHABLE(); }
rtems_status_code rtems_signal_catch( rtems_asr_entry asr_handler, rtems_mode mode_set ) { Thread_Control *executing; RTEMS_API_Control *api; ASR_Information *asr; ISR_lock_Context lock_context; executing = _Thread_State_acquire_for_executing( &lock_context ); api = executing->API_Extensions[ THREAD_API_RTEMS ]; asr = &api->Signal; if ( !_ASR_Is_null_handler( asr_handler ) ) { asr->mode_set = mode_set; asr->handler = asr_handler; } else { _ASR_Initialize( asr ); } _Thread_State_release( executing, &lock_context ); return RTEMS_SUCCESSFUL; }
void _Thread_Change_priority( Thread_Control *the_thread, Priority_Control new_priority, void *arg, Thread_Change_priority_filter filter, bool prepend_it ) { ISR_lock_Context lock_context; ISR_lock_Control *lock; lock = _Thread_Lock_acquire( the_thread, &lock_context ); /* * For simplicity set the priority restore hint unconditionally since this is * an average case optimization. Otherwise complicated atomic operations * would be necessary. Synchronize with a potential read of the resource * count in the filter function. See also _CORE_mutex_Surrender(), * _Thread_Set_priority_filter() and _Thread_Restore_priority_filter(). */ the_thread->priority_restore_hint = true; _Atomic_Fence( ATOMIC_ORDER_ACQ_REL ); /* * Do not bother recomputing all the priority related information if * we are not REALLY changing priority. */ if ( ( *filter )( the_thread, &new_priority, arg ) ) { uint32_t my_generation; my_generation = the_thread->priority_generation + 1; the_thread->current_priority = new_priority; the_thread->priority_generation = my_generation; ( *the_thread->Wait.operations->priority_change )( the_thread, new_priority, the_thread->Wait.queue ); _Thread_Lock_release( lock, &lock_context ); _Thread_State_acquire( the_thread, &lock_context ); if ( the_thread->priority_generation == my_generation ) { if ( _States_Is_ready( the_thread->current_state ) ) { _Scheduler_Change_priority( the_thread, new_priority, prepend_it ); } else { _Scheduler_Update_priority( the_thread, new_priority ); } } _Thread_State_release( the_thread, &lock_context ); } else { _Thread_Lock_release( lock, &lock_context ); } }
static void _POSIX_signals_Action_handler( Thread_Control *executing, Thread_Action *action, ISR_lock_Context *lock_context ) { POSIX_API_Control *api; int signo; uint32_t hold_errno; (void) action; _Thread_State_release( executing, lock_context ); api = executing->API_Extensions[ THREAD_API_POSIX ]; /* * We need to ensure that if the signal handler executes a call * which overwrites the unblocking status, we restore it. */ hold_errno = executing->Wait.return_code; /* * api may be NULL in case of a thread close in progress */ if ( !api ) return; /* * In case the executing thread is blocked or about to block on something * that uses the thread wait information, then this is a kernel bug. */ _Assert( ( _Thread_Wait_flags_get( executing ) & ( THREAD_WAIT_STATE_BLOCKED | THREAD_WAIT_STATE_INTEND_TO_BLOCK ) ) == 0 ); /* * If we invoke any user code, there is the possibility that * a new signal has been posted that we should process so we * restart the loop if a signal handler was invoked. * * The first thing done is to check there are any signals to be * processed at all. No point in doing this loop otherwise. */ while (1) { Thread_queue_Context queue_context; _Thread_queue_Context_initialize( &queue_context ); _POSIX_signals_Acquire( &queue_context ); if ( !(api->signals_unblocked & (api->signals_pending | _POSIX_signals_Pending)) ) { _POSIX_signals_Release( &queue_context ); break; } _POSIX_signals_Release( &queue_context ); for ( signo = SIGRTMIN ; signo <= SIGRTMAX ; signo++ ) { _POSIX_signals_Check_signal( api, signo, false ); _POSIX_signals_Check_signal( api, signo, true ); } /* Unfortunately - nothing like __SIGFIRSTNOTRT in newlib signal .h */ for ( signo = SIGHUP ; signo <= __SIGLASTNOTRT ; signo++ ) { _POSIX_signals_Check_signal( api, signo, false ); _POSIX_signals_Check_signal( api, signo, true ); } } executing->Wait.return_code = hold_errno; }
int pthread_setschedparam( pthread_t thread, int policy, struct sched_param *param ) { Thread_Control *the_thread; Per_CPU_Control *cpu_self; POSIX_API_Control *api; Thread_CPU_budget_algorithms budget_algorithm; Thread_CPU_budget_algorithm_callout budget_callout; int eno; Priority_Control unused; ISR_lock_Context lock_context; Priority_Control new_priority; /* * Check all the parameters */ if ( param == NULL ) { return EINVAL; } eno = _POSIX_Thread_Translate_sched_param( policy, param, &budget_algorithm, &budget_callout ); if ( eno != 0 ) { return eno; } the_thread = _Thread_Get_interrupt_disable( thread, &lock_context ); if ( the_thread == NULL ) { return ESRCH; } /* * Actually change the scheduling policy and parameters */ cpu_self = _Thread_Dispatch_disable_critical( &lock_context ); _Thread_State_acquire_critical( the_thread, &lock_context ); api = the_thread->API_Extensions[ THREAD_API_POSIX ]; if ( api->schedpolicy == SCHED_SPORADIC ) { _Watchdog_Per_CPU_remove_relative( &api->Sporadic_timer ); } api->schedpolicy = policy; api->schedparam = *param; api->Attributes.schedpolicy = policy; api->Attributes.schedparam = *param; the_thread->budget_algorithm = budget_algorithm; the_thread->budget_callout = budget_callout; switch ( policy ) { case SCHED_OTHER: case SCHED_FIFO: case SCHED_RR: the_thread->cpu_time_budget = rtems_configuration_get_ticks_per_timeslice(); new_priority = _POSIX_Priority_To_core( api->schedparam.sched_priority ); break; case SCHED_SPORADIC: api->ss_high_priority = api->schedparam.sched_priority; break; } _Thread_State_release( the_thread, &lock_context ); switch ( policy ) { case SCHED_OTHER: case SCHED_FIFO: case SCHED_RR: _Thread_Set_priority( the_thread, new_priority, &unused, true ); break; case SCHED_SPORADIC: _POSIX_Threads_Sporadic_budget_TSR( &api->Sporadic_timer ); break; } _Thread_Dispatch_enable( cpu_self ); return 0; }
void _Thread_Life_action_handler( Thread_Control *executing, Thread_Action *action, ISR_lock_Context *lock_context ) { Thread_Life_state previous_life_state; Per_CPU_Control *cpu_self; (void) action; previous_life_state = executing->Life.state; executing->Life.state = previous_life_state | THREAD_LIFE_PROTECTED; _Thread_State_release( executing, lock_context ); if ( _Thread_Is_life_terminating( previous_life_state ) ) { _User_extensions_Thread_terminate( executing ); } else { _Assert( _Thread_Is_life_restarting( previous_life_state ) ); _User_extensions_Thread_restart( executing ); } cpu_self = _Thread_Dispatch_disable(); if ( _Thread_Is_life_terminating( previous_life_state ) ) { cpu_self = _Thread_Wait_for_join( executing, cpu_self ); _Thread_Make_zombie( executing ); /* FIXME: Workaround for https://devel.rtems.org/ticket/2751 */ cpu_self->dispatch_necessary = true; _Assert( cpu_self->heir != executing ); _Thread_Dispatch_enable( cpu_self ); RTEMS_UNREACHABLE(); } _Assert( _Thread_Is_life_restarting( previous_life_state ) ); _Thread_State_acquire( executing, lock_context ); _Thread_Change_life_locked( executing, THREAD_LIFE_PROTECTED | THREAD_LIFE_RESTARTING, 0, 0 ); _Thread_State_release( executing, lock_context ); _Assert( _Watchdog_Get_state( &executing->Timer.Watchdog ) == WATCHDOG_INACTIVE ); _Assert( executing->current_state == STATES_READY || executing->current_state == STATES_SUSPENDED ); _User_extensions_Destroy_iterators( executing ); _Thread_Load_environment( executing ); #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) if ( executing->fp_context != NULL ) { _Context_Restore_fp( &executing->fp_context ); } #endif _Context_Restart_self( &executing->Registers ); RTEMS_UNREACHABLE(); }